將你需要多線程并發(fā)執(zhí)行的函數(shù)放入list中

龍鳳ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)建站的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!
import threading
threads = []
t1 = threading.Thread(target=函數(shù)名,args=參數(shù))
threads.append(t1)
啟動多線程
if __name__ == '__main__':
??? for t in threads:
? ? ??? t.setDaemon(True)
? ? ??? t.start()
t.join()
更多詳細(xì)操作help(threading)
#coding=utf-8
import?threading
from?time?import?ctime,sleep
#?要啟動的函數(shù)
def?music(func):
for?i?in?range(2):
print?"I?was?listening?to?%s.?%s"?%(func,ctime())
sleep(1)
#?要啟動的函數(shù)
def?move(func):
for?i?in?range(2):
print?"I?was?at?the?%s!?%s"?%(func,ctime())
sleep(5)
threads?=?[]
t1?=?threading.Thread(target=music,args=(u'愛情買賣',))
threads.append(t1)
t2?=?threading.Thread(target=move,args=(u'阿凡達(dá)',))
threads.append(t2)
#?函數(shù)加入線程列表
if?__name__?==?'__main__':
for?t?in?threads:
t.setDaemon(True)
t.start()
t.join()?#子線程完成運行之前,這個子線程的父線程將一直被阻塞,不會退出
print?"all?over?%s"?%ctime()
并發(fā):邏輯上具備同時處理多個任務(wù)的能力。
并行:物理上在同一時刻執(zhí)行多個并發(fā)任務(wù)。
舉例:開個QQ,開了一個進(jìn)程,開了微信,開了一個進(jìn)程。在QQ這個進(jìn)程里面,傳輸文字開一個線程、傳輸語音開了一個線程、彈出對話框又開了一個線程。
總結(jié):開一個軟件,相當(dāng)于開了一個進(jìn)程。在這個軟件運行的過程里,多個工作同時運轉(zhuǎn),完成了QQ的運行,那么這個多個工作分別有多個線程。
線程和進(jìn)程之間的區(qū)別:
進(jìn)程在python中的使用,對模塊threading進(jìn)行操作,調(diào)用的這個三方庫。可以通過 help(threading) 了解其中的方法、變量使用情況。也可以使用 dir(threading) 查看目錄結(jié)構(gòu)。
current_thread_num = threading.active_count() # 返回正在運行的線程數(shù)量
run_thread_len = len(threading.enumerate()) # 返回正在運行的線程數(shù)量
run_thread_list = threading.enumerate() # 返回當(dāng)前運行線程的列表
t1=threading.Thread(target=dance) #創(chuàng)建兩個子線程,參數(shù)傳遞為函數(shù)名
t1.setDaemon(True) # 設(shè)置守護(hù)進(jìn)程,守護(hù)進(jìn)程:主線程結(jié)束時自動退出子線程。
t1.start() # 啟動子線程
t1.join() # 等待進(jìn)程結(jié)束 exit()`# 主線程退出,t1子線程設(shè)置了守護(hù)進(jìn)程,會自動退出。其他子線程會繼續(xù)執(zhí)行。
1、python提供兩種方式使用多線程:一個是基于函數(shù):_thread模塊或者threading模塊。一個是基于類:theading.Thread
使用多線程函數(shù)包裝線程對象:_thread
_thead.start_new_thead(func,*args,**kwargs)
args,**kwargs是被包裝函數(shù)的入?yún)ⅲ仨殏魅朐婊蜃值?/p>
使用多線程函數(shù)包裝線程對象:threading
threading._start_new_thread(func,*args,**kwargs):開啟線程,帶元祖或字典
threading.currentThread():返回當(dāng)前線程變量
threading.enumerate():正在運行的線程列表,不含未啟動和已結(jié)束線程
threading.activeCount():返回正在運行的線程數(shù)量
threading.settrace(func):為所有threading模塊啟動的線程設(shè)置追蹤函數(shù),在調(diào)用run方法之前,func會被傳給追蹤函數(shù)
threading.setprofile(func):為所有threading模塊啟動的線程設(shè)置性能測試函數(shù),也是在run方法調(diào)用前就傳遞給性能測試函數(shù)
使用多線程類包裝線程對象:threading.Thread
Thread類提供以下方法:
run():表示線程活動的方法,線程需要控制些什么活動都在這里面定義。當(dāng)線程對象一但被創(chuàng)建,其活動一定會因調(diào)用線程的 start() 方法開始。這會在獨立的控制線程調(diào)用 run() 方法。
start():開啟線程活動
join():等待線程中止,阻塞當(dāng)前線程直到被調(diào)用join方法的線程中止。線程A調(diào)用線程B的join方法,那線程A將會被阻塞至線程B中止。
isAlive():返回線程是否還活動
getName():獲取線程名字
setName():設(shè)置線程名字
Lock對象:實例化線程鎖,包含acquire方法獲取鎖 和 release 方法釋放鎖,在最開始創(chuàng)建鎖的時候,鎖為未鎖定狀態(tài),調(diào)用acquire方法后鎖置為鎖定狀態(tài),此時其他線程再調(diào)用acquire方法就將會被阻塞至其他線程調(diào)用release方法釋放鎖,如果釋放一個并未被鎖定的鎖將會拋出異常。支持上下文管理協(xié)議,直接with lock 無需調(diào)用鎖定,釋放方法
Rlock對象:重入鎖,相比lock增加了線程和遞歸的概念。比如:線程目標(biāo)函數(shù)F,在獲得鎖之后執(zhí)行函數(shù)G,但函數(shù)G也需要先獲得鎖,此時同一線程,F(xiàn)獲得鎖,G等待,F(xiàn)等待G執(zhí)行,就造成了死鎖,此時使用rlock可避免。一旦線程獲得了重入鎖,同一個線程再次獲取它將不阻塞;但線程必須在每次獲取它時釋放一次。
daemon屬性:設(shè)置該線程是否是守護(hù)線程,默認(rèn)為none,需要在調(diào)用start方法之前設(shè)置好
事件對象:一個線程發(fā)出事件信號 ,其他線程收到信號后作出對應(yīng)活動。實例化事件對象后,初始事件標(biāo)志為flase。調(diào)用其wait方法將阻塞當(dāng)前所屬線程,至事件標(biāo)志為true時。調(diào)用set方法可將事件標(biāo)志置為true,被阻塞的線程將被執(zhí)行。調(diào)用clear方法可將事件標(biāo)志置為flase
注意點:
1、繼承threading.Thread類,初始化時要記得繼承父類的__init__方法
2、run()方法只能有一個入?yún)ⅲ时M量把啟動線程時的參數(shù)入?yún)⒌匠跏蓟臅r候
3、鎖要設(shè)定全局的,一個子線程獲得一個鎖沒有意義
以下實例:有一個列表,線程A從尾到頭遍歷元素,線程B從頭到尾將元素值重置為1,設(shè)置線程鎖之前線程A遍歷到頭部的數(shù)據(jù)已經(jīng)被修改,設(shè)置線程鎖之后不會再有數(shù)據(jù)不一致的情況
import threading,time
class tt(threading.Thread):
def __init__(self,name,func,ll):
? ? threading.Thread.__init__(self) #繼承父級的初始化方法
? ? self.name=name
? ? self.func=func? #run方法只能帶一個入?yún)ⅲ拾逊椒ㄈ雲(yún)⒌匠跏蓟臅r候
? ? self.ll=ll
def run(self):
? ? print(self.name)
? ? threadlock.acquire() #獲得鎖
? ? self.func(self.ll)
? ? threadlock.release() #釋放鎖
def readd(x):
a=len(x)
while a0:
? ? print(x[a-1])
? ? a-=1
def sett(x):
for i in range(len(x)):
? ? x[i]=1
print(x)
if __name__=="__main__":
l = [0,0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
threadlock=threading.Lock() #實例化全局鎖
th1=tt("read",readd,l)
th2=tt("set",sett,l)
th1.start()
th2.start()
th_list=[]?
th_list.append(th1)
th_list.append(th2)
for li in th_list:
? ? li.join()? ? ? ? #主線程被阻塞,直到兩個子線程處理結(jié)束
print("主線程結(jié)束")
2、隊列
queue模塊包含queue.Queue(maxsize=0)先入先出隊列,queue.LifoQueue()先入后出隊列,和queue.PriorityQueue()優(yōu)先級可設(shè)置的隊列
Queue 模塊中的常用方法:
Queue.qsize() 返回隊列的大小,獲取的數(shù)據(jù)不可靠,因為一直有線程在操作隊列,數(shù)據(jù)一直變化
Queue.empty() 如果隊列為空,返回True,反之False
Queue.full() 如果隊列滿了,返回True,反之False
Queue.full 與 maxsize 大小對應(yīng)
Queue.put(block=true,timeout=none) 將item數(shù)據(jù)寫入隊列,block=True,設(shè)置線程是否阻塞,設(shè)置阻塞當(dāng)隊列數(shù)據(jù)滿了之后就會阻塞,一直到隊列數(shù)據(jù)不滿時繼續(xù)添加,如果設(shè)置不阻塞,當(dāng)隊列滿了就會一直到timeout到后報錯
Queue.get([block[, timeout]]) 取出隊列數(shù)據(jù),block=True,設(shè)置線程是否阻塞。設(shè)置阻塞,將會等待直到隊列不為空有數(shù)據(jù)可取出,設(shè)置不阻塞直到超過timeout等待時間后報錯
Queue.task_done() 在完成一項工作之后,Queue.task_done()函數(shù)向任務(wù)已經(jīng)完成的隊列發(fā)送一個信號
Queue.join() 實際上意味著等到隊列為空,再執(zhí)行別的操作。會在隊列有未完成時阻塞,等待隊列無未完成的任務(wù),取出數(shù)據(jù)get()之后還需要配置task_done使用才能讓等待隊列數(shù)-1
import queue,time
import threading
q=queue.Queue(maxsize=5)
def sett():
a=0
while a20:
? ? q.put(a,True)
? ? print("%d被put"%a)
? ? a+=1
def gett():
time.sleep(1)
while not q.empty(): #只要隊列沒空,一直取數(shù)據(jù)
? ? print("%d被取出"%q.get(True))
? ? q.task_done() #取出一次數(shù)據(jù),將未完成任務(wù)-1,不然使用join方法線程會一直阻塞
if __name__=="__main__":
th1=threading._start_new_thread(sett,()) #不帶參數(shù)也要傳入空元祖不然會報錯
th2=threading._start_new_thread(gett,())
time.sleep(1) #延時主線程1S,等待put線程已經(jīng)put部分?jǐn)?shù)據(jù)到隊列
q.join()#阻塞主線程,直到未完成任務(wù)為0
在實際處理數(shù)據(jù)時,因系統(tǒng)內(nèi)存有限,我們不可能一次把所有數(shù)據(jù)都導(dǎo)出進(jìn)行操作,所以需要批量導(dǎo)出依次操作。為了加快運行,我們會采用多線程的方法進(jìn)行數(shù)據(jù)處理, 以下為我總結(jié)的多線程批量處理數(shù)據(jù)的模板:
主要分為三大部分:
共分4部分對多線程的內(nèi)容進(jìn)行總結(jié)。
先為大家介紹線程的相關(guān)概念:
在飛車程序中,如果沒有多線程,我們就不能一邊聽歌一邊玩飛車,聽歌與玩 游戲 不能并行;在使用多線程后,我們就可以在玩 游戲 的同時聽背景音樂。在這個例子中啟動飛車程序就是一個進(jìn)程,玩 游戲 和聽音樂是兩個線程。
Python 提供了 threading 模塊來實現(xiàn)多線程:
因為新建線程系統(tǒng)需要分配資源、終止線程系統(tǒng)需要回收資源,所以如果可以重用線程,則可以減去新建/終止的開銷以提升性能。同時,使用線程池的語法比自己新建線程執(zhí)行線程更加簡潔。
Python 為我們提供了 ThreadPoolExecutor 來實現(xiàn)線程池,此線程池默認(rèn)子線程守護(hù)。它的適應(yīng)場景為突發(fā)性大量請求或需要大量線程完成任務(wù),但實際任務(wù)處理時間較短。
其中 max_workers 為線程池中的線程個數(shù),常用的遍歷方法有 map 和 submit+as_completed 。根據(jù)業(yè)務(wù)場景的不同,若我們需要輸出結(jié)果按遍歷順序返回,我們就用 map 方法,若想誰先完成就返回誰,我們就用 submit+as_complete 方法。
我們把一個時間段內(nèi)只允許一個線程使用的資源稱為臨界資源,對臨界資源的訪問,必須互斥的進(jìn)行。互斥,也稱間接制約關(guān)系。線程互斥指當(dāng)一個線程訪問某臨界資源時,另一個想要訪問該臨界資源的線程必須等待。當(dāng)前訪問臨界資源的線程訪問結(jié)束,釋放該資源之后,另一個線程才能去訪問臨界資源。鎖的功能就是實現(xiàn)線程互斥。
我把線程互斥比作廁所包間上大號的過程,因為包間里只有一個坑,所以只允許一個人進(jìn)行大號。當(dāng)?shù)谝粋€人要上廁所時,會將門上上鎖,這時如果第二個人也想大號,那就必須等第一個人上完,將鎖解開后才能進(jìn)行,在這期間第二個人就只能在門外等著。這個過程與代碼中使用鎖的原理如出一轍,這里的坑就是臨界資源。 Python 的 threading 模塊引入了鎖。 threading 模塊提供了 Lock 類,它有如下方法加鎖和釋放鎖:
我們會發(fā)現(xiàn)這個程序只會打印“第一道鎖”,而且程序既沒有終止,也沒有繼續(xù)運行。這是因為 Lock 鎖在同一線程內(nèi)第一次加鎖之后還沒有釋放時,就進(jìn)行了第二次 acquire 請求,導(dǎo)致無法執(zhí)行 release ,所以鎖永遠(yuǎn)無法釋放,這就是死鎖。如果我們使用 RLock 就能正常運行,不會發(fā)生死鎖的狀態(tài)。
在主線程中定義 Lock 鎖,然后上鎖,再創(chuàng)建一個子 線程t 運行 main 函數(shù)釋放鎖,結(jié)果正常輸出,說明主線程上的鎖,可由子線程解鎖。
如果把上面的鎖改為 RLock 則報錯。在實際中設(shè)計程序時,我們會將每個功能分別封裝成一個函數(shù),每個函數(shù)中都可能會有臨界區(qū)域,所以就需要用到 RLock 。
一句話總結(jié)就是 Lock 不能套娃, RLock 可以套娃; Lock 可以由其他線程中的鎖進(jìn)行操作, RLock 只能由本線程進(jìn)行操作。
名稱欄目:Python多線程多函數(shù) python 多線程 函數(shù)
文章網(wǎng)址:http://chinadenli.net/article48/hhjoep.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、網(wǎng)站營銷、網(wǎng)站設(shè)計、網(wǎng)站維護(hù)、網(wǎng)站收錄、企業(yè)網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)