最近的一个软件杯的项目,由于数据分析阶段需要用到Python,在Python上写完分析过程后,在JavaWeb界面上数据的展示页面遇到了一个问题。
比赛中要求项目必须具有实时性,而如果直接用Java中的Runtime调用命令行界面中的python函数,则在运行python文件的时候执行前每次都得重新导入对应的包,导致函数运行的时间格外地长,第一次没经过优化的时候大概每次执行函数都需要10多秒的时间。这样远远不能够满足在界面调用的时候实时性的要求。
最开始的想法是对python中的运行效率进行了极致优化,例如jieba换成jieba_fast,砍除所有用不到的功能,对数据处理的结构,循环结构,变量使用进行了优化,使对应执行的效率大大提高,然而这个过程费力不讨好,经过了一系列优化之后,最终能将在Java中调用对应python函数的时间缩短至4秒多。4秒多,虽然在运行过程中可以等待一小段时间,但这样一来的话,如果要调用的函数次数一多,经过的时间也是漫长的,同时,用户的体验也不佳。
经过对python中的结构进行分析了之后,优化到极致之后调用对应函数时间长的原因主要在于import对应包的阶段,而这个过程并不能通过优化来使时间缩短。
通过不断地搜索对应资料,最终发现了有一个人也有同样的问题,他询问了很多人,并且别人也没有给他对应的实例,因此他选择了利用自己的想法:用socket套接字编程来解决这个问题,将python上对应的接口转化为Server,利用client来访问Server上的接口,这样一来就不用反复import对应的包名了
网址:https://www.it1352.com/902381.html
经过对应的优化之后,从原本的4秒多,到现在的0.55秒左右,基本上解决了这个问题。
现在用一个python端的socket服务端和一个python的客户端为例子。
服务端:
#!/usr/bin/env python # -*- coding:utf-8 -*- #@Time : 2020/5/3 18:44 #@Author: hdq #@File : server.py #将接口以服务器的方式暴露以提供给Java调用缩短调用时间 import socket #这里写需要加载的包 End='end send' #这里是为了判断对应的客户端请求命令的结束标志,目的是为了接受超过1024个字符的(client)客户端请求。 def recv_end(the_socket): total_data=[] while True: data=the_socket.recv(8192).decode('utf-8') if End in data: total_data.append(data[:data.find(End)]) 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] if End in last_pair: total_data[-2]=last_pair[:last_pair.find(End)] total_data.pop() 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) 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 conn.close()
client端(可以不用是python语言的,但是传递到服务端的语法要一致才能被正确识别,客户端这里并不需要加载头文件):
#!/usr/bin/env python # -*- coding:utf-8 -*- #@Time : 2020/5/3 18:47 #@Author: hdq #@File : client.py #调用服务端接口客户端,以缩短调用时间
import socket HOST = '127.0.0.1' # 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是服务端的返回参数