標籤:pool 允許 start sel 管理 ict sem cti server進程
之前實現的資料共用的方式只有兩種結構Value和Array。Python中提供了強大的Manager專門用來做資料共用的,Manager是進程間資料共用的進階介面。 Manager()返回的manager對象控制了一個server進程,此進程包含的python對象可以被其他的進程通過proxies來訪問。從而達到多進程間資料通訊且安全。Manager支援的類型有list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Queue, Value和Array。
下面看一個用於多進程共用dict和list資料:
from multiprocessing import Manager, Processdef worker(dt, lt): for i in range(10): dt[i] = i*i # 訪問共用資料 lt += [x for x in range(11, 16)]if __name__ == ‘__main__‘: manager = Manager() dt = manager.dict() lt = manager.list() p = Process(target=worker, args=(dt, lt)) p.start() p.join(timeout=3) print(dt) print(lt)
結果:{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}[11, 12, 13, 14, 15]
進程池
當使用Process類管理非常多(幾十上百個)的進程時,就會顯得比較繁瑣,Pool可以提供指定數量的進程,供使用者調用,當有新的請求提交到pool中時,如果池還沒有滿,那麼就會建立一個新的進程用來執行該請求;但如果池中的進程數已經達到規定最大值,那麼該請求就會等待,直到池中有進程結束,才會建立新的進程。
import timeimport multiprocessingdef fun(msg): print("#########start#### {0}".format(msg)) time.sleep(3) print("#########end###### {0}".format(msg))if __name__ == ‘__main__‘: print("start main") pool = multiprocessing.Pool(processes=3) #在進程池中建立3個進程 for i in range(1, 7): msg = "hello {0}".format(i) pool.apply_async(fun, (msg,))# 執行時間6s+ # pool.apply(fun, (msg,)) #執行時間 6*3=18s+ pool.close() #在調用join之前,要先調用close,否則會報錯,close執行完不會有新的進程加入到pool pool.join() #join 是等待所有的子進程結束,必須在close之後調用 print("end main")結果:start mainstart hello 1start hello 2start hello 3end hello 1start hello 4end hello 2start hello 5end hello 3start hello 6end hello 4end hello 5end hello 6end main6.18000006676 # 使用pool.apply_async()所花費時間18.2129998207 # 使用pool.apply()所花費時間
pool.apply_async 非阻塞,定義的進程池最大數的同時執行
pool.apply 一個進程結束,釋放回進程池,開始下一個進程
從上面的結果中我們可以看到,使用pool.apply_async所花費的時間較少。
多線程
Python中提供了threading模組來對多線程進行操作,線程是應用程式中工作的最小單元,多線程適用於密集型io。
多線程的實現方式有兩種:
方法一:將要執行的方法作為參數傳給Thread的構造方法(和多進程類似)
t = threading.Thread(target=action, args=(i,))
方法二:從Thread類繼承,並重寫run()方法。
方法一樣本:
import threadingdef worker(args): print("開始子進程 {0}".format(args)) print("結束子進程 {0}".format(args))if __name__ == ‘__main__‘: print("start main") t1 = threading.Thread(target=worker, args=(1,)) # 和多進程類似 t2 = threading.Thread(target=worker, args=(2,)) t1.start() t2.start() print("end main") 結果:start main開始子進程 1結束子進程 1開始子進程 2end main結束子進程 2
方法二樣本:
import threadingimport timeclass Hello(threading.Thread):
# 對run()方法進行重寫 def __init__(self, args): super(Hello, self).__init__() self.args = args def run(self): print("開始子進程 {0}".format(self.args)) time.sleep(1) print("結束子進程 {0}".format(self.args))if __name__ == ‘__main__‘: a = 1 print("start main") t1 = Hello(1) t2 = Hello(2) t1.start() t2.start() print("end main")結果:start main開始子進程 1開始子進程 2end main結束子進程 2結束子進程 1
線程鎖
當多線程爭奪鎖時,允許第一個獲得鎖的線程進入臨街區,並執行代碼。所有之後到達的線程將被阻塞,直到第一個線程執行結束,退出臨街區,並釋放鎖。
需要注意,那些阻塞的線程是沒有順序的。
import timeimport threadingdef sub(): global count lock.acquire() #上鎖,第一個線程如果申請到鎖,會在執行公用資料的過程中持續阻塞後續線程 #即後續第二個或其他線程依次來了發現已經被上鎖,只能等待第一個線程釋放鎖 #當第一個線程將鎖釋放,後續的線程會進行爭搶 ‘‘‘線程的公用資料‘‘‘ temp=count print("temp is {0}".format(temp)) time.sleep(0.001) count=temp+1 print("count is {0}".format(count)) ‘‘‘線程的公用資料‘‘‘ lock.release() # 釋放鎖 time.sleep(2)count=0l=[]lock=threading.Lock() for i in range(100): t=threading.Thread(target=sub,args=()) t.start() l.append(t)for t in l: t.join()print(count)結果:100
線程池
採用線程池,花費的時間更少。
文法結構樣本:
import threadpool def ThreadFun(arg1,arg2): pass def main(): device_list=[object1,object2,object3......,objectn]#需要處理的裝置個數 task_pool=threadpool.ThreadPool(8)#8是線程池中線程的個數 request_list=[]#存放工作清單 #首先構造工作清單 for device in device_list: request_list.append(threadpool.makeRequests(ThreadFun,[((device, ), {})])) #將每個任務放到線程池中,等待線程池中線程各自讀取任務,然後進行處理,使用了map函數,不瞭解的可以去瞭解一下。 map(task_pool.putRequest,request_list) #等待所有任務處理完成,則返回,如果沒有處理完,則一直阻塞 task_pool.poll() if __name__=="__main__": main()
pip install threadpool # 安裝threadpool
from threadpool import * #匯入模組
pool = ThreadPool(size) # 定義一個線程池,最多能建立size個線程
requests = makeRequests() # 調用makeRequests建立了要開啟多線程的函數,以及函數相關參數和回呼函數,其中回呼函數可以不寫,default是無,也就是說makeRequests只需要2個參數就可以運行;
[pool.putRequest(req) for req in requests] # 將所有要運行多線程的請求扔進線程池
pool.wait() # 等待所有的線程完成工作後退出。
[pool.putRequest(req) for req in requests]等同於:
for req in requests:
pool.putRequest(req)
例子:
import threadpooldef hello(m, n, o): print("m = {0} n={1} o={2}".format(m, n, o))if __name__ == ‘__main__‘: # 方法1 lst_vars_1 = [‘1‘, ‘2‘, ‘3‘] # 需要處理的線程個數 lst_vars_2 = [‘4‘, ‘5‘, ‘6‘] func_var = [(lst_vars_1, None), (lst_vars_2, None)] # 方法2 # dict_vars_1 = {‘m‘: ‘1‘, ‘n‘: ‘2‘, ‘o‘: ‘3‘} # dict_vars_2 = {‘m‘: ‘4‘, ‘n‘: ‘5‘, ‘o‘: ‘6‘} # func_var = [(None, dict_vars_1), (None, dict_vars_2)] pool = threadpool.ThreadPool(2) # 線程池中的線程個數 requests = threadpool.makeRequests(hello, func_var) # 建立了要開啟多線程的函數,建立需要線程池處理的任務,只需要兩個參數 [pool.putRequest(req) for req in requests] # 將每個任務放入到線程池中 pool.wait()結果:m = 1 n=2 o=3m = 4 n=5 o=6
python多進程(二)