Python--用Java调用Python函数过慢的解决方案

最近的一个软件杯的项目,由于数据分析阶段需要用到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是服务端的返回参数

 

posted on 2020-05-03 21:50  Halone  阅读(2562)  评论(4编辑  收藏  举报