SAP下載報表速度慢?為啥你不試試python多執行緒

NewJune發表於2022-01-28

  由於SAP系統自身原因,或者公司內部ABAP程式碼的演算法效率不高,我們經常遇到,手工執行某個事務程式碼下載某個報表會非常耗時,小爬曾見過公司某個自開發的報表,單家公司的資料下載超過半小時。如果我們剛好接到一個自動化需求:批量下載N個公司的某些報表資料,即使我們用python指令碼實現了該場景的自動化,效率依然不高。

 

  或許我們可以嘗試python的多執行緒技術來加速。這應該是個好主意,現在小爬就帶著大家往多執行緒這個方向思考。

  SAP GUI的會話數量一般都有限制,各個公司的SAP策略或有不同,在小爬所在的公司,SAP GUI客戶端允許的會話數不超過6,我們不妨用多個會話分別去下載資料。小爬遇到的場景是:有N家公司,分別進入4個事務程式碼下載四張不同的表,這四張表的匯出速度各有不同,有的較快,有的極慢。

方案一:我們啟用四個sap會話,分別下載這四張表,每次引數中傳入不同的公司程式碼;

方案二:我們開啟最大SAP會話數6,每個會話都執行一些公司程式碼,也都會下載到這四張表。

  仔細思考後不難發現,方案二可以將下載速度最大化。方案一中各個會話對應的報表下載速度各不相同,最終速度受最慢的那個影響,而且它只能根據四張報表來啟用四個會話執行緒;而方案一,則可以同時開啟六個SAP會話執行緒,且每個會話下都會下載這四張表,無形中,避免了”一個會話在苦戰,其它會話全圍觀“的尷尬局面。

  具體到程式碼層面,我們需要批量建立多個sap會話,新建一個全域性的任務佇列companyQ,每個sap會話獨自不停去佇列中取任務(下載需要的引數),驅動各自負責的SAP會話來完成資料的下載,當佇列中所有任務都完成了,意味著執行緒結束。等以上思路都琢磨明白了,程式碼該怎麼寫就不再是一個問題了。

第一步:定義連線sap的方法,並自動開啟N個session會話

第二部:定義下載SAP資料的方法

第三步:開啟多個執行緒,分別呼叫同一個方法,傳入不同session的index作為引數,實現對多個會話的自動化控制

def connect_SAP(maxSessionNum):
    '''連線SAP,並建立maxSessionNum個session會話,返回session列表(含session索引)'''
    SapGuiAuto = win32com.client.GetObject("SAPGUI")
    application = SapGuiAuto.GetScriptingEngine
    connection = application.Children(0)
    indexSessions=[]
    session=connection.Children(0)
    cnt=connection.Children.Count
    if cnt<maxSessionNum:
        for _ in range(maxSessionNum-cnt):
            session.Createsession()
            sleep(0.5)
    sleep(2)
    for index,session in enumerate(connection.Children):
        indexSessions.append([index,session])
    SapGuiAuto=None
    application=None
    connection=None
    session=None
    return indexSessions

def exportSapData(sessionIndex):
    '''給定公司程式碼,期間,依次匯出應收社保、公積金,應付社保、公積金報表資料'''
    pythoncom.CoInitialize()
    SapGuiAuto = win32com.client.GetObject("SAPGUI")
    application = SapGuiAuto.GetScriptingEngine
    connection = application.Children(0)
    session=connection.Children(sessionIndex)

    '''輸入zhr054,匯出HR社保往來掛賬應付公積金明細表'''
    session.findById("wnd[0]").iconify() 
    unfinishedNum=companyQ.unfinished_tasks
    while True:
        lk.acquire()
        if not companyQ.empty():
            companyCode=companyQ.get(block=False)
        else:
            lk.release()
            break
        lk.release()
        downloadFunc(companyCode,reportPeriod)

  下面的程式碼便演示瞭如何藉助python多執行緒技術,針對每個執行緒,傳入的引數就是session的索引號(0-6),最終把他們分別啟動起來~

connect_SAP(maxSessionNum=5)
sleep(3)
threads = []
for i in range(6):
    threads.append(threading.Thread(target=exportSapData,args=(i,)))
for companyCode in companies:
    companyQ.put(companyCode)
for t in threads:
    t.setDaemon(True)
    t.start()
for t in threads:
    t.join()
 
print ("all over %s" %ctime())
endtime = datetime.datetime.now()
secs = (endtime - starttime).seconds
minutes = secs // 60
second = secs % 60  
timeStr = str(minutes) + '分鐘' + str(second) + "秒"
root=tk.Tk()
root.withdraw()
tkinter.messagebox.showinfo("資訊",f"已完成所有資料下載,執行時間為:{timeStr}")

 

  以上,就是小爬利用python多執行緒來驅動sap多個會話進行特定自動化操作的主要過程。基於這一波操作,整個下載效率可以提升4-6倍。那一刻,彷彿有6個自動化機器人在同時幫小爬分擔枯燥的資料下載工作,幸福感瞬間拉滿!!!

  有任何疑問,歡迎評論區積極留言,同時也歡迎掃碼關注我的公眾號,獲取更多爬蟲、資料分析的知識!

 

相關文章