Python多線程模塊Threading用法示例小結(jié)
本文實(shí)例講述了Python多線程模塊Threading用法。分享給大家供大家參考,具體如下:
步入正題前,先準(zhǔn)備下基本知識(shí),線程與進(jìn)程的概念。
相信作為一個(gè)測(cè)試人員,如果從理論概念上來(lái)說(shuō)其兩者的概念或者區(qū)別,估計(jì)只會(huì)一臉蒙蔽,這里就舉個(gè)例子來(lái)說(shuō)明下其中的相關(guān)概念。
平安夜剛過(guò),你是吃到了蘋果還是香蕉呢。。。其實(shí)當(dāng)你用手去接下對(duì)方蘋果的時(shí)候,你的手臂就可以比喻成進(jìn)程,你的五個(gè)手指就可以比喻成線程,所以很明顯,線程可以說(shuō)是進(jìn)程的細(xì)化,沒(méi)有進(jìn)程就不會(huì)有線程。
這里還是說(shuō)下必要的概念:
進(jìn)程
是操作系統(tǒng)中當(dāng)前程序的一次執(zhí)行。要知道擁有單個(gè)CPU的電腦,在嚴(yán)格意義上,一個(gè)時(shí)間點(diǎn)上操作系統(tǒng)只能進(jìn)行同一個(gè)工作命令。由于計(jì)算機(jī)的運(yùn)行速度快,在工作時(shí)可以運(yùn)行一會(huì)A代碼,運(yùn)行一會(huì)B代碼,交錯(cuò)運(yùn)行,由于運(yùn)算速度快,所以一般看來(lái)它好像可以同時(shí)進(jìn)行多個(gè)程序--這就是多進(jìn)程。
線程
線程是程序中一個(gè)單一的順序控制流程。進(jìn)程內(nèi)一個(gè)相對(duì)獨(dú)立的、可調(diào)度的執(zhí)行單元,是系統(tǒng)獨(dú)立調(diào)度和分派CPU的基本單位,這里的單位指運(yùn)行中的程序的調(diào)度單位。在單個(gè)程序中同時(shí)運(yùn)行多個(gè)線程完成不同的工作,稱為多線程。線程還可以自己創(chuàng)建、撤銷和切換。就像拿蘋果,如果一根手指可以辦到,那它就是單線程,如果需要多根手指,那就是多線程。
進(jìn)程和線程的區(qū)別
(1)進(jìn)程是資源的分配和調(diào)度的一個(gè)獨(dú)立單元,而線程是CPU調(diào)度的基本單元
(2)同一個(gè)進(jìn)程中可以包括多個(gè)線程,并且線程共享整個(gè)進(jìn)程的資源(寄存器、堆棧、上下文),一個(gè)進(jìn)程至少包括一個(gè)線程。
(3)進(jìn)程結(jié)束后它擁有的所有線程都將銷毀,而線程的結(jié)束不會(huì)影響同個(gè)進(jìn)程中的其他線程的結(jié)束
(4)線程是輕量級(jí)的進(jìn)程,它的創(chuàng)建和銷毀所需要的時(shí)間比進(jìn)程小很多,所有操作系統(tǒng)中的執(zhí)行功能都是創(chuàng)建線程去完成的
(5)線程中執(zhí)行時(shí)一般都要進(jìn)行同步和互斥,因?yàn)樗麄児蚕硗贿M(jìn)程的所有資源(資源競(jìng)爭(zhēng))
(6)線程有自己的私有屬性TCB,線程id,寄存器、硬件上下文,而進(jìn)程也有自己的私有屬性進(jìn)程控制塊PCB,這些私有屬性是不被共享的,用來(lái)標(biāo)示一個(gè)進(jìn)程或一個(gè)線程的標(biāo)志
子進(jìn)程與子線程的區(qū)別
進(jìn)程和線程的區(qū)別在于粒度不同, 進(jìn)程之間的變量(或者說(shuō)是內(nèi)存)是不能直接互相訪問(wèn)的, 而線程可以, 線程一定會(huì)依附在某一個(gè)進(jìn)程上執(zhí)行.我舉個(gè)例子, 你在Windows下開(kāi)一個(gè)IE瀏覽器, 這個(gè)IE瀏覽器是一個(gè)進(jìn)程. 你用瀏覽器去打開(kāi)一個(gè)pdf, IE就去調(diào)用Acrobat去打開(kāi), 這時(shí)Acrobat是一個(gè)獨(dú)立的進(jìn)程, 就是IE的子進(jìn)程.而IE自己本身同時(shí)用同一個(gè)進(jìn)程開(kāi)了2個(gè)網(wǎng)頁(yè), 并且同時(shí)在跑兩個(gè)網(wǎng)頁(yè)上的腳本, 這兩個(gè)網(wǎng)頁(yè)的執(zhí)行就是IE自己通過(guò)兩個(gè)線程實(shí)現(xiàn)的.值得注意的是, 線程仍然是IE的內(nèi)容, 而子進(jìn)程Acrobat嚴(yán)格來(lái)說(shuō)就不屬于IE了, 是另外一個(gè)程序,之所以是IE的子進(jìn)程, 只是受IE調(diào)用而啟動(dòng)的而已。
這里大家可能會(huì)疑惑,進(jìn)程分配內(nèi)存空間的依據(jù)是啥?其實(shí)進(jìn)程建立,系統(tǒng)會(huì)為其分配虛擬地址空間4GB(在32位系統(tǒng)中),具體分配情況要取決于該包含的所有可執(zhí)行模塊或dll模塊的代碼和數(shù)據(jù),還包含動(dòng)態(tài)內(nèi)存分配的空間(如線程中堆棧的分配)
好了,上面介紹了基本的線程及進(jìn)程的概念,接下來(lái)可以開(kāi)始正題了,這里主要總結(jié)下python內(nèi)的Threading模塊
python多線程之Threading
單線程
額,這個(gè)忽略吧。。。操作系統(tǒng)單任務(wù)的處理,排好隊(duì),一個(gè)一個(gè)來(lái)就是單線程。
多線程
多線程Threading一般可以通過(guò)兩種渠道來(lái)實(shí)現(xiàn):一種是通過(guò)繼承Thread類,重寫它的run方法;另一種是創(chuàng)建一個(gè)threading.Thread對(duì)象,在它的初始化函數(shù)(__init__)中將可調(diào)用對(duì)象作為參數(shù)傳入,本質(zhì)上來(lái)講,兩種方式一樣。
來(lái)一發(fā)實(shí)例:
# -*- coding: utf-8 -*-
import threading
import time
#方式二是方式一的具體,方式一為類構(gòu)造,方式二為方法實(shí)例構(gòu)造,其實(shí)本質(zhì)都是一樣,都是調(diào)用threading.Thread模塊
#方式一
count = 0
class Counter(threading.Thread):
def __init__(self, lock, threadName):
#注意:一定要顯式的調(diào)用父類的初始化函數(shù),這里可以指定生成的線程名,可以是*args、**kwargs
#def __init__(self, group=None, target=None, name=None, args=(), kwargs={}),其中g(shù)roup是預(yù)留的,將來(lái)用于擴(kuò)展
super(Counter, self).__init__(name=threadName)
self.lock = lock
def run(self):
global count
self.lock.acquire()
for i in range(100):
count = count + 1
self.lock.release()
#方式二
lockA = threading.Lock()
lockB = threading.Lock()
rLock = threading.RLock()
condt = threading.Condition()
event = threading.Event()
def add(lockA):
global count
#定義當(dāng)前資源只能單線程訪問(wèn),鎖住后完成資源調(diào)用一定要釋放鎖,不然會(huì)造成死鎖狀態(tài),甚至程序崩潰
lockA.acquire()
for i in range(1000):
count = count + 1
#資源調(diào)用完畢,釋放鎖
lockA.release()
def addRunner():
for i in range(2):
th = threading.Thread(target=rloc, args=(rLock,))
#開(kāi)啟線程,從此刻起,多線程開(kāi)始,主線程繼續(xù)前行
th.start()
#調(diào)用Thread.join[timeout]將會(huì)使主調(diào)線程堵塞,直到被調(diào)用線程運(yùn)行結(jié)束或超時(shí)。參數(shù)timeout是一個(gè)數(shù)值類型,表示超時(shí)時(shí)間
th.join()
print '----- %s is start -----' % th.getName()
print "over"
#RLock允許在同一線程中被多次acquire,避免單線程出現(xiàn)思索情況
def rloc(rLock):
rLock.acquire()
for i in range(2):
rLock.acquire()
print i,
rLock.release()
rLock.release()
print "over!"
def rlocRun():
for i in range(2):
th = threading.Thread(target=rloc, args=(rLock,))
th.start()
print '----- %s is start -----' % th.getName()
print "over"
#現(xiàn)在出現(xiàn)復(fù)雜的場(chǎng)景,多個(gè)線程需要調(diào)用多個(gè)共同的資源,此時(shí)就需要threading.Condition出馬,加入簡(jiǎn)單的說(shuō)就是A搞完了A的事
# ,就發(fā)廣播說(shuō)明自己搞定了,其它人可以進(jìn)來(lái)了,B同理。
def cond(cond):
#適合那種主動(dòng)休眠,被動(dòng)喚醒的場(chǎng)景
cond.acquire()
global count
for i in range(1000):
count = count + 1
#喚醒一個(gè)掛起的線程(如果存在掛起的線程),提醒當(dāng)前的掛起的線程看看其它的鎖開(kāi)了沒(méi)有,如果開(kāi)了就搞其他的事。
#注意:notify()方法不會(huì)釋放所占用的瑣。
cond.notify()
#wait方法釋放內(nèi)部所占用的瑣,同時(shí)線程被掛起,直至接收到通知被喚醒或超時(shí)
cond.wait(5)
#相信大家應(yīng)該看出問(wèn)題來(lái)了,最后一個(gè)線程咋辦列,沒(méi)人喚醒啊,這個(gè)時(shí)候應(yīng)該做過(guò)一個(gè)判斷
cond.release()
print "over!"
def condRun():
global condt
for i in range(0, 3):
th = threading.Thread(target=cond, args=(condt, ))
th.start()
print '----- %s is start -----' % th.getName()
print "over"
#此時(shí)可能會(huì)有一點(diǎn)問(wèn)題,就是線程的同步(并發(fā))問(wèn)題怎么解決呢?此時(shí)threading.Event出馬
def even(n, event):
while not event.isSet():
print 'Thread %s is ready' % n
time.sleep(1)
#同condition一樣,掛起該線程,等待set開(kāi)關(guān)
event.wait()
while event.isSet():
print 'Thread %s is running' % n
time.sleep(1)
def evenRun():
for i in range(0, 2):
th = threading.Thread(target=even, args=(i, event))
th.start()
time.sleep(3)
print '----- event is set -----'
event.set()
time.sleep(3)
print '----- event is clear -----'
event.clear()
if __name__ == "__main__":
Counter(lockA, "thread1").start()
addRunner()
rlocRun()
condRun()
evenRun()
更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python進(jìn)程與線程操作技巧總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門與進(jìn)階經(jīng)典教程》、《Python+MySQL數(shù)據(jù)庫(kù)程序設(shè)計(jì)入門教程》及《Python常見(jiàn)數(shù)據(jù)庫(kù)操作技巧匯總》
希望本文所述對(duì)大家Python程序設(shè)計(jì)有所幫助。
- 在Python中通過(guò)threading模塊定義和調(diào)用線程的方法
- Python+threading模塊對(duì)單個(gè)接口進(jìn)行并發(fā)測(cè)試
- python threading和multiprocessing模塊基本用法實(shí)例分析
- Python 多線程,threading模塊,創(chuàng)建子線程的兩種方式示例
- Python線程threading模塊用法詳解
- Python threading模塊condition原理及運(yùn)行流程詳解
- Python 多線程之threading 模塊的使用
- Python多線程編程之threading模塊詳解
- python threading模塊的使用指南
- Python常用模塊之threading和Thread模塊及線程通信
相關(guān)文章
Python通過(guò)pymysql調(diào)用MySQL進(jìn)行增刪改移查
這篇文章主要介紹了Python通過(guò)pymysql調(diào)用MySQL,從而實(shí)現(xiàn)數(shù)據(jù)的增刪改移查功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2021-12-12
python2.x實(shí)現(xiàn)人民幣轉(zhuǎn)大寫人民幣
這篇文章主要為大家詳細(xì)介紹了python2.x實(shí)現(xiàn)人民幣轉(zhuǎn)大寫人民幣,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
Pytorch之8層神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)Cifar-10圖像分類驗(yàn)證集準(zhǔn)確率94.71%
這篇文章主要介紹了Pytorch之8層神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)Cifar-10圖像分類驗(yàn)證集準(zhǔn)確率94.71%問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
python 實(shí)現(xiàn)人和電腦猜拳的示例代碼
這篇文章主要介紹了python 實(shí)現(xiàn)人和電腦猜拳的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
python 實(shí)現(xiàn)docx與doc文件的互相轉(zhuǎn)換
這篇文章主要介紹了python 實(shí)現(xiàn)docx與doc文件的互相轉(zhuǎn)換操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03
如何解決django-celery啟動(dòng)后迅速關(guān)閉
在本篇文章里小編給大家整理的是關(guān)于django-celery啟動(dòng)后迅速關(guān)閉的解決方法,有需要的朋友們學(xué)習(xí)下。2019-10-10
python3+django2開(kāi)發(fā)一個(gè)簡(jiǎn)單的人員管理系統(tǒng)過(guò)程詳解
這篇文章主要介紹了python3+django2開(kāi)發(fā)一個(gè)簡(jiǎn)單的人員管理系統(tǒng)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07

