用其他语言调用Python模块,并提高模块的导入速度

tech2026-09-26  2

现在许多的项目都要求实时性,如果直接用Java中的Runtime调用命令行界面中的python函数,则在运行python文件前每次都得重新导入对应的包,导致函数运行的时间格外地长。在最初没经过优化的时候大概每次执行函数都需要10多秒的时间。这样远远不能够满足在界面调用的时候实时性要求。

最开始的想法是对python中的运行效率进行了极致优化,例如将jieba换成jieba_fast,砍除所有用不到的功能,对数据处理的结构,循环结构,变量使用进行了优化,使对应执行的效率大大提高,然而这个过程费力不讨好,经过了一系列优化之后,最终使Java中执行python函数的时间缩短至4秒多。4秒多,虽然在运行过程中可以等待一小段时间,但这样一来的话,如果要调用的函数次数一多,经过的时间也是漫长的,同时,用户的体验也不佳。

经过对python中的结构进行分析了之后,优化到极致之后调用对应函数时间长的原因主要在于import对应包的阶段,而这个过程并不能通过优化来使时间缩短。

例如,导入包

import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation import scipy.ndimage import scipy.signal import sys import os

下面是导入包需要的时间:

matplotlib.pyplot [300ms] numpy [110ms] scipy.signal [200ms]

通过不断地搜索,发现可以用socket套接字编程来解决这个问题,将python上对应的接口转化为Server,利用client来访问Server上的接口,这样一来就不用反复import对应的包名了。

服务器端:

创建文件server.py

# -- coding:utf-8 -*- import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation import scipy.ndimage import scipy.signal import sys import os import socket End='end send' #这里是为了判断对应的客户端请求命令的结束标志,目的是为了接受不超过8192个字符的(client)客户端请求。 def recv_end(the_socket): total_data=[] while True: data=the_socket.recv(8192).decode('utf-8') print('1: ' + data) if End in data: total_data.append(data[:data.find(End)]) # 取'end send'前面的字段 print( total_data) break total_data.append(data) if len(total_data)>1: #check if end_of_data was split last_pair=total_data[-2]+total_data[-1] print( last_pair) if End in last_pair: total_data[-2]=last_pair[:last_pair.find(End)] total_data.pop() print( total_data) break return ''.join(total_data) HOST = '' # Symbolic name meaning all available interfaces PORT = 50007 # Arbitrary non-privileged port s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(1) while 1: conn, addr = s.accept() print('Connected by', addr) # e.g., Connected by ('127.0.0.1', 13917) data=recv_end(conn) # 接受客服端发送过来的数据,并进行处理 method = data[0] subdata = data[1:] if (method == "1"): #当客户端传递过来的第一个字符为1时,params表示传递过来的参数 params=subdata.split("|") #这里写要调用的函数 #将结果返回给客户端 conn.sendall((str((params[0],params[1]))).encode()) # 发送给客户端 #elif method=='2': #当客户端传递过来的第一个字符为2时 # #需要执行的命令2 # update plot # data = conn.recv(1024) # if not data: break # conn.sendall(("PLOTTING:" + str(data)).encode()) # update plot conn.close()

客户端:

创建文件client.py

# -- coding:utf-8 -*- #调用服务端接口客户端,以缩短调用时间 import socket import sys HOST = '127.0.0.1' # The remote host #HOST = '' # The remote host PORT = 50007 # The same port as used by the server End='end send' def cl_test(test1,test2): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.sendall((str(1)+ test1+"|"+test2 +End).encode()) #str(1)表示第一个字符,然后在server端中规定字符串用|隔开 data = [] while True: subdata = s.recv(20480) #接受服务端返回参数 if not subdata: break data.append(str(subdata, encoding='utf-8')) data = ''.join(data) s.close() return data #data是服务端的返回参数 print( 'Received', repr(cl_test('wode','nide ne ')))

运行流程:

(1)首先开启服务端:

python server.py

开启后,服务器端等待接收数据。

(2)启动客户端:

python client.py

客户端接收到服务器端发送回来的数据后,自动结束。

(3)服务器端显示的数据:

服务器端一直在运行状态,未结束。

 

最后Socket相关函数和连接过程,请参见https://www.cnblogs.com/wumingxiaoyao/p/7047658.html

最新回复(0)