在上一章中,學習了Python多進程編程的一些基本方法:使用跨平台多進程模組multiprocessing提供的Process、Pool、Queue、Lock、Pipe等類,實現子進程創建、進程池(批量建立子進程並管理子進程數量上限)以及進程間通訊。這一章學習下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().name13 print 'the index is %d' % index14 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().name17 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().name21 #创建线程22 my_thread = threading.Thread(target = test, args=(1,) , name= 'zni_feng_thread')23 #等待2s24 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類別來為共享變數加鎖。
先看看使用多執行緒寫同一個共享變量,不加鎖的例子:
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 = 012 13 def add(self):14 for i in range(0,100000):15 self.balance += 116 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對程式進行加鎖:
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 = 012 13 def add(self, lock):14 #获得锁15 lock.acquire()16 for i in range(0,100000):17 self.balance += 118 #释放锁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]
【相關推薦】
2. Python中推薦使用多進程而不是多執行緒?分享推薦使用多進程的原因
以上是Python中多進程與多執行緒實例(二)程式設計方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!