併發程式設計(執行緒)——前言理論,開啟執行緒的兩種方式,執行緒物件join方法,同一個程序下的多個執行緒資料共享,執行緒物件及其他方法,守護執行緒,執行緒互斥鎖,GIL全域性直譯器鎖理論
阿新 • • 發佈:2020-08-25
一、執行緒理論
計算機相當於大工廠,工廠裡有一個個的車間(程序),有很多人(執行緒)幹不同的事
真正幹活的是執行緒--》執行緒是cup排程的最小單位
程序是資源分配的最小單位,執行緒是CPU排程的最小單位。每一個程序中至少有一個執行緒
執行緒開銷更小,更輕量級
二、開啟執行緒的兩種方式
1、函式式
#第一種 from threading import Thread import time def task(): print('開始') time.sleep(1) print('結束') if __name__ == '__main__': t=Thread(target=task,) #例項化得到一個物件 t.start() # 物件.start()啟動執行緒 print('主'
2、通過類繼承方式
#第二種 from threading import Thread import time class MyThread(Thread): def run(self): print('開始') time.sleep(1) print('結束') if __name__ == '__main__': t=MyThread() t.start() print('主')
三、執行緒物件join方法
from threading import Thread import time def task(n): print('開始') time.sleep(n) print('結束') if __name__ == '__main__': t=Thread(target=task,args=(2,)) t.start() t1=Thread(target=task,args=(3,)) t1.start() t.join() # 等待子程序執行結束 t1.join() print('主')
四、同一個程序下多個執行緒資料共享
from threading import Thread import time money = 99 def task(n): global money money=n print('開始') # time.sleep(n) print('結束') if __name__ == '__main__': t = Thread(target=task, args=(2,)) t.start() t1 = Thread(target=task, args=(66,)) t1.start() t.join() t1.join() print(money) print('主')
五、執行緒物件及其他方法
from threading import Thread, current_thread,active_count import time def task(): print('開始') print(current_thread().name) # 執行緒名字 time.sleep(1) print('結束') if __name__ == '__main__': t1 = Thread(target=task,name='egon') t2 = Thread(target=task) t1.start() t2.start() print(active_count()) # 打印出3 ,開了兩個執行緒,還有一個主執行緒
from threading import Thread, current_thread,active_count import time import os def task(n): print('開始') print(current_thread().name) # 執行緒名字 # 如果列印程序id號,會是什麼 print(os.getpid()) time.sleep(n) print('結束') if __name__ == '__main__': t1 = Thread(target=task,name='egon',args=(2,)) t2 = Thread(target=task,args=(8,)) t1.start() t2.start() t1.join() print('---------',t1.is_alive()) print('---------',t2.is_alive()) # 當作執行緒id號 print('*********',t1.ident) print('*********',t2.ident) print(os.getpid()) print(active_count()) # 打印出3 ,開了兩個執行緒,還有一個主執行緒
總結必知:
1 執行緒t.name t.getName() 2 當前程序下有幾個執行緒存活active_count 3 t1.is_alive() 當前執行緒是否存活 4 t1.ident 當作是執行緒id號
六、守護執行緒
from threading import Thread, current_thread,active_count import time import os def task(n): print('開始') time.sleep(n) # print('-----',active_count()) print('結束') if __name__ == '__main__': t1 = Thread(target=task,name='egon',args=(10,)) # t1.daemon = True t1.setDaemon(True) t1.start() t2 = Thread(target=task,name='egon',args=(4,)) t2.start() print('主')
七、執行緒互斥鎖
from threading import Thread,Lock # from multiprocessing import Lock import time import random money = 99 def task(n,mutex): global money # 在修改資料的時候,枷鎖 mutex.acquire() temp = money time.sleep(0.1) money = temp - 1 # 修改完以後,釋放鎖,其它執行緒就能再次搶到鎖 mutex.release() if __name__ == '__main__': ll=[] mutex=Lock() for i in range(10): t = Thread(target=task, args=(i,mutex)) t.start() ll.append(t) for i in ll: i.join() print(money)
八、GIL全域性直譯器鎖理論
1 python的直譯器有很多,cpython,jpython,pypy(python寫的直譯器)
2 python的庫多,庫都是基於cpython寫起來的,其他直譯器沒有那麼多的庫
3 cpython中有一個全域性大鎖,每條執行緒要執行,必須獲取到這個鎖
4 為什麼會有這個鎖呢?python的垃圾回收機制
5 python的多執行緒其實就是單執行緒
6 某個執行緒想要執行,必須先拿到GIL,我們可以把GIL看作是“通行證”,並且在一個python程序中,GIL只有一個。拿不到通行證的執行緒,就不允許進入CPU執行
7 總結:cpython直譯器中有一個全域性鎖(GIL),執行緒必須獲取到GIL才能執行,我們開的多執行緒,不管有幾個cpu,同一時刻,只有一個執行緒在執行(python的多執行緒,不能利用多核優勢)
8 如果是io密集型操作:開多執行緒
9如果是計算密集型:開多程序
(8 9 這兩句話,只針對與cpython直譯器)
九、
---38---