標籤:start 活動 聲明 ipc 自己 多工 isp src call
聲明:樣本來源《python核心編程》
前言
單線程處理多個外部輸入源的任務只能使用I/O多工,如:select,poll,epoll。
特別值得注意的是:由於一個串列程式需要從每個 I/O 終端通道來檢查使用者的輸入,程式在讀取 I/O 終端通道時不能阻塞,因為使用者輸入的到達時間是不確定的,並且阻塞會妨礙其他 I/O 通道的處理。
select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而非同步I/O則無需自己負責進行讀寫,非同步I/O的實現只負責把資料從核心拷貝到使用者空間。
為此就引出了我們的主體多線程,多線程的特點:
- 本質上是非同步
- 需要多個並發活動
- 每個活動的處理順序可能是不確定的,或者說是隨機的、不可預測的。
什麼是進程?
進程就是一個執行中的程式。每個進程都擁有自己的地址空間、記憶體、資料棧以及其他用於跟蹤執行的輔助資料。作業系統管理其上所有進程的執行,並為這些進程合理地分配時間。進程也可以通過派生( fork 或 spawn)新的進程來執行其他任務,不過因為每個新進程也都擁有自己的記憶體和資料棧等,所以只能採用處理序間通訊( IPC)的方式共用資訊。
什麼是線程?
線程(有時候稱為輕量級進程)與進程類似,不過它們是在同一個進程下執行的,並共用相同的上下文。可以將它們認為是在一個主進程或“主線程”中並行啟動並執行一些“迷你進程”。
python中的多線程實現threading模組中的對象列表
ps:我們通過python實現多線程編程,主要用到的是threading.Thread對象
Thread對象常用屬性和方法
多線程樣本
context: python2.7.13
python通過Thread對象建立一個多線程執行個體,主要有3種方式:
- 建立 Thread 的執行個體,傳給它一個函數。
- 建立 Thread 的執行個體,傳給它一個可調用的類執行個體。
- 派生 Thread 的子類,並建立子類的執行個體。
ps:我們通常會選擇第一個或第三個方案。當你需要一個更加符合物件導向的介面時,會選擇後者。所以,建議使用第三種方案,它是最適合你的應用和未來擴充的方法。
樣本1:建立 Thread 的執行個體,傳給它一個函數。
1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 import threading 4 from time import sleep,ctime 5 6 loops = [4,2] 7 8 def loop(nloop,nsec): 9 print "start loop",nloop,"at:",ctime()10 sleep(nsec)11 print "loop",nloop,‘done at:‘,ctime()12 13 def main():14 print "Starting at:",ctime()15 threads = []16 nloops = range(len(loops))17 #完成所有線程分配,並不立即開始執行18 for i in nloops:19 t = threading.Thread(target=loop,args=(i,loops[i]))20 threads.append(t)21 #開始調用start方法,同時開始所有線程22 for i in nloops:23 threads[i].start()24 #join方法:主線程等待所有子線程執行完成,再執行主線程接下來的操作。25 for i in nloops:26 threads[i].join()27 28 print "All done at:",ctime()29 if __name__=="__main__":30 main()
Starting at: Sun Jun 18 10:00:49 2017start loop 0 at: Sun Jun 18 10:00:49 2017start loop 1 at: Sun Jun 18 10:00:49 2017loop 1 done at: Sun Jun 18 10:00:51 2017loop 0 done at: Sun Jun 18 10:00:53 2017All done at: Sun Jun 18 10:00:53 2017Process finished with exit code 0
resault樣本2:建立 Thread 的執行個體,傳給它一個可調用的類執行個體
#!/usr/bin/env python#-*- encoding:utf-8 -*-import threadingfrom time import sleep,ctimeloops = [4,2]class ThreadFunc(object): def __init__(self,func,args,name=""): self.name = name self.func = func self.args = args #使類具有函數行為,就像函數的代理(proxy) def __call__(self): self.func(*self.args)def loop(nloop,nsec): print "start loop",nloop,"at:",ctime() sleep(nsec) print "loop",nloop,‘done at:‘,ctime()def main(): print "Starting at:",ctime() threads = [] nloops = range(len(loops)) #完成所有線程分配,並不立即開始執行 for i in nloops: t = threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__)) threads.append(t) #開始調用start方法,同時開始所有線程 for i in nloops: threads[i].start() #join方法等待子線程執行完成,再執行主線程接下來的操作。 for i in nloops: threads[i].join() print "All done at:",ctime()if __name__=="__main__": main()
傳入類執行個體
Starting at: Sun Jun 18 10:03:52 2017start loop 0 at: Sun Jun 18 10:03:52 2017start loop 1 at: Sun Jun 18 10:03:52 2017loop 1 done at: Sun Jun 18 10:03:54 2017loop 0 done at: Sun Jun 18 10:03:56 2017All done at: Sun Jun 18 10:03:56 2017Process finished with exit code 0
resault樣本3:派生 Thread 的子類,並建立子類的執行個體。自訂類MyThread
- 檔案名稱:mythread.py,
- 內容:MyThread為threading.Thread的衍生類別
#!/usr/bin/env python#-*- coding:utf-8 -*-import threadingfrom time import sleep,ctimeclass MyThread(threading.Thread): def __init__(self,func,args,name=""): threading.Thread.__init__(self) self.name = name self.func = func self.args = args def get_res(self): return self.res def run(self): print "Starting",self.name,"at:",ctime() self.res = self.func(*self.args) print self.name,"finish at:",ctime()
菲波那切數列,階乘,累加單線程也多線程對比
#!/usr/bin/env python#-*- coding:utf-8 -*-#MyThread為自訂的threading.Thread的衍生類別from mythread import MyThreadfrom time import sleep,ctime#斐波那契數列def fib(x): sleep(0.005) if x < 2:return 1 return (fib(x-2)+fib(x-1))#階乘def fac(x): sleep(0.1) if x < 2:return 1 return (x*fac(x-1))#累加def sum(x): sleep(0.1) if x < 2:return 1 return (x + sum(x-1))funcs = [fib,fac,sum]n = 12def main(): nfuncs = range(len(funcs)) print "---SINGLE THREAD---" for i in nfuncs: print "Starting",funcs[i].__name__,"at:",ctime() print funcs[i](n) print funcs[i].__name__,"finish at:",ctime() print "\n---MULTIPLE THREADS---" threads = [] for i in nfuncs: t = MyThread(funcs[i],(n,),funcs[i].__name__) threads.append(t) for i in nfuncs: threads[i].start() for i in nfuncs: threads[i].join() print threads[i].get_res() print "All Done!"if __name__ == ‘__main__‘: main()
---SINGLE THREAD---Starting fib at: Sun Jun 18 09:12:17 2017233fib finish at: Sun Jun 18 09:12:24 2017Starting fac at: Sun Jun 18 09:12:24 2017479001600fac finish at: Sun Jun 18 09:12:26 2017Starting sum at: Sun Jun 18 09:12:26 201778sum finish at: Sun Jun 18 09:12:27 2017---MULTIPLE THREADS---Starting fib at: Sun Jun 18 09:12:27 2017Starting fac at: Sun Jun 18 09:12:27 2017Starting sum at: Sun Jun 18 09:12:27 2017fac finish at: Sun Jun 18 09:12:28 2017sum finish at: Sun Jun 18 09:12:28 2017fib finish at: Sun Jun 18 09:12:34 201723347900160078All Done!Process finished with exit code 0
resault
以單線程模式運行時,只是簡單地依次調用每個函數,並在函數執行結束後立即顯示相應的結果。
而以多線程模式運行時,並不會立即顯示結果。 因為我們希望讓 MyThread 類越通用越好(有輸出和沒有輸出的調用都能夠執行),我們要一直等到所有線程都執行結束,然後調用get_res()方法來最終顯示每個函數的傳回值。
python之多線程