最近在學習python多線程,寫一下隨筆就當複習了。另外強烈推薦你們看一下《Python核心編程》這本書,這本書裏面能夠幫你學習python進階。python
一。基本概念:編程
1.線程:多線程
線程又稱爲輕量級進程,線程之間能夠進行信息共享,線程能夠當作是主進程或‘主線程’的迷你進程。併發
2.進程:app
進程又稱爲重量級進程,進程之間是獨立的,進程間共享信息要經過 ‘進程間通訊(IPC)’ 來進行。異步
3.同步:函數
同步是指一個任務執行完成後,另外一個任務接着進行,就是一個挨着一個,好比你在食堂打飯,一號窗口的菜好吃,有不少人排隊,只有前一個打完飯,後一個才能夠打飯。學習
4.異步:spa
異步是指多個任務同時進行,好比:食堂有不少打飯窗口,不少人能夠同時進行打飯。線程
5. I/O:
I/O是 input/output 的縮寫,表明的含義是讀寫。
6. I/O密集型代碼(I/O bound):
I/O密集型是指程序進行讀寫操做要不少,計算相對較少。
7. 計算密集型代碼(CPU bound):
計算密集型是指程序主要進行計算,而讀寫操做要少。
8. 併發和並行:
併發 CPU數量<線程數,併發是指相同時間間隔內執行任務。
並行 CPU數量>線程數,並行是指多個任務同時執行。
二。python和線程:
python代碼的執行由python虛擬機(解釋器主循環)來進行控制。
Python還有一個GIL(全局解釋器鎖),用來控制程序只有一個線程在執行。
GIL鎖執行過程:
鎖定
執行
釋放
返回第一步。
python執行多線程時,實際上是在相同時間間隔內對任務進行執行,每一個任務執行一小段時間,而後掛起,在執行下一個,一直到最後一個,而後在從第一個開始,如此往復,直至結束。
python對於I/O密集型比計算密集型要友好。緣由:python在執行I/O密集型程序時,主要進行文件讀寫,而計算較少,每一個任務在計算的同時能夠進行對其餘以完成的計算讀寫,而計算密集型對於計算較多,一直佔用CPU,致使處理效率不高,因此對於計算密集型並不友好。
三。threading模塊
對於多線程有thread模塊和threading模塊。thread模塊在執行多線程時,在不加鎖的狀況下,若是主線程結束,而子線程還未結束時,子線程會被強制中止,形成得不到運行結果。在進行多線程學習時推薦使用threading模塊。
1.添加線程: threading.Thread(target=函數名,args=(須要傳入的參數))
Thread類還能夠傳入name,給線程命名。
2.判斷線程是否激活狀態: is_alive()
3.獲取線程數量: threading.active_count()
4.獲取當前線程:threading.current_thread()
5.得到線程名字:.name
6.等待線程:。join()
等待與不等待:
等待:
1 def a_1(): 2 print('aaaaa') 3 time.sleep(3) 4 print('aaaaa') 5 def a_2(): 6 print('bbbbb') 7 time.sleep(5) 8 print('bbbbb') 9 def main(): 10 print('....start....') 11 t1 = threading.Thread(target=a_1) 12 t2 = threading.Thread(target=a_2) 13 t1.start() 14 t2.start() 15 print('....end....') 16 17 if __name__ == '__main__': 18 main() 19 20 21 運行結果: 22 23 ....start.... 24 aaaaa 25 bbbbb 26 ....end.... 27 aaaaa 28 bbbbb 29 30 Process finished with exit code 0
從運行結果能夠看出,在不添加等待時,運行結果並非咱們想要的結果。
下面是不用 .join()的等待:
def main(): print('....start....') t1 = threading.Thread(target=a_1) t2 = threading.Thread(target=a_2) t1.start() t2.start() time.sleep(8) print('....end....') if __name__ == '__main__': main() 運行結果: ....start.... aaaaa bbbbb aaaaa bbbbb ....end.... Process finished with exit code 0
經過添加time.sleep()語句使主線程等待子線程運行結束再運行下一步操做。打印內容均在...start....和...end...之間。
下面是運用 .join()進行等待。
def main(): print('....start....') t1 = threading.Thread(target=a_1) t2 = threading.Thread(target=a_2) t1.start() t2.start() t1.join() t2.join() print('....end....') if __name__ == '__main__': main() 運行結果: ....start.... aaaaa bbbbb aaaaa bbbbb ....end.... Process finished with exit code 0
經過該結果能夠看出,添加sleep()和join()效果同樣,可是推薦使用.join() ,由於在運行程序的時候用sleep()等待,還得知道等待時間,比較麻煩。join()較爲方便。
建立線程方法:
<1> 給Thread類傳入函數
<2>給Thread類傳入一個實例類
<3>建立一個子類,繼承Thread類,而後將函數傳入子類中
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
在不用多線程時:
import datetime
def num_1():
print('start...1')
time.sleep(2)
print('end...1')
def num_2():
print('start...2')
time.sleep(4)
print('end...2')
def main():
a = datetime.datetime.now()
print('.............start...........')
num_1()
num_2()
print('..............end............')
b = datetime.datetime.now()
p = (b - a).seconds
print('運行%s秒 ' % p)
if __name__ == '__main__':
main()
建立兩個函數,分別打印不一樣內容,並在程序執行完成打印執行時間。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
對於<1>
下面是示範代碼: .join()是主線程等待子線程完成後在執行下一步操做。
1 import threading 2 import datetime 3 #傳遞函數(1) 4 def num(nu,se): 5 print('%s start' % nu) 6 time.sleep(se) 7 print('%s end' % nu) 8 9 time_list = [2,4] 10 def main(): 11 a = datetime.datetime.now() 12 print('.....start.....') 13 thread_list = [] 14 for x in range(len(time_list)): 15 t = threading.Thread(target=num,args=(x,time_list[x])) 16 thread_list.append(t) 17 for x in thread_list: 18 x.start() 19 for x in thread_list: 20 x.join() 21 print('.....end.....') 22 b = datetime.datetime.now() 23 p = (b - a).seconds 24 print('運行%s秒' % p) 25 if __name__ == '__main__': 26 main()
<2>添加一個實例類。
class New_1(): def __init__(self,num,se): self.num = num self.se = se def __call__(self): return self.num(*self.se) pass def main(): a = datetime.datetime.now() print('...start...') thread_list = [] for x in range(len(time_list)): t = threading.Thread(target=New_1(num,(x+1,time_list[x]))) thread_list.append(t) for x in thread_list: x.start() for x in thread_list: x.join() print('...end...') b = datetime.datetime.now() p = (b-a).seconds print('運行%s秒' % p) if __name__ == '__main__': main()
運行結果:
...start...
1 start
2 start
1 end
2 end
...end...
運行4秒
Process finished with exit code 0
3.繼承Thread類,將內容傳遞進子類中。
下面是代碼:
#傳遞函數(1) def num(nu,se): print('%s start' % nu) time.sleep(se) print('%s end' % nu) time_list = [2,4] class New_2(threading.Thread): def __init__(self,num,se): super().__init__() self.num = num self.se = se
#對於下面的函數run()進行重寫,能夠靈活的定義函數,函數名必須是run(),不然在傳入參數後運行時,不會運行多線程。 def run(self): return self.num(*self.se) pass def main(): a = datetime.datetime.now() print('...start...') thread_list = [] for x in range(len(time_list)): t = New_2(num,(x,time_list[x])) thread_list.append(t) for x in thread_list: x.start() for x in thread_list: x.join() print('...end...') b = datetime.datetime.now() p = (b-a).seconds print('運行%s秒' % p) if __name__ == '__main__': main() 運行結果: ...start... 0 start 1 start 0 end 1 end ...end... 運行4秒 Process finished with exit code 0
對於以上三種添加線程的方法,能夠根據本身喜愛自行選擇,其餘的作了解便可。
若是有不對的地方,還請各位給予指正。
感謝你們的閱讀。