1. 程式人生 > >python執行緒池(threadpool)模組使用

python執行緒池(threadpool)模組使用

最近碰到個問題,需要telnet登入上千臺機器去取主機名;其中有使用者名稱密碼互動部分,有需要延遲的部分,大概一次登入一次到處理完要10s,1000臺機器序列處理就需要1000×10s,差不多三個小時,這是很難受的事情;

之前用thread的start_new_thread方法也可以實現,但是執行緒數量不好控制,沒找到相關的控制執行緒數量的鎖;

找了下關於python的執行緒池,找到threadpool這麼一個模組,可以滿足我的需求,見:

http://chrisarndt.de/projects/threadpool/

我下的是版本1.2.2:

http://chrisarndt.de/projects/threadpool/download/threadpool-1.2.2.tar.bz2

放到當前目錄或者python模組庫都行,用法很簡單,見:

    Basic usage::  
      
        >>> pool = ThreadPool(poolsize)  
        >>> requests = makeRequests(some_callable, list_of_args, callback)  
        >>> [pool.putRequest(req) for req in requests]  
        >>> pool.wait()  

第一行定義了一個執行緒池,表示最多可以建立poolsize這麼多執行緒;

第二行是呼叫makeRequests建立了要開啟多執行緒的函式,以及函式相關引數和回撥函式,其中回撥函式可以不寫,default是無,也就是說makeRequests只需要2個引數就可以執行;

第三行用法比較奇怪,是將所有要執行多執行緒的請求扔進執行緒池,[pool.putRequest(req) for req in requests]等同於:

    for req in requests:  
        pool.putRequest(req)  
第四行是等待所有的執行緒完成工作後退出;

下面看下我的程式碼,使用執行緒池前後程式碼對比,不使用執行緒池:

    import telnetlib  
    import time  
      
    #執行比較耗時的函式,需要開啟多執行緒  
    def myTelnet(L):  
        tn = telnetlib.Telnet(L[0])  
        time.sleep(2)  
        ...  
        idx = tn.expect(["Username:", "login:"], timeout=5)  
        ...  
        time.sleep(3)  
        x = tn.read_very_eager()  
        tn.close()  
        ...  
        return  
      
    #模擬255個ip,需要逐個登入的函式  
    def myIpPool(ipPrefix):  
        List=[]  
        for i in range(1, 255):  
            List.append("%s.%d" % (ipPrefix, i))  
        return List  
      
    #序列執行telnet登入  
    L=myIpPool("200.200.200")  
    for i in range(len(L)):  
        myTelnet(L[i])  
如果myTelnet每次執行要10s,那麼255次myTelnet就需要2550s,大概是40分鐘;

用多執行緒的情況:

    import telnetlib  
    import time  
    import threadpool  
      
    #執行比較耗時的函式,需要開啟多執行緒  
    def myTelnet(L):  
        tn = telnetlib.Telnet(L[0])  
        time.sleep(2)  
        ...  
        idx = tn.expect(["Username:", "login:"], timeout=5)  
        ...  
        time.sleep(3)  
        x = tn.read_very_eager()  
        tn.close()  
        ...  
        return  
      
    #模擬255個ip,需要逐個登入的函式  
    def myIpPool(ipPrefix):  
        List=[]  
        for i in range(1, 255):  
            List.append("%s.%d" % (ipPrefix, i))  
        return List  
      
          
    #使用多執行緒執行telnet函式  
    pool = threadpool.ThreadPool(10)  
    requests = threadpool.makeRequests(myTelnet, L)  
    [pool.putRequest(req) for req in requests]  
    pool.wait()  
    output.close()  
開始是個執行緒,理論上應該快10倍,實際可能沒這麼快,我將myTelnet函式改成只的sleep 10秒,什麼也不幹,測了下執行完需要260s,幾乎是10倍的速度;改成如下:
    pool = threadpool.ThreadPool(30)  
90s執行完畢,說明執行緒池還是很有用的東西