標籤:onclick 卡住 rgs isalive 就是 作業系統 線程同步 mutex 忽略
一 什麼是線程
在傳統作業系統中,每一個進程都有一個地址空間,而且預設就有一個控制線程
線程顧名思義,就是一條流水線工作的過程,一條流水線必須屬於一個車間,一個車間的工作過程是一個進程工作車間負責吧資源整合到一起,是一個資源單位,而一個車間內至少有一個流水線
進程只是用來把資源集中到一起,二線程才是cpu上的的執行單位
線程是代碼的運行過程
二 為何要用線程
1.同一個進程下,多個線程共用該進程下的資源
2.線程比進程開銷要小得多
三 開啟線程的兩種方式
#方式一from threading import Threadimport timedef sayhi(name): time.sleep(2) print(‘%s say hello‘ %name)if __name__ == ‘__main__‘: t=Thread(target=sayhi,args=(‘egon‘,)) t.start() print(‘主線程‘)
方式一
#方式二from threading import Threadimport timeclass Sayhi(Thread): def __init__(self,name): super().__init__() self.name=name def run(self): time.sleep(2) print(‘%s say hello‘ % self.name)if __name__ == ‘__main__‘: t = Sayhi(‘egon‘) t.start() print(‘主線程‘)
方式二四 線程相關的其他方法
Thread執行個體對象的方法 # isAlive(): 返回線程是否活動的。 # getName(): 返回線程名。 # setName(): 設定線程名。threading模組提供的一些方法: # threading.currentThread(): 返回當前的線程變數。 # threading.enumerate(): 返回一個包含正在啟動並執行線程的list。正在運行指線程啟動後、結束前,不包括啟動前和終止後的線程。 # threading.activeCount(): 返回正在啟動並執行線程數量,與len(threading.enumerate())有相同的結果。
from threading import Threadimport threadingfrom multiprocessing import Processimport osdef work(): import time time.sleep(3) print(threading.current_thread().getName())if __name__ == ‘__main__‘: #在主進程下開啟線程 t=Thread(target=work) t.start() print(threading.current_thread().getName()) print(threading.current_thread()) #主線程 print(threading.enumerate()) #連同主線程在內有兩個啟動並執行線程 print(threading.active_count()) print(‘主線程/主進程‘) ‘‘‘ 列印結果: MainThread <_MainThread(MainThread, started 140735268892672)> [<_MainThread(MainThread, started 140735268892672)>, <Thread(Thread-1, started 123145307557888)>] 主線程/主進程 Thread-1 ‘‘‘
View Code五 守護線程
from threading import Threadimport timedef sayhi(name): time.sleep(2) print(‘%s say hello‘ %name)if __name__ == ‘__main__‘: t=Thread(target=sayhi,args=(‘egon‘,)) t.setDaemon(True) #必須在t.start()之前設定 t.start() print(‘主線程‘) print(t.is_alive()) ‘‘‘ 主線程 True ‘‘‘
六 死結現象與遞迴鎖
所謂死結:是指兩個或以上的進程或線程在執行過程中,因爭奪資源而造成的一種互相等待現象,如無外力作用, 它們都將無法推進下去。此時稱系統處於死結狀態或系統產生了死結。
from threading import Thread,Lockimport timemutexA=Lock()mutexB=Lock()class MyThread(Thread): def run(self): self.func1() self.func2() def func1(self): mutexA.acquire() print(‘\033[41m%s 拿到A鎖\033[0m‘ %self.name) mutexB.acquire() print(‘\033[42m%s 拿到B鎖\033[0m‘ %self.name) mutexB.release() mutexA.release() def func2(self): mutexB.acquire() print(‘\033[43m%s 拿到B鎖\033[0m‘ %self.name) time.sleep(2) mutexA.acquire() print(‘\033[44m%s 拿到A鎖\033[0m‘ %self.name) mutexA.release() mutexB.release()if __name__ == ‘__main__‘: for i in range(10): t=MyThread() t.start()‘‘‘Thread-1 拿到A鎖Thread-1 拿到B鎖Thread-1 拿到B鎖Thread-2 拿到A鎖然後就卡住,死結了‘‘‘
死結
解決方案,遞迴鎖,在Python中為了支援在同一線程中的多此請求同一資源,Python提供了可重新進入鎖RLock。
七訊號量Semaphore
Semaphore管理一個內建的計數器,
每當調用acquire()時內建計數器-1;
調用release()時內建計數器+1;
計數器不能小於0;當計數器為 0時,acquire()將阻塞線程直到其他線程調用release()。
執行個體(同時只有5 個線程可以獲得Semaphore,即可以限制最大串連數為5)
from threading import Thread, Semaphore# Semaphore 訊號量import time, randomsm = Semaphore(5)def task(name): sm.acquire() print(‘%s 正在上廁所‘ % name) time.sleep(random.randint(1, 3)) sm.release() # 釋放鎖if __name__ == ‘__main__‘: for i in range(20): t1 = Thread(target=task, args=(‘路人%s‘ % i,)) t1.start()
訊號量八 Event
同進程一樣
線程的一個關鍵特性是每個線程都是獨立運行且狀態不可測。如果程式之中的其他線程需要通過判斷某個線程的狀態來確定自己下一步的操作,這時線程同步問題就會變得非常棘手。為瞭解決這個問題,我們需要使用threading庫中的Event對象。對象包含一個可由線程設定的訊號標誌,允許線程等待某些事件的發生。在初始狀態下Event中的訊號標誌被設定成假。一個線程如果將一個Event對象的訊號標誌設定為真,他將喚醒所有等待這個EEevent對象的線程。如果一個線程已經被設定為真的Event對象,那麼他將忽略這個事件,繼續執行
event.isSet():返回event的狀態值;event.wait():如果 event.isSet()==False將阻塞線程;event.set(): 設定event的狀態值為True,所有阻塞池的線程啟用進入就緒狀態, 等待作業系統調度;event.clear():恢複event的狀態值為False。
# 一個線程運行完,立刻通知下一個線程開始運行from threading import Thread, Eventimport timeevent = Event()def light(): print(‘紅燈正亮著‘) time.sleep(3) event.set() #綠燈亮def car(name): print(‘車輛%s 正在等綠燈‘ % name) event.wait() # 等燈變綠 print(‘車%s通行‘%name)if __name__ == ‘__main__‘: # 紅綠燈 t1 = Thread(target=light) t1.start() # 車 for i in range(10): t = Thread(target=car, args=(i,)) t.start()
Event
python並發編程之多線程