• 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是服务端的返回参数
  • 相关阅读:
    Python接口自动化之request请求封装
    AI缘起——达特茅斯会议
    AirtestProject测试框架
    强化学习落地:竞态场景下基于锁机制的闲置端口查用
    多智能体强化学习入门Qmix
    代码回滚----git reset 和 git revert 使用
    requestAnimationFrame
    深度剖析-事件循环event
    Ubuntu18.04安装ES也就是ELK
    Ubuntu18.04+kafka
  • 原文地址:https://www.cnblogs.com/halone/p/12823740.html
Copyright © 2020-2023  润新知