python和go相互调用的两种方法

news2024/11/18 7:39:31

前言

在这里插入图片描述

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的数据类型对应关系

三种数据类型使用场景:

  1. ctypes数据类型为指定调用函数时的传入参数和返回值的数据类型
  2. python数据类型为调用函数时传入的参数的数据类型
  3. 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 ctypes

lib = ctypes.cdll.LoadLibrary("library.so")

print(lib.add(1, 2))

由于Python和Go是两种不同的语言,其参数的类型也有所不同。所以在调用时需要进一步转换成C语言类型来进行转换。

import ctypes

lib = ctypes.cdll.LoadLibrary("library.so")

GoInt64 = ctypes.c_int64
GoInt = GoInt64

add = lib.add

add.argtypes = [GoInt64, GoInt64]
add.restype = GoInt64

res = 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
  1. 环境安装

    grpcio 是启动 gRPC 服务的项目依赖

    pip install grpcio

    grpcio 是启动 gRPC 服务的项目依赖

    pip install grpcio-tools

  2. 定义 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;
    }
    
    
  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)的类。

  4. 实现python服务端

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    import logging
    from concurrent import futures
    
    import grpc
    from api import api_pb2_grpc, api_pb2
    from api.api_pb2_grpc import MyServiceServicer
    from service import get_users
    
    
    class Service(MyServiceServicer):
        def Health(self, request, context):
            return
    
        def 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。

  1. 环境搭建
    安装 ptotobuf, 推荐使用 brew

    brew 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

  2. 生成 Go pb 代码

    protoc -I ./ --go_out=plugins=grpc:./ api.proto

  3. Go客户端调用

    package main
    
    import (
    	"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)
    }
    
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1065247.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是DOM(Document Object Model)?如何使用JavaScript操作DOM元素?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是DOM?⭐ 如何使用JavaScript操作DOM元素?1. 获取DOM元素2. 修改元素内容3. 修改元素属性4. 添加和移除元素5. 添加和移除事件监听器 ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界…

【开发篇】十七、消息:模拟订单短信通知

文章目录 1、消息2、JMS3、AMQP4、案例:模拟订单短信通知 相关文章: 【同步通讯与异步通讯】 1、消息 消息的发送方,即生产者。消息的接收方,即消费者。同步通信就行打视频,等着对方接电话才能继续往下,而…

JDBC 【SQL注入】

一、SQL注入🍓 (一)、SQL注入问题🥝 1.向jdbc_user表中 插入两条数据 # 插入2条数据 INSERT INTO jdbc_user VALUES(NULL,jack,123456,2020/2/24); INSERT INTO jdbc_user VALUES(NULL,tom,123456,2020/2/24);2.SQL注入演示 # SQL注入演示 -- 填写…

泊车功能专题介绍 ———— AVP系统基础数据交互内容

文章目录 系统架构系统功能描述云端子系统车辆子系统场端子系统用户APP 工作流程基础数据交互内容AVP 系统基础数据交互服务车/用户 - 云基础数据交互内容车位查询工作流程技术要求数据交互要求 车位预约工作流程技术要求数据交互要求 取消预约工作流程技术要求数据交互要求 泊…

利用C++开发一个迷你的英文单词录入和测试小程序-升级版本

我们现在有了一个本地sqlite3的迷你英文单词小测试工具,需求就跟工作当中一样是不断变更的。这里虚构两个场景,并且一步一步的完成最终升级后的小demo。 场景:数据不依赖本地sqlite3,需要支持远程访问,用目前的restfu…

深入探究C++编程中的资源泄漏问题

目录 1、GDI对象泄漏 1.1、何为GDI资源泄漏? 1.2、使用GDIView工具排查GDI对象泄漏 1.3、有时可能需要结合其他方法去排查 1.4、如何保证没有GDI对象泄漏? 2、进程句柄泄漏 2.1、何为进程句柄泄漏? 2.2、创建线程时的线程句柄泄漏 …

Dijkstra 邻接表表示算法 | 贪心算法实现--附C++/JAVA实现源码

以下是详细步骤。 创建大小为 V 的最小堆,其中 V 是给定图中的顶点数。最小堆的每个节点包含顶点编号和顶点的距离值。 以源顶点为根初始化最小堆(分配给源顶点的距离值为0)。分配给所有其他顶点的距离值为 INF(无限)。 当最小堆不为空时,执行以下操作: 从最小堆中提取…

