背景:近期工作需要耀找,要縮短多個(gè)程序的運(yùn)行時(shí)間。
目標(biāo):做到同時(shí)運(yùn)行多個(gè)函數(shù)业崖,提高效率野芒。
方案:查閱資料后蓄愁,發(fā)現(xiàn)可以使用線(xiàn)程,進(jìn)程狞悲,協(xié)程來(lái)提高效率涝登。(包括線(xiàn)程池,進(jìn)程池)
【一】 多線(xiàn)程
【二】 線(xiàn)程池
tips:
#需要處理列表中的所有數(shù)據(jù)
url_list =[url1,ulr2,-----,url100]
工作中需要對(duì)一個(gè)列表中的所有數(shù)據(jù)進(jìn)行處理效诅,直接用多線(xiàn)程的話(huà),一開(kāi)始數(shù)據(jù)數(shù)對(duì)不上趟济,后來(lái)拆分成多個(gè)列表進(jìn)行處理的話(huà)乱投,感覺(jué)很麻煩。所以開(kāi)始使用線(xiàn)程池顷编。
參考原文
1戚炫、下載運(yùn)行包
pip install threadpool
2、參數(shù)說(shuō)明
pool = ThreadPool(poolsize)
定義了一個(gè)線(xiàn)程池媳纬,表示最多可以創(chuàng)建poolsize這么多線(xiàn)程双肤;
requests = makeRequests(some_callable, list_of_args, callback)
調(diào)用makeRequests創(chuàng)建了要開(kāi)啟多線(xiàn)程的函數(shù),以及函數(shù)相關(guān)參數(shù)和回調(diào)函數(shù)钮惠,其中回調(diào)函數(shù)可以不寫(xiě)茅糜,default是無(wú),也就是說(shuō)makeRequests只需要2個(gè)參數(shù)就可以運(yùn)行素挽;
for req in requests:
pool.putRequest(req)
是將所有要運(yùn)行多線(xiàn)程的請(qǐng)求扔進(jìn)線(xiàn)程池蔑赘;
pool.wait()
第四行是等待所有的線(xiàn)程完成工作后退出
3、對(duì)比效果
#創(chuàng)建一個(gè)長(zhǎng)度30的列表
a = []
n =1
while n<=30:
a.append(n)
n +=1
#創(chuàng)建一個(gè)存儲(chǔ)位置
c = []
#定義一個(gè)對(duì)單一數(shù)據(jù)處理的函數(shù),將處理后的數(shù)據(jù)存儲(chǔ)在c中
def x(aaa):
u = (12+aaa)+aaa%2
c.append(u)
print ("Hello ",aaa)
time.sleep(1)
串行操作:
start_time = time.time()
for i in a:
x(i)
print(c)
print ('%d second'% (time.time()-start_time))
串行結(jié)果
線(xiàn)程池操作:
start_time = time.time()
#一次跑10個(gè)線(xiàn)程
pool = threadpool.ThreadPool(10)
#運(yùn)行函數(shù)x,參數(shù)為a
requests = threadpool.makeRequests(x, a)
[pool.putRequest(req) for req in requests]
pool.wait()
print ('%d second'% (time.time()-start_time))
線(xiàn)程池結(jié)果
運(yùn)用線(xiàn)程池可以批量處理數(shù)據(jù)预明,節(jié)省時(shí)間
4缩赛、多個(gè)參數(shù)的設(shè)置。
實(shí)際工作中定義的函數(shù)不止包含一個(gè)參數(shù)撰糠,那么在調(diào)用線(xiàn)程池的時(shí)候需要對(duì)參數(shù)做預(yù)處理酥馍。
if __name__ == '__main__':
# 方法1 --- 存入列表
lst_vars_1 = ['1', '2', '3']
lst_vars_2 = ['4', '5', '6']
func_var = [(lst_vars_1, None), (lst_vars_2, None)]
# 方法2 --- 存成字典
dict_vars_1 = {'m':'1', 'n':'2', 'o':'3'}
dict_vars_2 = {'m':'4', 'n':'5', 'o':'6'}
func_var = [(None, dict_vars_1), (None, dict_vars_2)]
pool = threadpool.ThreadPool(2)
requests = threadpool.makeRequests(hello, func_var)
[pool.putRequest(req) for req in requests]
pool.wait()
參數(shù)處理:
list1 = [1,2,3,4,5,6]
list2 = [7,6,5,4,3,2]
def X(a,b,c=3,d=4,e=5):
time.sleep(1)
print(a+b+c+d+e)
#構(gòu)建參數(shù)組
data1 =[ {
'a':i,
'b':j,
'c':3,
'd':4
} for i,j in zip(list1,list2) ]
data2 = [(None,i) for i in data1]
#調(diào)用線(xiàn)程池
start_time = time.time()
pool = threadpool.ThreadPool(2)
requests = threadpool.makeRequests(X, data2)
[pool.putRequest(req) for req in requests]
pool.wait()
print ('%d second'% (time.time()-start_time))
5、編寫(xiě)線(xiàn)程池函數(shù)阅酪。
實(shí)際工作中可以將線(xiàn)程池編寫(xiě)如函數(shù)直接進(jìn)行調(diào)用旨袒。
參數(shù)包含(函數(shù),運(yùn)行所需的參數(shù)遮斥,線(xiàn)程數(shù)量)
def Run_threadpool (function,data,number):
pool = threadpool.ThreadPool(number)
requests = threadpool.makeRequests(function, data)
[pool.putRequest(req) for req in requests]
pool.wait()
6峦失、異常can’t start new thread
我在跑某個(gè)程序時(shí),創(chuàng)建線(xiàn)程池到一個(gè)方法中术吗,這個(gè)方法會(huì)被循環(huán)調(diào)用尉辑,即使局部變量pool被覆蓋,但是之前創(chuàng)建的線(xiàn)程依然存在较屿,所以線(xiàn)程炸了
pool = threadpool.ThreadPool(10)
把上面的代碼放進(jìn)class的構(gòu)造函數(shù)中隧魄,或者保證它只執(zhí)行一次
python中線(xiàn)程的正確用法是卓练,按需創(chuàng)建線(xiàn)程,重復(fù)使用有限的線(xiàn)程