python3之threading模塊(中)
阿新 • • 發佈:2019-01-26
區別 參數 wait dna 實例 線程的狀態 state 100% second
派生線程
簡單的示例
1: import threading
2: import logging
3:4: class Mythread(threading.Thread):
5: def run(self):
6: logging.debug("running")
7: logging.basicConfig(8: level=logging.DEBUG,9: format="(%(threadName)s) %(message)s"
10: )11: for i in range(5):12: t = Mythread()13: t.start()
結果
1: (Thread-1) running2: (Thread-2) running3: (Thread-3) running4: (Thread-4) running5: (Thread-5) running
如果要子類像父類(threading.Thread)那樣傳遞參數,需要重新定義構造函數
1: import threading
2: import logging
3:4: class Mythread(threading.Thread):
5:6: def __init__(self, group=None, target=None, name=None,7: args=(), kwargs=None, *, daemon=None):8: super().__init__(group=group, target=target, name=name,9: daemon=daemon)10: self.args = args11: self.kwargs = kwargs12:13: def run(self):
14: logging.debug("running with %s and %s" % (self.args, self.kwargs))15:16: logging.basicConfig(17: level=logging.DEBUG,18: format="(%(threadName)s) %(message)s",
19: )20: for i in range(5):21: t = Mythread(args=(i,), kwargs={"a": "A", "b": "B"})22: t.start()
結果:
1: (Thread-1) running with (0,) and {‘a‘: ‘A‘, ‘b‘: ‘B‘}2: (Thread-2) running with (1,) and {‘a‘: ‘A‘, ‘b‘: ‘B‘}3: (Thread-3) running with (2,) and {‘a‘: ‘A‘, ‘b‘: ‘B‘}4: (Thread-4) running with (3,) and {‘a‘: ‘A‘, ‘b‘: ‘B‘}5: (Thread-5) running with (4,) and {‘a‘: ‘A‘, ‘b‘: ‘B‘}
定時器線程
Timer在一個延遲後開始工作,而且可以被任意時刻被取消。
1: t = threading.Timer(float, target)2: # 設定線程名3: t.setName(“t1”)4: # 取消運行5: t.cancel()
線程之間同步操作
如果程序中的其他線程需要通過判斷某個線程的狀態來確定自己下一步的操作,時,事件(Event)對象是實現線程間安全通信的一種簡單的方法。
event.wait():如果event.is_set()==False將阻塞線程;
event.set(): 設置event的狀態值為True,所有阻塞池的線程激活進入就緒狀態, 等待操作系統調度;
event.clear():恢復event的狀態值為False。
event.is_set():當內部標誌為True返回True。與isSet()方法一樣。
下面是一個簡單的兩個線程的例子:
1: import logging
2: import threading
3: import time4: def wait_for_event(e):
5: """6: waiting for the event to be set before do anything7: :param e: Event對象的形參8: :return:
9: """10: logging.debug("waiting")
11: # 這個線程被阻塞了12: event_is_set = e.wait()13: # 如果事件沒有set就永遠不會執行14: logging.debug("event set:%s", event_is_set)
15:16: def wait_for_event_timeout(e, t):
17: """18: wait t seconds and then timeout19: :param e: Event對象的形參20: :param t: 等待事件的時間(seconds)21: :return:
22: """23: while not e.is_set():24: logging.debug("wait_for_event_timeout")
25: # 表示等待事件的時間為t26: event_is_set = e.wait(t)27: # 當事件set後或者時間超過t才會繼續執行28: logging.debug("event set:%s", event_is_set)
29: if event_is_set:
30: logging.debug("processing event")
31: else:
32: logging.debug("doing other work")
33: logging.basicConfig(34: level=logging.DEBUG,35: format="(%(threadName)-10s) %(message)s",
36: )37: # 實例化的Event對象38: e = threading.Event()39: t1 = threading.Thread(40: name="block",41: target=wait_for_event,42: args=(e,),43: )44: t1.start()
45: t2 = threading.Thread(46: name="noblock",47: target=wait_for_event_timeout,48: args=(e, 2)49: )50: t2.start()
51:52: logging.debug("waiting before calling Event.set()")
53: time.sleep(0.3)
54: # 啟動事件55: e.set()56: logging.debug("Event is set")
結果:
1: (block ) waiting2: (noblock ) wait_for_event_timeout3: (MainThread) waiting before calling Event.set()4: (MainThread) Event is set5: (block ) event set:True6: (noblock ) event set:True7: (noblock ) processing event
控制資源訪問
threading.LOCK() LocK鎖對象
threading.LOCK().acquire() 獲取底層鎖
threading.LOCK().release() 釋放底層鎖
註意python中GIL與LOCK的區別,這裏就不廢話了。
下面是一個兩個線程使用lock鎖的例子:
1: import logging
2: import random
3: import threading
4: import time5: class Counter:
6: def __init__(self, start=0):7: # 這是Counter的專用鎖對象8: self.lock = threading.Lock()9: self.value = start
10: def increment(self):
11: logging.debug("waiting for lock")
12: # 拿到lock鎖13: self.lock.acquire()14: try:15: # 無論誰拿到這個鎖,每顯示一次value就會加一16: logging.debug("acquired lock")
17: self.value = self.value + 118: finally:19: # 釋放lock鎖20: self.lock.release()21:22: def worker(c):
23: """24: make Counter().value + 225: :param c: Counter實例化對象26: :return:
27: """28: for i in range(2):29: pause = random.random()30: logging.debug("sleeping % 0.02f", pause)
31: time.sleep(pause)
32: c.increment()33: logging.debug("done")
34: logging.basicConfig(35: level=logging.DEBUG,36: format="(%(threadName)-10s %(message)s)"
37: )38: counter = Counter()39: for i in range(2):40: # 生成兩個線程41: t = threading.Thread(target=worker, args=(counter, ))42: t.start()
43: logging.debug("waiting for worker threads")
44: # 拿到當前python程序的主線程45: main_thread = threading.main_thread()46: 讓所有未執行完的其他線程等待。47: for t in threading.enumerate():48: if t is not main_thread:
49: t.join()
50: # 最後計算counter的value值51: logging.debug(("Counter:%d" % counter.value))
結果
1: (Thread-1 sleeping 0.43)2: (Thread-2 sleeping 0.84)3: (MainThread waiting for worker threads)4: (Thread-1 waiting for lock)5: (Thread-1 acquired lock)6: (Thread-1 sleeping 0.96)7: (Thread-2 waiting for lock)8: (Thread-2 acquired lock)9: (Thread-2 sleeping 0.24)10: (Thread-2 waiting for lock)11: (Thread-2 acquired lock)12: (Thread-2 done)13: (Thread-1 waiting for lock)14: (Thread-1 acquired lock)15: (Thread-1 done)16: (MainThread Counter:4)
在寫代碼中,應該避免死鎖或者競爭條件。所有種類的鎖還可以如下地寫,with語句自動控制鎖的獲取與釋放。
1: with lock_A:2: # 業務代碼3: statement
再入鎖
正常的Lock對象是不能請求多次的。同一個調用鏈中不同函數訪問同一個鎖的話,會產生副作用。
1: threading.RLock() 可以讓同一個線程的不同代碼“重新獲得”鎖
python3之threading模塊(中)