JVM技术文档--JVM诊断调优工具Arthas--阿里巴巴开源工具--一文搞懂Arthas--快速上手--国庆开卷!!

​ Arthas首页 简介 | arthas Arthas官网文档 Arthas首页、文档和下载 - 开源 Java 诊断工具 - OSCHINA - 中文开源技术交流社区 阿丹: 之前聊过了一些关于JMV中的分区等等,但是有同学还是在后台问我,还有私信问我,学了这些…

人工智能驱动的古彝文识别:保护和传承古彝文文化

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

从零开始 Spring Cloud 13:分布式事务

从零开始 Spring Cloud 13:分布式事务 1.分布式事务问题 用一个示例项目演示在分布式系统中使用事务会产生的问题。 示例项目的 SQL:seata_demo.sql 示例项目代码:seata-demo.zip 这个示例项目中的微服务的互相调用依赖于 Nacos&#xf…

低代码平台如何借助Nginx实现网关服务

摘要:本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 前言 在典型的系统部署架构中,应用服务器是一种软件或硬件系统&#xff0c…

解决Ubuntu18.04安装好搜狗输入法后无法打出中文的问题

首先下载安装 搜狗拼音输入法 ,下载选择: x86_64 在ubuntu中设置 fcitx 最后发现安装好了,图标有了 ,但是使用时不能输入中文,使用下面的命令解决: sudo apt install libqt5qml5 libqt5quick5 libqt5qu…

PyTorch深度学习实战(20)——从零开始实现R-CNN目标检测

PyTorch深度学习实战(20)——从零开始实现R-CNN目标检测 0. 前言1. R-CNN 目标检测模型1.1 核心思想1.2 算法流程 2. 实现 R-CNN 目标检测2.1 数据集准备2.2 获取区域提议和偏移量2.3 创建训练数据2.4 构建 R-CNN 架构 3. R-CNN目标检测模型测试小结系列…

【JUC系列-09】深入理解ReentrantReadWriteLock的底层实现

JUC系列整体栏目 内容链接地址【一】深入理解JMM内存模型的底层实现原理https://zhenghuisheng.blog.csdn.net/article/details/132400429【二】深入理解CAS底层原理和基本使用https://blog.csdn.net/zhenghuishengq/article/details/132478786【三】熟练掌握Atomic原子系列基本…

浅谈智能安全配电装置在老年人建筑中的应用

摘要:我国每年因触电伤亡人数非常多,大多数事故是发生在用电设备和配电装置。在电气事故中,无法预料和不可抗拒的事故是比较少的,大量用电事故可采取切实可行措施来预防。本文通过结合老年人建筑的特点和智能安全配电装置的功能&a…

教你三步搞定VsCode调试C++

目录 1 配置编译任务2 配置调试任务3 进行调试 1 配置编译任务 使用VsCode进行C开发时,除了在机器上安装必要的编译工具(例如,gcc、g、cmake等)之外,还需要在VsCode配置编译任务,从而可以通过点击或者快捷…

【MySql】mysql之进阶查询语句

目录 一、常用查询 1、order by按关键字排序❤ 1.1 升序排序 1.2 降序排序 1.3 结合where进项条件过滤再排序 1.4 多字段排序 2、and和or判断 2.1 and和or的使用 2.2 嵌套、多条件使用 3、distinct 查询不重复记录 4、group by 对结果进行分组 5、limit限制结果…

MySQL57部署与配置[Windows10]

下载原始安装包 https://dev.mysql.com/downloads/installer/https://downloads.mysql.com/archives/notifier/默认安装 MySQL57 默认安装 MySQL Notifier 环境变量配置 Path: C:\Program Files\MySQL\MySQL Server 5.7\binDBeaver数据库连接

【MySql】4- 实践篇(二)

文章目录 1. SQL 语句为什么变“慢”了1.1 什么情况会引发数据库的 flush 过程呢?1.2 四种情况性能分析1.3 InnoDB 刷脏页的控制策略 2. 数据库表的空间回收2.1 innodb_file_per_table参数2.2 数据删除流程2.3 重建表2.4 Online 和 inplace 3. count(*) 语句怎样实现…

websocket拦截

python实现websocket拦截 前言一、拦截的优缺点优点缺点二、实现方法1.环境配置2.代码三、总结现在的直播间都是走的websocket通信,想要获取websocket通信的内容就需要使用websocket拦截,大多数是使用中间人代理进行拦截,这里将会使用更简单的方式进行拦截。 前言 开发者工…