python之 threading(多執行緒)模組

ckxllf發表於2020-05-04

  一、

  1.active_count() , activeConut()

  方法  功能

  active_count() , activeConut()  返回處於alive狀態的Thread物件數量

  用法:

  import time

  import threading

  def sing():

  print("---singing---")

  time.sleep(10)

  print(threading.active_count())

  輸出:2

  當前處於alive的Thread物件為:[<_MainThread(MainThread, started 9104)>, ]

  下面給他新增執行緒物件:

  import time

  import threading

  def sing():

  print("---singing---")

  time.sleep(10)#這裡需要讓執行緒休息10秒,不然一瞬間就完成了,然後執行緒結束

  t_1 = threading.Thread(target = sing)

  #Thread是threading中比較重要的一個類。下面有介紹。

  t_1.start()

  t_2 = threading.Thread(target = sing)

  t_2.start()

  t_3 = threading.Thread(target = sing)

  t_3.start()

  print(threading.active_count())

  #這裡也可以寫成

  #print(threading.activeCount())

  activeCount()輸出為:5

  這5個物件為:

  [<_MainThread(MainThread, started 16276)>, , , , ]

  2.current_thread() , currentThread()

  current_thread() , currentThread()  返回當前的Thread物件

  import time

  import threading

  def sing():

  print("---singing---")

  time.sleep(10)

  t_1 = threading.Thread(target = sing)

  t_1.start()

  print(threading.current_thread())

  print(threading.currentThread())

  輸出:

  ---singing---

  <_MainThread(MainThread, started 6880)>

  <_MainThread(MainThread, started 6880)>

  3. get_ident()

  get_ident()  返回當前執行緒的執行緒識別符號。執行緒識別符號是一個非負整數,並無特殊函式,只是用來標識執行緒,該整數可能會被迴圈利用。python3.3及以後版本支援該方法

  import time

  import threading

  def sing():

  print('執行緒t_1',threading.get_ident())

  time.sleep(10)

  print('主執行緒',threading.get_ident())

  import time

  import threading

  def sing():

  print('執行緒t_1',threading.get_ident())

  time.sleep(10)

  t_1 = threading.Thread(target=sing)

  t_1.start()

  4.enumerate()

  enumerate()  返回當前處於alive狀態的所有Thread物件列表

  4.1

  import time

  import threading

  def sing():

  time.sleep(10)

  t_1 = threading.Thread(target = sing)

  t_1.start()

  t_2 = threading.Thread(target = sing)

  t_2.start()

  t_3 = threading.Thread(target = sing)

  t_3.start()

  print(threading.enumerate())

  輸出:

  [<_MainThread(MainThread, started 19200)>, , , , ]

  列表後3個分別對應a_1,a_2,a_3 這三個子執行緒

  前兩個對應主執行緒。

  4.2

  import time

  import threading

  def sing():

  time.sleep(10)

  t_1 = threading.Thread(target = sing)

  t_1.start()

  t_2 = threading.Thread(target = sing)

  t_2.start()

  print(threading.enumerate())

  輸出:

  [<_MainThread(MainThread, started 2372)>, , , ]

  4.3

  import time

  import threading

  def sing():

  time.sleep(10)

  print(threading.enumerate())

  輸出:

  [<_MainThread(MainThread, started 20176)>, ]

  5.stack_size()

  stack_size([size])  返回建立執行緒時使用的棧的大小,如果指定size引數,則用來指定後續建立的執行緒使用的棧大小,size必須是0(表示使用系統預設值)或大於32K的正整數。

  import threading

  print(threading.stack_size())#輸出當前執行緒棧的大小

  threading.stack_size(43*1024)#設定下一個執行緒棧的大小43*1024=44032

  print(threading.stack_size())

  輸出

  0

  44032

  6.main_threade()

  main_thread()  返回主執行緒物件,即啟動python直譯器的執行緒物件。python3.4及以後版本支援該方法

  import time

  import threading

  def sing():

  time.sleep(10)

  print(threading.enumerate())

  print(threading.main_thread())

  輸出:

  [<_MainThread(MainThread, started 15304)>, ]

  <_MainThread(MainThread, started 15304)>

  二、

  Thread 物件

  threading.Thread  執行緒類,用於建立和管理執行緒

  Thread是threading中比較重要的一個類。

  可以透過Thread類的建構函式傳遞一個可呼叫物件來建立執行緒

  可以繼承threading.Thread類建立派生類,並重寫__init__和run方法,實現自定義執行緒物件類。

  1.threading.Thread的start()

  start()  自動呼叫 run 方法,啟動執行緒,執行執行緒程式碼

  import time

  import threading

  def sing(i):

  print('執行緒',i)

  time.sleep(10)

  t_1 = threading.Thread(target=sing,name = 't_1',args='1')

  t_1.start()#啟動t_1執行緒

  #輸出為執行緒1

  #還可以這樣寫

  threading.Thread(target=sing,name = 't_2',args=(2,)).start()

  #輸出為執行緒2

  輸出:

  執行緒1

  執行緒2

  2.threading.Thread的run()

  run()  執行緒程式碼,用來實現執行緒的功能與業務邏輯,可以在子類中重寫該方法來自定義執行緒的行為

  下面建立執行緒類。

  import time

  import threading

  class mythread(threading.Thread):#threading.Thread(基類)

  def __init__(self,numble):

  threading.Thread.__init__(self)

  #這裡有個規律(我也不太懂,就是總結一下)為什麼用threading.Thread.__init__(self)而不用super.__init__.(self)呢,因為class myThread(threading.Thread):

  #有個括號,括號裡面是threading.Thread,可以多找幾個例子,不帶括號的用super().__init__.()

  #super(myThread,self).__init__()這樣寫也對

  self.numble = numble

  def run(self):

  print(self.numble)

  if __name__ == '__main__':

  t_1 = mythread('執行緒t_1')#建立執行緒

  t_1.start()#啟動執行緒

  輸出:執行緒t_1

  還可以這樣做:

  import time

  import threading

  def mythread(numble):

  print(t_1.getName())#也可以在這裡輸出,因為t_1這個物件已經被傳入。不懂再複習一下前面的學的

  print(numble)

  if __name__ == '__main__':

  t_1 = threading.Thread(target=mythread,name='t_1執行緒',args=(1,))#target對應函式,name對應執行緒名字,args對應傳入的資料

  t_1.start()

  print(t_1.getName())

  如果輸出亂的話可以再命令提示符裡面執行。

  2.threading.Thread的join()

  join()  join([timeour]) :阻塞當前執行緒,等待被調執行緒結束或超時後再繼續執行當前執行緒的後續程式碼,引數 timeout 用來指定最長等待時間,單位為秒。

  import time

  import threading

  def mythread(numble):

  for i in range(numble):

  print(i)

  time.sleep(10)

  if __name__ == '__main__':

  t_1 = threading.Thread(target=mythread,args=(4,))

  t_1.start()

  t_1.join(3)#只等3秒mythread函式有一行程式碼time.sleep(10),但是我們加了一個t_1.join(3)

  #不管他休息幾秒,join裡面是3秒,3秒內沒執行完也不會等了,

  #可以數一下時間看看是不是3秒後執行t_2執行緒。

  t_2 = threading.Thread(target=mythread,args=(5,))

  t_2.start()

  t_2.join()

  輸出:

  0

  1

  2

  3

  0

  1

  2

  3

  4

  3.threading.Thread的is_alive() , is_Alive()

  is_alive() , is_Alive()  測試執行緒是否處於 alive 狀態

  import time

  import threading

  def mythread(numble):

  for i in range(numble):

  pass

  #print(i)

  time.sleep(10)

  if __name__ == '__main__':

  t_1 = threading.Thread(target=mythread,args=(4,))

  t_1.start()

  t_1.join(3)

  t_2 = threading.Thread(target=mythread,args=(5,))

  t_2.start()

  t_2.join()

  print(t_1.isAlive())

  print(t_2.isAlive())

  輸出:

  False

  False

  為什麼輸出了兩個False呢?

  分析一下:

  t_1.join(3),t_1執行3秒後開始執行t_2,但是此時t_1還是alive狀態,

  t_1在還剩7秒的時候,開始執行t_2,t_2可以執行10秒,在這10秒執行的同時

  t_1的7秒已經執行完了。

  import time

  import threading

  def mythread(numble):

  for i in range(numble):

  pass

  #print(i)

  time.sleep(10)

  if __name__ == '__main__':

  t_1 = threading.Thread(target=mythread,args=(4,))

  t_1.start()

  t_1.join(3)

  t_2 = threading.Thread(target=mythread,args=(5,))

  t_2.start()

  t_2.join(1)

  print(t_1.isAlive())

  print(t_2.isAlive())

  輸出:

  True

  True

  分析:

  t_1.join(3),t_1執行3秒後開始執行t_2,t_1還剩7秒

  沒有執行完,然後t_2開始,因為加了個t_2.join(1),

  t_2執行了一秒,此時t_2還剩9秒,t_1還剩6秒,

  所以t_1與t_2都是alive狀態。

  如果加一行程式碼:

  import time

  import threading

  def mythread(numble):

  for i in range(numble):

  pass

  #print(i)

  time.sleep(10)

  if __name__ == '__main__':

  t_1 = threading.Thread(target=mythread,args=(4,))

  t_1.start()

  t_1.join(3)

  t_2 = threading.Thread(target=mythread,args=(5,))

  t_2.start()

  t_2.join(1)

  print(t_1.isAlive())

  time.sleep(10)

  print(t_2.isAlive())

  輸出:

  True

  False

  分析:

  因為time.sleep(10),主程式阻塞了10秒,在阻塞之前t_1已經輸出,

  但是t_2還沒有,t_2帶著它僅剩的9秒時間等了10秒,早就結束了,

  所以t_2不是alive狀態。

  4.threading.Thread的daemon

  daemon  在指令碼執行過程中有一個主執行緒,若在主執行緒中建立了子執行緒,當主執行緒結束時根據子執行緒 daemon 屬性值的不同可能會發生下面的兩種情況之一:當某子執行緒的 daemon 屬性為 Fasle 時,主執行緒結束時會檢測該子執行緒是否結束,如果該子執行緒尚未完成,則主執行緒會等待它完成後再退出。當某子執行緒的 daemon 屬性為 True時,主執行緒執行結束時不對該子執行緒進行檢查而直接退出,同時所有 daemon 值為 True 的子執行緒將隨主執行緒一起結束,而不論是否執行完成。daemon 屬性的值預設為 False ,如果需要修改,則必須在呼叫 start() 方法啟動執行緒之前修改。以上論述不適用於 IDLE 環境中的互動模式或指令碼執行模式,因為在該環境中的主執行緒只有在退出 python IDLE 時才終止。

  import time

  import threading

  class mythread(threading.Thread):#threading.Thread(基類)

  def __init__(self,numble):

  threading.Thread.__init__(self)

  #這裡有個規律(我也不太懂,就是總結一下)為什麼用threading.Thread.__init__(self)而不用super.__init__.(self)呢,因為class myThread(threading.Thread):

  #有個括號,括號裡面是threading.Thread,可以多找幾個例子,不帶括號的用super().__init__.()

  #super(myThread,self).__init__()這樣寫也對

  self.numble = numble

  def run(self):

  time.sleep(self.numble)

  print(self.numble)

  if __name__ == '__main__':

  t_1 = mythread(3)#建立執行緒t_1

  t_2 = mythread(4)#建立執行緒t_2

  print(t_1.daemon)

  print(t_2.daemon)

  t_2.daemon = True

  print(t_1.daemon)

  print(t_2.daemon)

  t_1.start()#啟動執行緒t_1

  t_2.start()#啟動執行緒t_2

  需要在命令提示符裡面執行daemon才起作用。

  輸出:

  False

  False

  False

  True

  3

  分析:

  主函式在執行到t_2.start()時,就結束了。因為t_1的daemon為False,所以主函式

  等待t_1執行結束,輸出了3;

  因為t_2的daemon為True,所以主函式不會等它,於是t_2就沒有輸出了。

  三、Lock與RLock物件

  1.Lock

  Lock  Lock是 比較低階的同步原語,當被鎖定以後不屬於特定的執行緒。一個鎖有兩種狀態: locked和unlocked。 如果鎖處於unclocked狀態,acquire(方 法將其修改為locked並立即返回;如果鎖已處於locked狀態,則阻塞當前執行緒並等待其他執行緒釋放鎖然後將其修改為locked並立即返回,或等待一定的時間後返回但不修改鎖的狀態。release()方法將鎖狀態由locked修改為unlocked並立即返回,如果鎖狀態本來已經是unlocked,呼叫該方法將會丟擲異常。

  import time

  import threading

  class mythread(threading.Thread):

  def __init__(self):

  threading.Thread.__init__(self)

  def run(self):

  global x

  lock.acquire()

  for i in range(3):

  x = x + i

  time.sleep(2)

  print(x)

  lock.release()

  lock = threading.Lock()#建立鎖#也可以寫為lock = threading.RLock()

  t_1 = []

  for i in range(10):

  t = mythread()

  t_1.append(t)

  x = 0

  for i in t_1:

  i.start()

  輸出:

  3

  6

  9

  12

  15

  18

  21

  24

  27

  30

  分析:

  明明建立了10個程式,如果不加鎖,這10個程式誰先進入cpu,誰就先執行,

  輸出就是雜亂無章的

  但事實上我們加了鎖,當第一個程式啟動並執行到lock.acquire()時,他就獲得了鎖,

  那麼其他程式執行到lock.acquire()時,如果第一個獲得鎖的程式還沒有執行

  lock.release()把鎖釋放,那麼,這些程式就會堵在這,直到第一個獲得鎖的程式

  執行了lock.release(),其他程式就開始搶奪這一把鎖,誰搶到,誰執行lock.acquire()

  下面的程式碼。

  2.RLock

  RLock  RLock與Lock的主要區別:在同一執行緒內,對RLock進行多次acquire()操作,程式不會阻塞。也就是說,在一個執行緒內,可以執行多個lock.acquire(),同樣當我們想要解除阻塞的時候需要執行同樣個數的lock.release()才可以。

  加一把鎖

  import time

  import threading

  class mythread(threading.Thread):

  def __init__(self):

  threading.Thread.__init__(self)

  def run(self):

  global x

  lock.acquire()

  for i in range(3):

  x = x + i

  time.sleep(2)

  print(x)

  lock.release()

  lock = threading.RLock()

  t_1 = []

  for i in range(10):

  t = mythread()

  t_1.append(t)

  x = 0

  for i in t_1:

  i.start()

  i.join()

  輸出:

  3

  6

  9

  12

  15

  18

  21

  24

  27

  30

  加兩把鎖

  import time

  import threading

  class mythread(threading.Thread):

  def __init__(self):

  threading.Thread.__init__(self)

  def run(self):

  global x

  lock.acquire()

  lock.acquire()

  for i in range(3):

  x = x + i

  time.sleep(2)

  print(x)

  lock.release()

  lock.release()

  lock = threading.RLock()

  t_1 = []

  for i in range(10):

  t = mythread()

  t_1.append(t)

  x = 0

  for i in t_1:

  i.start()

  i.join()

  輸出:

  3

  6

  9

  12

  15

  18

  21

  24

  27

  30

  在使用鎖的同時,要避免死鎖,

  簡單敘述一下:

  就是在執行多個執行緒的時候,每個執行緒都需要獲取兩把鎖才可以執行,但是因為

  程式碼邏輯問題,導致甲執行緒獲得了鎖一,卻沒有獲得鎖二,

  而乙程式獲得了鎖二,卻沒有獲得鎖一,導致兩個執行緒都無法執行,

  這就是死鎖。

  四、Condition

  Condition  使用Condition物件可以在某些事件觸發後才處理資料或執行特定的功能程式碼,可以用於不同執行緒之間的通訊或通知,以實現更高階別的同步。在內部實現上,Condition物件總是與某種鎖物件相關聯。Condition物件支援 上下文管理語句with。Condition對 象除了具有acquire()和release()方法之外,還有wait()、wait_ for()、 notify()、 notify all()等 方法。

  wait()  wait(timeout=None)方法 會釋放鎖,並阻塞當前執行緒直到超時或其他執行緒針對同一個Condition物件呼叫了notify(),notify_ all()方法, 被喚醒之後當前執行緒會重新嘗試獲取鎖並在成功獲取鎖之後結束wait()方法,然後繼續執行。

  wait_for()  wait_for(predicate, timeout=None)方法阻塞當前執行緒直到超時或者指定條件得到滿足

  notify  notify(n=1)喚醒等待該Condition物件的一個或多個執行緒,該方法並不負責釋放鎖.

  notify_all()  notify_all()方 法會喚醒等待該Condition物件的所有執行緒。

  import threading

  import time

  condition = threading.Condition()

  def a_1():

  print('已經進入a_1')

  condition.acquire()

  print('a_1獲得了')

  print('我這就去告訴a_2,並把condiion交給a_2')

  condition.wait()#把鎖釋放掉,阻塞當前執行緒。

  print('a_2終於把condition還給我了。')

  condition.release()

  print('a_1release')

  def a_2():

  time.sleep(1)

  print('好的我知道了,謝謝你的幫助。')

  print('已經進入a_2')

  condition.acquire()

  print('a_2獲得了')

  print('我也獲得了,condition就還給你吧。')

  condition.notify(1)#喚醒此時一個正在等待的執行緒

  condition.wait()

  print('a_2終於出來了')

  condition.release()

  print('a_2release')

  def a_3():

  b_1 = threading.Thread(target=a_1)

  b_2 = threading.Thread(target=a_2)

  b_1.start()

  b_2.start()

  b_1.join()

  b_2.join()

  if __name__ == '__main__':

  a_3()

  已經進入a_1

  a_1獲得了

  我這就去告訴a_2,並把condiion交給a_2

  好的我知道了,謝謝你的幫助。

  已經進入a_2

  a_2獲得了

  我也獲得了,condition就還給你吧。

  a_2終於把condition還給我了。

  a_1release

  分析:

  剛開始b_1,b_2進入了各自的函式,開始執行,但是b_2睡了1秒,

  導致b_2執行進度比b_1慢,在b_2睡覺的時候b_1已經執行到了condition.wait(),

  b_1就把鎖釋放掉,阻塞當前執行緒。以上就是b_1趁著b_2睡覺時間乾的事。

  b_2睡醒後開始執行condition.notify(1),喚醒此時一個正在等待的執行緒,

  此時正在等待的只有b_1,所以b_1被喚醒,(如果condition.notify(0)這樣寫,

  將喚醒0個執行緒),b_1被喚醒後,開始執行a_1中condition.wait()下面的程式碼,

  並偷偷地釋放了condition,執行結束。可憐的b_2還在傻傻等著b_1喚醒自己。

  修改一下:

  import threading

  import time

  condition = threading.Condition()

  def a_1():

  print('已經進入a_1')

  condition.acquire()

  print('a_1獲得了')

  print('我這就去告訴a_2,並把condiion交給a_2')

  condition.wait()#把鎖釋放掉,阻塞當前執行緒。

  print('a_2終於把condition還給我了。')

  condition.notify()

  condition.release()

  print('a_1release')

  def a_2():

  time.sleep(1)

  print('好的我知道了,謝謝你的幫助。')

  print('已經進入a_2')

  condition.acquire()

  print('a_2獲得了')

  print('我也獲得了,condition就還給你吧。')

  condition.notify(1)#喚醒此時一個正在等待的執行緒

  condition.wait()

  print('我就知道你不會把我忘了的。')

  condition.release()

  print('a_2release')

  def a_3():

  b_1 = threading.Thread(target=a_1)

  b_2 = threading.Thread(target=a_2)

  b_1.start()

  b_2.start()

  b_1.join()

  b_2.join()

  if __name__ == '__main__':

  a_3()

  print('結束')

  已經進入a_1

  a_1獲得了

  我這就去告訴a_2,並把condiion交給a_2

  好的我知道了,謝謝你的幫助。

  已經進入a_2

  a_2獲得了

  我也獲得了,condition就還給你吧。

  a_2終於把condition還給我了。

  a_1release

  我就知道你不會把我忘了的。

  a_2release

  結束

  五、Queue物件

  Queue  Queue物件主要實現了put()和get()方法,分別用來往佇列尾部追加元素和在佇列頭部獲取並刪除元素。put(item, block=True, timeout=None) get(block=True, timeout=None)

  import threading

  import time

  import queue

  myqueue = queue.Queue()

  def a_1():

  global myqueue

  for i in range(4):

  myqueue.get()

  print('佇列中剩餘元素個數',myqueue.qsize())

  def a_2():

  global myqueue

  for i in range(4):

  myqueue.put(i)#放入

  print(i)

  print('佇列中剩餘元素個數',myqueue.qsize())

  b_2 = threading.Thread(target=a_2)

  b_1 = threading.Thread(target=a_1)

  b_2.start()

  b_2.join()

  b_1.start()

  b_1.join()

  輸出:

  0

  1

  2

  3

  佇列中剩餘元素個數 4

  佇列中剩餘元素個數 0

  推薦個佇列講解的連結點選進入

  六、Event物件

  Event  Event物件的set()方法可以設定Event物件內部的訊號標誌為真;Event物件的clear()方法可以清除Event物件內部的訊號標誌,將其設定為假; .Event物件的isSet()方法用來判斷其內部訊號標誌的狀態;Event物件的wait()方法只有在其內部訊號狀態為真時將很快地執行並返回;若Event物件的內部訊號標誌為假,wait方法將一直等待至超時或內部訊號狀態為真。

  1.

  import threading

  myevent = threading.Event()

  print(myevent.isSet())#輸出為False,可知預設為False。

  myevent.set()

  print(myevent.isSet())

  myevent.clear()

  print(myevent.isSet())

  輸出:

  False

  True

  False

  分析:

  第一個False為預設情況。

  set之後,在輸出iSset,為True,表示Event物件內部的訊號標誌為真

  clear之後,為False,清除Event物件內部的訊號標誌,此時訊號標準為假

  2.

  import threading

  myevent = threading.Event()

  myevent.set()

  myevent.set()

  myevent.set()

  myevent.set()

  myevent.clear()

  print(myevent.isSet())

  輸出:

  False

  分析:

  不管set了幾次,clear一次,全部玩完。

  import threading

  import time

  myevent = threading.Event()

  def a_1(numble):

  if myevent.isSet():

  print('大門已經開啟,請迅速進入。')

  else:

  print('大門已經關閉了。請等待!')

  print('學生{}正在等待'.format(numble))

  time.sleep(1)

  myevent.wait()

  print('學生{}已經進入了教室'.format(numble))

  def a_2():

  print(b_3.getName(),'來了,他掏出了鑰匙,開啟了門。')

  print('門開啟了。')

  print('班長等待學生全部進入教室。')

  myevent.set()

  time.sleep(3)

  print('班長進入了教室。')

  if __name__ == '__main__':

  myevent.clear()

  b_1 = threading.Thread(target=a_1,args=(1,))

  b_2 = threading.Thread(target=a_1,args=(2,))

  b_3 = threading.Thread(target=a_2,name='班長')

  b_1.start()

  b_2.start()

  time.sleep(3)

  b_3.start()

  time.sleep(6)

  #這裡睡了6秒,就是為了讓班長進入教室的時間比老師早,不然班長還沒進教室,老師就已經進了。

  print('老師來了,開始上課。')

  輸出:

  大門已經關閉了。請等待!

  大門已經關閉了。請等待!

  學生1正在等待

  學生2正在等待

  班長 來了,他掏出了鑰匙,開啟了門。

  門開啟了。

  班長等待學生全部進入教室。

  學生1已經進入了教室

  學生2已經進入了教室

  班長進入了教室。

  老師來了,開始上課。

  七、Semaphore與BoundedSemaphore

  Semaphore與BoundedSemaphore  Semaphore物件維護著-一個內部計數器,呼叫acquire()方法時該計數器減1,呼叫release()方法時該計數器加1,適用於需要控制特定資源的併發訪問執行緒數量的場合。呼叫acquire()方法時, 如果計數器已經為0則阻塞當前執行緒,直到有其他執行緒呼叫了release()方法,所以計數器的值永遠不會小於0。Semaphore物件可以呼叫任意次release()方法,而BoundedSemaphore物件可以保證計數器的值不超過特定的值。

  1.Semaphore 鄭州婦科檢查哪家好

  Semaphore  threading.Semaphore([value]) values是一個內部計數,values預設是1,如果小於0,則會丟擲 ValueError 異常,可以用於控制執行緒數併發數

  import threading

  import time

  S = threading.Semaphore(5) #可以同時啟動5個執行緒

  def a_1(numble):

  S.acquire()#阻塞式請求獲得執行緒(訊號量減1)

  time.sleep(1)

  print(numble,time.time())#輸出牌號與時間戳

  S.release()#釋放資源(訊號量加1)

  def b_1():

  threads = list()

  for i in range(10):#準備啟動10個執行緒

  threads.append(threading.Thread(target=a_1, args=(i,)))

  threads[-1].start()

  for t in threads:

  t.join()

  print('所有執行緒工作結束')

  if __name__ == '__main__':

  b_1()

  輸出:

  0 1588401833.5383408

  3 1588401833.539341

  2 1588401833.539341

  4 1588401833.539341

  1 1588401833.539341

  5 1588401834.5388339

  9 1588401834.5398383

  8 1588401834.5398383

  7 1588401834.5398383

  6 1588401834.5398383

  所有執行緒工作結束

  由上面的時間戳可以看出基本上一次性啟動5個執行緒

  2.BoundedSemaphore

  import threading

  import time

  def a_1(numble):

  Boun.acquire()

  time.sleep(1)

  print('執行緒',numble,time.time())

  Boun.release()

  Boun = threading.BoundedSemaphore(2)

  for i in range(10):

  b_1 = threading.Thread(target=a_1,args=(i,))

  b_1.start()

  輸出:

  執行緒 0 1588402326.64822

  執行緒 1 1588402326.64822

  執行緒 2 1588402327.6486

  執行緒 3 1588402327.6495996

  執行緒 4 1588402328.648927

  執行緒 5 1588402328.6499276

  執行緒 6 1588402329.649535

  執行緒 7 1588402329.6505356

  執行緒 8 1588402330.649914

  執行緒 9 1588402330.6509147

  每一秒啟動兩個執行緒。

  3.Semaphore與BoundSemaphore的區別

  import threading

  Boun = threading.BoundedSemaphore(2)

  #Boun.acquire()

  Boun.release()

  這樣做會報錯。

  再看看Semaphore

  import threading

  Boun = threading.Semaphore(2)

  #Boun.acquire()

  Boun.release()

  Boun.release()

  Boun.release()

  Boun.release()

  Boun.release()

  Boun.release()

  沒有報錯。

  可以發現,普通訊號量可以被無數次的釋放。

  有限制的訊號量,在沒有被acquire前不可以被釋放。

  八、Barrier

  Barrier  Barrier物件常用來實現這樣的執行緒同步,多個執行緒執行到某個時間點以後每個執行緒都需要等著其他執行緒準備好以後,再同時進行下-步工作。

  wait()  Barrier對 象最常用的方法是wait()。執行緒呼叫該方法後會阻塞,當所有執行緒都呼叫了該方法後,會被同時釋放並繼續執行後面的程式碼。Barrier對 象的wait()方法會返回-一個 介於0到parties-1之間的整數,每個執行緒都會得到一個不同的整數。

  import threading

  import time

  import random

  def a_1(numble):

  times=random.randint(1,9)

  time.sleep(times)

  num=Bar.wait(10)#因為下面threading.Barrier(parties=3,action=a_2,timeout=10)中timeout=10,所以

  #如果wait()裡面不寫數的話,就預設等待10秒。

  print('wait返回值{} 執行緒引數{} 隨機等待時間{}'.format(num,numble,times))

  def a_2():

  print('已經進入等待')

  Bar = threading.Barrier(parties=4,action=a_2,timeout=10)

  #parties最多啟動的執行緒,action wait()全部執行緒都進入等待後執行的函式,timeout 預設等待的時間(可修改)

  b_1 = threading.Thread(target=a_1,args=(1,))

  b_2 = threading.Thread(target=a_1,args=(2,))

  b_3 = threading.Thread(target=a_1,args=(3,))

  b_4 = threading.Thread(target=a_1,args=(4,))

  b_1.start()

  b_2.start()

  b_3.start()

  b_4.start()

  輸出:

  已經進入等待

  wait返回值3 執行緒引數1 隨機等待時間7

  wait返回值0 執行緒引數2 隨機等待時間2

  wait返回值1 執行緒引數4 隨機等待時間3

  wait返回值2 執行緒引數3 隨機等待時間3


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2689848/,如需轉載,請註明出處,否則將追究法律責任。

相關文章