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)活动ÿ…...

聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...

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

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...

如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...