python和go相互调用的两种方法
前言
Python 和 Go 语言是两种不同的编程语言,它们分别有自己的优势和适用场景。在一些项目中,由于团队内已有的技术栈或者某一部分业务的需求,可能需要 Python 和 Go 相互调用,以此来提升效率和性能。
-
性能优势
Go 通常比 Python 更高效,尤其是在并发和并行处理方面。因此,可以使用 Go 编写高性能的底层组件或服务,并通过 Python 调用这些组件来提高整体性能。
-
并发和并行处理
Go 是为并发设计的语言,具有轻量级线程(goroutines)和通道(channels)等特性。在需要处理大量并发任务的情况下,Go 的并发性能可能优于 Python。通过将 Go 组件嵌入到 Python 代码中,可以利用 Go 的并发处理能力。
-
易用性和灵活性
Python 具有简洁、易读、易学的语法,适用于快速开发和原型设计。将 Python 用于高层逻辑和算法,而使用 Go 来编写性能敏感的底层组件,可以在性能和开发速度之间找到平衡。
方案简介
1.动态库调用
一、调用步骤:
将go代码编译成so库 -> python中通过ctypes引用so库并指定需要调用的函数(同时可指定传入参数类型和返回值类型) -> 指定后按python使用函数方式调用。
需要注意的是:python和go之间参数传递是需要经过C的数据类型转换的,因此需要了解python中ctypes数据类型和python数据类型以及C的数据类型对应关系
三种数据类型使用场景:
- ctypes数据类型为指定调用函数时的传入参数和返回值的数据类型
- python数据类型为调用函数时传入的参数的数据类型
- C的数据类型为go代码中定义的函数所需的参数和返回值数据类型
二、示例
假设我们就有这么一个函数,需要在 Python 中调用这个函数
func add(a int, b int) int {return a + b
}
第一步:对此函数进行改造
如下:
// main.go
package main
import "C"
func main() {}
//export add
func add(a int, b int) int {return a + b
}
1.import “C” 这个必须要加载 Go 源文件前,这一点必须做,应该就是告诉编译器我要即将编译的软件需要做为 C 的库而不直接是二进制。这个包也提供一些功能让 Go 去直接操作 C 的数据结构等等。
2.main() main 函数一定不能少,即使没有任何一行代码也没事;
3.//export add 在函数定义之前添加上注释来告诉编译器哪些定义可以被 C 引用,注意 // 和 export 之前不能有空格,否则会导出失败的
第二步: 将 Go 编译成 C 可以调用的库
执行命令
go build --buildmode=c-shared -o library.so main.go
编译完后在当前目录下回有一个 library.so 和 library.h 的文件
第三步:python调用
编写python调用函数main.py
import ctypeslib = ctypes.cdll.LoadLibrary("library.so")print(lib.add(1, 2))
由于Python和Go是两种不同的语言,其参数的类型也有所不同。所以在调用时需要进一步转换成C语言类型来进行转换。
import ctypeslib = ctypes.cdll.LoadLibrary("library.so")GoInt64 = ctypes.c_int64
GoInt = GoInt64add = lib.addadd.argtypes = [GoInt64, GoInt64]
add.restype = GoInt64res = add(GoInt(1), GoInt(2))print(res)
使用 ctypes.cdll.LoadLibrary 来加载这个动态库,然后就可以直接调用了。
其对应参数类型如下:
例如:当python传入的参数需是string时,ctypes中指定的传参参数类型需为c_wchar_p,go中需要指定接收的参数数据类型为 *C.wchar_t。
其他类型请参考文档链接https://docs.python.org/3.5/library/ctypes.html
2.grpc调用
grpc已经在之前文章https://blog.csdn.net/qq_45066628/article/details/118602349介绍过了,就不重复赘述了。
调用流程
Python gRPC
-
环境安装
grpcio 是启动 gRPC 服务的项目依赖
pip install grpcio
grpcio 是启动 gRPC 服务的项目依赖
pip install grpcio-tools
-
定义 proto 文件
syntax = "proto3";import "google/protobuf/empty.proto";// service 关键字定义提供的服务 service MyService {// 定义一个探活方法rpc Health (.google.protobuf.Empty) returns (.google.protobuf.Empty){}// 定义一个批量查询 user 的方法rpc User (UserReq) returns (UserReply){}}// message 关键字定义交互的数据结构 message UserReq {repeated int32 userIDs= 1; }message UserReply {string message = 1;// repeated 定义一个数组repeated User data = 2; }message User {string name = 1;int32 age = 2;string email = 3; }
-
编译生成代码
使用 protoc 和相应的插件可以编译生成对应语言的代码
-I 指定 import 路径,可以指定多个 -I 参数,编译时按顺序查找,不指定默认当前目录python -m grpc_tools.protoc -I ./ --python_out=. --grpc_python_out=. ./api.proto
经过上述步骤,我们生成了这样两个文件api_pb2.py 此文件包含每个 message 生成一个含有静态描述符的模块,,该模块与一个元类(metaclass)在运行时(runtime)被用来创建所需的Python数据访问类api_pb2_grpc.py 此文件包含生成的 客户端(MyServiceStub)和服务端 (MyServiceServicer)的类。
-
实现python服务端
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import logging from concurrent import futuresimport grpc from api import api_pb2_grpc, api_pb2 from api.api_pb2_grpc import MyServiceServicer from service import get_usersclass Service(MyServiceServicer):def Health(self, request, context):returndef User(self, request, context):print('start to process request...')res = get_users(request.userIDs)users = []for u in res:users.append(api_pb2.User(name=u['name'], age=u['age'], email=u['email']))return api_pb2.UserReply(message='success', data=users)def serve():print('start grpc server====>')server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))api_pb2_grpc.add_MyServiceServicer_to_server(Service(), server)server.add_insecure_port('[::]:50051')server.start()server.wait_for_termination()if __name__ == '__main__':logging.basicConfig()serve()
Go gRPC
Go 服务作为客户端调用 Python 服务,同样需要根据 proto 文件生成代码,进而创建客户端发起 RPC。
-
环境搭建
安装 ptotobuf, 推荐使用 brewbrew install protobuf
protoc go 插件安装
go get -u github.com/golang/protobuf/protoc-gen-go
这里安装在 GOPATH 下的 bin 目录,所以保证这个目录在 $PATH 中
export PATH=“ P A T H : PATH: PATH:(go env GOPATH)/bin”
代码 gprc 依赖安装
go get -u google.golang.org/grpc
-
生成 Go pb 代码
protoc -I ./ --go_out=plugins=grpc:./ api.proto
-
Go客户端调用
package mainimport ("context""fmt""log""time""ginDemo/api""google.golang.org/grpc" )const (address = "localhost:50051"defaultName = "world" )func main() {conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())if err != nil {log.Fatalf("did not connect: %v", err)}defer conn.Close()c := api.NewMyServiceClient(conn)ctx, cancel := context.WithTimeout(context.Background(), time.Second)defer cancel()r, err := c.User(ctx, &api.UserReq{UserIDs: []int32{1, 2}})if err != nil {log.Fatalf("could not greet: %v", err)}fmt.Printf("gprc result: %+v", r.Data) }
相关文章:

