python3之threading模塊(上)


threading模塊提供了管理多個線程執行的API。

最簡單的用法。就是用一個目標函數實例化一個Thread對象。start()開始工作,join()等待當前線程完成。

  1: import threading
  2: def work():
  3:     print("working")
  4: for i in range(5):
  5:     t = threading.Thread(target=work)
  6:     t.start()
  7:     print("please wait!")
  8:     t.join()

結果

  1: working
  2: please wait!
  3: working
  4: please wait!
  5: working
  6: please wait!
  7: working
  8: please wait!
  9: working
 10: please wait!

當然也可以傳遞參數。

  1: import threading
  2: def work(i):
  3:     print("%i is working" %i)
  4: for i in range(5):
  5:     t = threading.Thread(target=work,args=(i,))
  6:     t.start()
  7:     print("please wait!")
  8:     t.join()

結果

  1: 0 is working
  2: please wait!
  3: 1 is working
  4: please wait!
  5: 2 is working
  6: please wait!
  7: 3 is working
  8: please wait!
  9: 4 is working
 10: please wait!

確定當前線程

每個Thread實例都有一個帶有默認值的名字,也可以傳入name參數更改。

  1: import threading
  2: import time
  3: def work():
  4:     print(threading.current_thread().getName(),"starting!")
  5:     time.sleep(0.5)
  6:     print(threading.current_thread().getName(),"end!")
  7: 
  8: t = threading.Thread(name="worker", target=work)
  9: t.start()
 10: print("please wait!")
 11: t.join()

結果

  1: worker starting!
  2: please wait!
  3: worker end!

出於線程安全的考慮,我們下面用logging模塊輸出消息。

守護線程與非守護線程

一般來說,程序都會等待所有線程完成工作之后才退出。而守護線程可以一直運行而不阻塞主程序的退出。傳入daemon=True或者調用setDaemon()方法並提供參數True來構造守護線程。

  1: import threading
  2: import time
  3: import logging
  4: def daemon():
  5:     logging.debug("start")
  6:     time.sleep(0.5)
  7:     logging.debug("exite")
  8: def non_deamon():
  9:     logging.debug("start")
 10:     logging.debug("exit")
 11: logging.basicConfig(
 12:     level=logging.DEBUG,
 13:     format='(%(threadName)-10s) %(message)s',
 14: )
 15: d = threading.Thread(name='deamon', target=daemon, daemon=True)
 16: t = threading.Thread(name="non-deamon", target=non_deamon)
 17: d.start()
 18: t.start()

結果中沒有看到守護線程的退出的消息,主程序就已經退出了。

  1: (deamon    ) start
  2: (non-deamon) start
  3: (non-deamon) exit

要等待一個守護線程結束,需要使用join()方法。默認下,join會無限阻塞,但可以傳入浮點值。在時間內線程即使未完成,join也會強制返回。

  1: import threading
  2: import time
  3: import logging
  4: def daemon():
  5:     logging.debug("start")
  6:     time.sleep(0.5)
  7:     logging.debug("exite")
  8: def non_deamon():
  9:     logging.debug("start")
 10:     logging.debug("exit")
 11: logging.basicConfig(
 12:     level=logging.DEBUG,
 13:     format='(%(threadName)-10s) %(message)s',
 14: )
 15: d = threading.Thread(name='deamon', target=daemon, daemon=True)
 16: t = threading.Thread(name="non-deamon", target=non_deamon)
 17: d.start()
 18: d.join(0.2)
 19: t.start()

結果還是沒有看到守護線程的結束退出的消息。

  1: (deamon    ) start
  2: (non-deamon) start
  3: (non-deamon) exit

枚舉所有線程

threading.enumerate()會返回一個Thread實例的一個列表。由於等待當前主程序終止會引入一種死鎖的情況,所以跳過這個線程等待。注意根據電腦配置,合理調節線程睡眠時間,否則會由於缺少logging參數而報錯。

  1: import threading
  2: import time
  3: import logging
  4: import random
  5: def worker():
  6:     pause = random.randint(1, 5) / 2
  7:     logging.debug("sleeping %0.2f" % pause)
  8:     time.sleep(pause)
  9:     logging.debug("end!")
 10: logging.basicConfig(
 11:     level=logging.DEBUG,
 12:     format='(%(threadName)-10s) %(message)s',
 13: )
 14: for i in range(3):
 15:     t = threading.Thread(target=worker, daemon=True)
 16:     t.start()
 17: # 拿到當前主線程
 18: main_thread = threading.main_thread()
 19: for t in threading.enumerate():
 20:     if t is main_thread:
 21:         continue
 22:     logging.debug("joining %s" % t.getName())
 23:     t.join()
上述程序各個線程執行的順序 image

輸出順序可能不一樣,

  1: (Thread-1  ) sleeping 0.50
  2: (Thread-2  ) sleeping 1.50
  3: (Thread-3  ) sleeping 2.00
  4: (MainThread) joining Thread-1
  5: (Thread-1  ) end!
  6: (MainThread) joining Thread-2
  7: (Thread-2  ) end!
  8: (MainThread) joining Thread-3
  9: (Thread-3  ) end!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM