现在许多的项目都要求实时性,如果直接用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