Python多線程編程之threading模塊詳解
一、介紹
線程是什么?線程有啥用?線程和進(jìn)程的區(qū)別是什么?
線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。被包含在進(jìn)程中,是進(jìn)程中的實際運(yùn)作單位。一條線程指的是進(jìn)程中一個單一順序的控制流,一個進(jìn)程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務(wù)。
二、Python如何創(chuàng)建線程
2.1 方法一:
創(chuàng)建Thread對象
步驟:
1.目標(biāo)函數(shù)
2.實例化Thread對象
3.調(diào)用start()方法
import threading # 目標(biāo)函數(shù)1 def fun1(num): for i in range(num): print('線程1: 第%d次循環(huán):' % i) # 目標(biāo)函數(shù)2 def fun2(lst): for ele in lst: print('線程2: lst列表中元素 %d' % ele) def main(): num = 10 # 實例化Thread對象 # target參數(shù)一定為一個函數(shù),且不帶括號 # args參數(shù)為元組類型,參數(shù)為一個時一定要加逗號 t1 = threading.Thread(target=fun1, args=(num,)) t2 = threading.Thread(target=fun2, args=([1, 2, 3, 4, 5],)) # 調(diào)用start方法 t1.start() t2.start() if __name__ == '__main__': main()
2.2 方法二:
創(chuàng)建子類繼承threading.Thread類
import threading import os class Person(threading.Thread): def run(self): self.sing(5) self.cook() @staticmethod def sing(num): for i in range(num): print('線程[%d]: The person sing %d song.' % (os.getpid(), i)) @staticmethod def cook(): print('線程[%d]:The person has cooked breakfast.' % os.getpid()) def main(): p1 = Person() p1.start() p2 = Person() p2.start() if __name__ == '__main__': main()
三、線程的用法
3.1 確定當(dāng)前的線程
import threading import time import logging def fun1(): print(threading.current_thread().getName(), 'starting') time.sleep(0.2) print(threading.current_thread().getName(), 'exiting') def fun2(): # print(threading.current_thread().getName(), 'starting') # time.sleep(0.3) # print(threading.current_thread().getName(), 'exiting') logging.debug('starting') time.sleep(0.3) logging.debug('exiting') logging.basicConfig( level=logging.DEBUG, format='[%(levelname)s] (%(threadName)-10s) %(message)s' ) def main(): t1 = threading.Thread(name='線程1', target=fun1) t2 = threading.Thread(name='線程2', target=fun2) t1.start() t2.start() if __name__ == '__main__': main()
3.2 守護(hù)線程
區(qū)別
- 普通線程:主線程等待子線程關(guān)閉后關(guān)閉
- 守護(hù)線程:管你子線程關(guān)沒關(guān),主線程到時間就關(guān)閉
守護(hù)線程如何搞
- 方法1:構(gòu)造線程時傳入dameon=True
- 方法2:調(diào)用setDaemon()方法并提供參數(shù)True
import threading import time import logging def daemon(): logging.debug('starting') # 添加延時,此時主線程已經(jīng)退出,exiting不會打印 time.sleep(0.2) logging.debug('exiting') def non_daemon(): logging.debug('starting') logging.debug('exiting') logging.basicConfig( level=logging.DEBUG, format='[%(levelname)s] (%(threadName)-10s) %(message)s' ) def main(): # t1 = threading.Thread(name='線程1', target=daemon) # t1.setDaemon(True) t1 = threading.Thread(name='線程1', target=daemon, daemon=True) t2 = threading.Thread(name='線程2', target=non_daemon) t1.start() t2.start() # 等待守護(hù)線程完成工作需要調(diào)用join()方法,默認(rèn)情況join會無限阻塞,可以傳入浮點值,表示超時時間 t1.join(0.2) t2.join(0.1) if __name__ == '__main__': main()
3.3 控制資源訪問
目的:
Python線程中資源共享,如果不對資源加上互斥鎖,有可能導(dǎo)致數(shù)據(jù)不準(zhǔn)確。
import threading import time g_num = 0 def fun1(num): global g_num for i in range(num): g_num += 1 print('線程1 g_num = %d' % g_num) def fun2(num): global g_num for i in range(num): g_num += 1 print('線程2 g_num = %d' % g_num) def main(): t1 = threading.Thread(target=fun1, args=(1000000,)) t2 = threading.Thread(target=fun1, args=(1000000,)) t1.start() t2.start() if __name__ == '__main__': main() time.sleep(1) print('主線程 g_num = %d' % g_num)
互斥鎖
import threading import time g_num = 0 L = threading.Lock() def fun1(num): global g_num L.acquire() for i in range(num): g_num += 1 L.release() print('線程1 g_num = %d' % g_num) def fun2(num): global g_num L.acquire() for i in range(num): g_num += 1 L.release() print('線程2 g_num = %d' % g_num) def main(): t1 = threading.Thread(target=fun1, args=(1000000,)) t2 = threading.Thread(target=fun1, args=(1000000,)) t1.start() t2.start() if __name__ == '__main__': main() time.sleep(1) print('主線程 g_num = %d' % g_num)
互斥鎖引發(fā)的另一個問題:死鎖
死鎖產(chǎn)生的原理:
import threading import time g_num = 0 L1 = threading.Lock() L2 = threading.Lock() def fun1(): L1.acquire(timeout=5) time.sleep(1) L2.acquire() print('產(chǎn)生死鎖,并不會打印信息') L2.release() L1.release() def fun2(): L2.acquire(timeout=5) time.sleep(1) L1.acquire() print('產(chǎn)生死鎖,并不會打印信息') L1.release() L2.release() def main(): t1 = threading.Thread(target=fun1) t2 = threading.Thread(target=fun2) t1.start() t2.start() if __name__ == '__main__': main() time.sleep(1) print('主線程 g_num = %d' % g_num)
如何避免產(chǎn)生死鎖:
鎖超時操作
import threading import time g_num = 0 L1 = threading.Lock() L2 = threading.Lock() def fun1(): L1.acquire() time.sleep(1) L2.acquire(timeout=5) print('超時異常打印信息1') L2.release() L1.release() def fun2(): L2.acquire() time.sleep(1) L1.acquire(timeout=5) print('超時異常打印信息2') L1.release() L2.release() def main(): t1 = threading.Thread(target=fun1) t2 = threading.Thread(target=fun2) t1.start() t2.start() if __name__ == '__main__': main() time.sleep(1) print('主線程 g_num = %d' % g_num)
到此這篇關(guān)于Python多線程編程之threading模塊詳解的文章就介紹到這了,更多相關(guān)python threading模塊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python+MySQL隨機(jī)試卷及答案生成程序的示例代碼
這篇文章主要介紹了Python+MySQL隨機(jī)試卷及答案生成程序的示例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02Python利用itchat對微信中好友數(shù)據(jù)實現(xiàn)簡單分析的方法
Python 熱度一直很高,我感覺這就是得益于擁有大量的包資源,極大的方便了開發(fā)人員的需求。下面這篇文章主要給大家介紹了關(guān)于Python利用itchat實現(xiàn)對微信中好友數(shù)據(jù)進(jìn)行簡單分析的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。2017-11-11如何通過雪花算法用Python實現(xiàn)一個簡單的發(fā)號器
這篇文章主要介紹了如何通過雪花算法用Python實現(xiàn)一個簡單的發(fā)號器,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Python遞歸調(diào)用實現(xiàn)數(shù)字累加的代碼
今天小編就為大家分享一篇Python遞歸調(diào)用實現(xiàn)數(shù)字累加的代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02