在上一章中,學習了Python多進程編程的一些基本方法:使用跨平臺多進程模塊multiprocessing提供的Process、Pool、Queue、Lock、Pipe等類,實現子進程建立、進程池(批量建立子進程並管理子進程數量上限)以及進程間通訊。這一章學習下Python下的多線程編程方法。python
線程是操做系統執行任務的最小單元。Python標準庫中提供了threading模塊,對多線程編程提供了很便捷的支持。編程
下面是使用threading實現多線程的代碼:多線程
1 #!/usr/bin/python 2 # -*- coding: utf-8 -* 3 __author__ = 'zni.feng' 4 import sys 5 reload (sys) 6 sys.setdefaultencoding('utf-8') 7 8 import threading, time 9 10 def test(index): 11 print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) 12 print 'thread %s starts.' % threading.current_thread().name 13 print 'the index is %d' % index 14 time.sleep(3) 15 print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) 16 print 'thread %s ends.' % threading.current_thread().name 17 18 if __name__ == "__main__": 19 print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) 20 print 'thread %s starts.' % threading.current_thread().name 21 #建立線程 22 my_thread = threading.Thread(target = test, args=(1,) , name= 'zni_feng_thread') 23 #等待2s 24 time.sleep(2) 25 #啓動線程 26 my_thread.start() 27 #等待線程結束 28 my_thread.join() 29 print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) 30 print 'thread %s ends.' % threading.current_thread().name
輸出結果爲:函數
2017-01-12 22:06:32
thread MainThread starts.
2017-01-12 22:06:34
thread zni_feng_thread starts.
the index is 1
2017-01-12 22:06:37
thread zni_feng_thread ends.
2017-01-12 22:06:37
thread MainThread ends.
[Finished in 5.1s]
其中,threading模塊的current_thread()函數會返回當前線程的實例。學習
多進程與多線程的最大不一樣在於,多進程中,同一個變量,各自有一份拷貝存在於每一個進程中,互不影響。而多線程中,全部變量都由全部線程共享,因此,任何一個共享變量均可以被任何一個線程修改。所以線程之間共享數據最大的危險在於多個線程同時改變一個變量。爲了解決這個問題,咱們能夠藉助於threading模塊的Lock類給共享變量加鎖。ui
先看看使用多線程寫同一個共享變量,不加鎖的例子:spa
1 #!/usr/bin/python 2 # -*- coding: utf-8 -* 3 __author__ = 'zni.feng' 4 import sys 5 reload (sys) 6 sys.setdefaultencoding('utf-8') 7 import threading 8 9 class Account: 10 def __init__(self): 11 self.balance = 0 12 13 def add(self): 14 for i in range(0,100000): 15 self.balance += 1 16 17 def delete(self): 18 for i in range(0,100000): 19 self.balance -=1 20 21 if __name__ == "__main__": 22 account = Account() 23 #建立線程 24 thread_add = threading.Thread(target=account.add, name= 'Add') 25 thread_delete = threading.Thread(target=account.delete, name= 'Delete') 26 27 #啓動線程 28 thread_add.start() 29 thread_delete.start() 30 31 #等待線程結束 32 thread_add.join() 33 thread_delete.join() 34 35 print 'The final balance is: ' + str(account.balance)
運行結果爲:操作系統
The final balance is: -51713
[Finished in 0.1s]
能夠發現,每次運行,它的最終結果都會不一樣,並且都不是0。就是由於不一樣線程在同時修改同一個變量時,發生了衝突,某些中間變量沒有按順序被使用致使。線程
如今咱們使用Lock對程序進行加鎖:code
1 #!/usr/bin/python 2 # -*- coding: utf-8 -* 3 __author__ = 'zni.feng' 4 import sys 5 reload (sys) 6 sys.setdefaultencoding('utf-8') 7 import threading 8 9 class Account: 10 def __init__(self): 11 self.balance = 0 12 13 def add(self, lock): 14 #得到鎖 15 lock.acquire() 16 for i in range(0,100000): 17 self.balance += 1 18 #釋放鎖 19 lock.release() 20 21 def delete(self, lock): 22 #得到鎖 23 lock.acquire() 24 for i in range(0,100000): 25 self.balance -=1 26 #釋放鎖 27 lock.release() 28 29 30 if __name__ == "__main__": 31 account = Account() 32 lock = threading.Lock() 33 #建立線程 34 thread_add = threading.Thread(target=account.add, args=(lock, ), name= 'Add') 35 thread_delete = threading.Thread(target=account.delete, args=(lock, ), name= 'Delete') 36 37 #啓動線程 38 thread_add.start() 39 thread_delete.start() 40 41 #等待線程結束 42 thread_add.join() 43 thread_delete.join() 44 45 print 'The final balance is: ' + str(account.balance)
能夠發現,不管如何執行多少次,balance結果都爲0。若是將每次balance計算的結果都打印出來,還會發現,當一個線程開始執行時,另外一個線程必定會等到前一個線程執行完(準確地說是lock.release()執行完)後纔開始執行。
The final balance is: 0
[Finished in 0.1s]