python和go相互调用的两种方法
前言 Python 和 Go 语言是两种不同的编程语言,它们分别有自己的优势和适用场景。在一些项目中,由于团队内已有的技术栈或者某一部分业务的需求,可能需要 Python 和 Go 相互调用,以此来提升效率和性能。 性能优势 Go 通常比 Python 更高效&…...
c# 分部视图笔记
Html.Partial("**", 1) public ActionResult **(int page) { ViewBag.page page; return PartialView("**"); }...

Vue3最佳实践 第七章 TypeScript 中
Vue组件中TypeScript 在Vue组件中,我们可以使用TypeScript进行各种类型的设置,包括props、Reactive和ref等。下面,让我们详细地探讨一下这些设置。 设置描述设置props在Vue中,props本身就具有类型设定的功能。但如果你希望使用Ty…...

(三)行为模式:8、状态模式(State Pattern)(C++示例)
目录 1、状态模式(State Pattern)含义 2、状态模式的UML图学习 3、状态模式的应用场景 4、状态模式的优缺点 (1)优点 (2)缺点 5、C实现状态模式的实例 1、状态模式(State Pattern&#x…...
nginx的配置文件概述及简单demo(二)
默认配置文件 当安装完nginx后,它的目录下通常有默认的配置文件 #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connection…...

Apollo Planning2.0决策规划算法代码详细解析 (2): vscode gdb单步调试环境搭建
前言: apollo planning2.0 在新版本中在降低学习和二次开发成本上进行了一些重要的优化,重要的优化有接口优化、task插件化、配置参数改造等。 GNU symbolic debugger,简称「GDB 调试器」,是 Linux 平台下最常用的一款程序调试器。GDB 编译器通常以 gdb 命令的形式在终端…...

flex 布局:元素/文字靠右
前言 略 使用flex的justify-content属性控制元素的摆放位置 靠右 <view class"more">展开更多<text class"iconfont20231007 icon-zhankai"></text></view>.more {display: flex;flex-direction: row;color: #636363;justify-co…...

java基础-第1章-走进java世界
一、计算机基础知识 常用的DOS命令 二、计算机语言介绍 三、Java语言概述 四、Java环境的搭建 JDK安装图解 环境变量的配置 配置环境变量意义 配置环境变量步骤 五、第一个Java程序 编写Java源程序 编译Java源文件 运行Java程序 六、Java语言运行机制 核心机制—Java虚拟机 核…...
jvm 堆内存 栈内存 大小设置
4种方式配置不同作用域的jvm的堆栈内存。 1、Eclise 中设置jvm内存: 改动eclipse的配置文件,对全部project都起作用 改动eclipse根文件夹下的eclipse.ini文件 -vmargs //虚拟机设置 -Xms40m //初始内存 -Xmx256m //最大内存 -Xmn16m //最小内存 -XX:PermSize=128M //非堆内…...

免杀对抗-反沙盒+反调试
反VT-沙盒检测-Go&Python 介绍: 近年来,各类恶意软件层出不穷,反病毒软件也更新了各种检测方案以提高检率。 其中比较有效的方案是动态沙箱检测技术,即通过在沙箱中运行程序并观察程序行为来判断程序是否为恶意程序。简单来说…...
QTimer类的使用方法
本文介绍QTimer类的使用方法。 1.单次触发 在某些情况下,定时器只运行一次,可使用单次触发方式。 QTimer *timer new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWindow::timeout); timer->setSingleShot(true); timer-…...
(三)行为模式:9、空对象模式(Null Object Pattern)(C++示例)
目录 1、空对象模式(Null Object Pattern)含义 2、空对象模式的主要涉及以下几个角色 3、空对象模式的应用场景 4、空对象模式的优缺点 (1)优点 (2)缺点 5、C实现空对象模式的实例 1、空对象模式&am…...

Django实战项目-学习任务系统-用户登录
第一步:先创建一个Django应用程序框架代码 1,先创建一个Django项目 django-admin startproject mysite将创建一个目录,其布局如下:mysite/manage.pymysite/__init__.pysettings.pyurls.pyasgi.pywsgi.py 2,再创建一个…...

【动手学深度学习-Pytorch版】Transformer代码总结
本文是纯纯的撸代码讲解,没有任何Transformer的基础内容~ 是从0榨干Transformer代码系列,借用的是李沐老师上课时讲解的代码。 本文是根据每个模块的实现过程来进行讲解的。如果您想获取关于Transformer具体的实现细节(不含代码)可…...

做外贸独立站选Shopify还是WordPress?
现在确实会有很多新人想做独立站,毕竟跨境电商平台内卷严重,平台规则限制不断升级,脱离平台“绑架”布局独立站,才能获得更多流量、订单、塑造品牌价值。然而,在选择建立外贸独立站的过程中,选择适合的建站…...

echarts的bug,在series里写tooltip,不起作用,要在全局先写tooltip:{}才起作用,如果在series里写的不起作用就写到全局里
echarts的bug,在series里写tooltip,不起作用,要在全局先写tooltip:{show:true}才起作用,如果在series里写的不起作用就写到全局里 series里写tooltip不起作用,鼠标悬浮在echarts图表上时不显示提示 你需要…...

jmeter分布式压测
一、什么是压力测试? 压力测试(Stress Test),也称为强度测试、负载测试,属于性能测试的范畴。 压力测试是模拟实际应用的软硬件环境及用户使用过程的系统负荷,长时间或超大负荷地运行被测软件系统ÿ…...

consulmanage部署
一、部署consul 使用yum方式部署consul yum install -y yum-utils yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo yum -y install consul 执行以下命令获取uuid密钥并记录下来 uuidgen 编辑consul配置文件 vi /etc/consul.d/consul.h…...

大数据软件项目的验收流程
大数据软件项目的验收流程是确保项目交付符合预期需求和质量标准的关键步骤。以下是一般的大数据软件项目验收流程,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 1.项目验收计划制定: 在…...

《第一行代码Andorid》阅读笔记-第一章
这篇文章是我自己的《第一行代码Andorid》的阅读笔记,虽然大量参考了别人已经写好的一些笔记和代码但是也有自己的提炼和新的问题在里面,我也会放上参考文章链接。 学习重点 Android系统的四大组件: (1)活动ÿ…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...