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是服務端的返回參數

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM