前言

在这里插入图片描述

Python 和 Go 语言是两种不同编程语言,它们分别有自己的优势和适用场景。在一些项目中,由于团队内已有的技术栈或者某一部分业务需求可能需要 Python 和 Go 相互调用,以此来提升效率性能

方案简介

1.动态库调用

一、调用步骤

go代码编译成so库 -> python通过ctypes引用so库并指定需要调用的函数(同时可指定入参类型返回值类型) -> 指定后按python使用函数方式调用。

需要注意的是:pythongo之间参数传递是需要经过C的数据类型转换的,因此需要了解pythonctypes数据类型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_pgo中需要指定接收的参数数据类型为 *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)
    }
    
    

原文地址:https://blog.csdn.net/qq_45066628/article/details/133612258

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_44070.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注