標籤:同步原語 __str__ append exit read start style rand name
當出現競態條件時候,即在同一個時刻只有一個線程可以進入臨界區,需要使用同步。
常見的同步原語有兩種:鎖/互斥,訊號量。
鎖是最簡單,最低級的機制。
首先看一個不使用鎖時候的多線程樣本:
from atexit import registerfrom time import sleep, ctimefrom threading import currentThread, Threadfrom random import randrangeclass cleanOutput(list): def __str__(self): return ‘,‘.join(self)loops = [randrange(2, 5) for x in range(randrange(3, 7))]remaining = cleanOutput()def loop(nsec): myname = currentThread().name remaining.append(myname) print(‘{0} starting at {1}‘.format(myname, ctime())) sleep(nsec) remaining.remove(myname) print(‘{0} end at {1}‘.format(myname, ctime())) print(‘remaining {0}‘.format(remaining))def main(): for i in loops: Thread(target=loop, args=(i,)).start()@registerdef _atexit(): print("end!")if __name__ == ‘__main__‘: main()
輸出結果1:
Thread-1 starting at Tue Dec 20 23:12:03 2016
Thread-2 starting at Tue Dec 20 23:12:03 2016
Thread-3 starting at Tue Dec 20 23:12:03 2016
Thread-4 starting at Tue Dec 20 23:12:03 2016
Thread-5 starting at Tue Dec 20 23:12:03 2016
Thread-6 starting at Tue Dec 20 23:12:03 2016
Thread-2 end at Tue Dec 20 23:12:05 2016
Thread-3 end at Tue Dec 20 23:12:05 2016
Thread-5 end at Tue Dec 20 23:12:05 2016
remaining Thread-1,Thread-4,Thread-6
remaining Thread-1,Thread-4,Thread-6
remaining Thread-1,Thread-4,Thread-6
Thread-1 end at Tue Dec 20 23:12:06 2016
remaining Thread-4,Thread-6
Thread-6 end at Tue Dec 20 23:12:06 2016
remaining Thread-4
Thread-4 end at Tue Dec 20 23:12:06 2016
remaining
end!
輸出結果2:
Thread-1 starting at Tue Dec 20 23:18:45 2016
Thread-2 starting at Tue Dec 20 23:18:45 2016
Thread-3 starting at Tue Dec 20 23:18:45 2016
Thread-4 starting at Tue Dec 20 23:18:45 2016
Thread-1 end at Tue Dec 20 23:18:47 2016
remaining Thread-2,Thread-3,Thread-4
Thread-3 end at Tue Dec 20 23:18:47 2016
Thread-2 end at Tue Dec 20 23:18:47 2016
remaining Thread-4
remaining Thread-4
Thread-4 end at Tue Dec 20 23:18:48 2016
remaining
end!
可以看到輸出的結果非常奇怪,當多個線程同時使用remaining列表時候,結果會出現意外。
當使用鎖時,即
1 from atexit import register 2 from time import sleep, ctime 3 from threading import currentThread, Thread, Lock 4 from random import randrange 5 6 7 class cleanOutput(list): 8 def __str__(self): 9 return ‘,‘.join(self)10 11 loops = [randrange(2, 5) for x in range(randrange(3, 7))]12 remaining = cleanOutput()13 lock = Lock()14 15 16 def loop(nsec):17 myname = currentThread().name18 with lock: #也可以使用lock.acquire()和lock.release()19 remaining.append(myname) 20 print(‘{0} starting at {1}‘.format(myname, ctime()))21 sleep(nsec)22 with lock:23 remaining.remove(myname)24 print(‘{0} end at {1}‘.format(myname, ctime()))25 print(‘remaining {0}‘.format(remaining))26 27 28 def main():29 for i in loops:30 Thread(target=loop, args=(i,)).start()31 32 33 @register34 def _atexit():35 print("end!")36 37 38 if __name__ == ‘__main__‘:39 main()
輸出結果為:
Thread-1 starting at Tue Dec 20 23:22:53 2016
Thread-2 starting at Tue Dec 20 23:22:53 2016
Thread-3 starting at Tue Dec 20 23:22:53 2016
Thread-4 starting at Tue Dec 20 23:22:53 2016
Thread-5 starting at Tue Dec 20 23:22:53 2016
Thread-6 starting at Tue Dec 20 23:22:53 2016
Thread-1 end at Tue Dec 20 23:22:55 2016
remaining Thread-2,Thread-3,Thread-4,Thread-5,Thread-6
Thread-4 end at Tue Dec 20 23:22:55 2016
remaining Thread-2,Thread-3,Thread-5,Thread-6
Thread-2 end at Tue Dec 20 23:22:55 2016
remaining Thread-3,Thread-5,Thread-6
Thread-5 end at Tue Dec 20 23:22:56 2016
remaining Thread-3,Thread-6
Thread-6 end at Tue Dec 20 23:22:57 2016
remaining Thread-3
Thread-3 end at Tue Dec 20 23:22:57 2016
remaining
end!
結果正常了
參考資料:Python核心編程.第四章.Wesley Chun著
【[email protected]】鎖樣本