欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

python多線程并發(fā)實(shí)例及其優(yōu)化

系統(tǒng) 1615 0

單線程執(zhí)行

python的內(nèi)置模塊提供了兩個(gè)內(nèi)置模塊:thread和threading,thread是源生模塊,threading是擴(kuò)展模塊,在thread的基礎(chǔ)上進(jìn)行了封裝及改進(jìn)。所以只需要使用threading這個(gè)模塊就能完成并發(fā)的測試

實(shí)例

創(chuàng)建并啟動一個(gè)單線程

            
import threading
def myTestFunc():
print("我是一個(gè)函數(shù)")
t = threading.Thread(target=myTestFunc) # 創(chuàng)建一個(gè)線程
t.start() # 啟動線程
          

執(zhí)行結(jié)果

            
C:\Python36\python.exe D:/MyThreading/myThread.py
我是一個(gè)線程函數(shù)
Process finished with exit code 0
          

其實(shí)單線程的執(zhí)行結(jié)果和單獨(dú)執(zhí)行某一個(gè)或者某一組函數(shù)結(jié)果是一樣的,區(qū)別只在于用線程的方式執(zhí)行函數(shù),而線程是可以同時(shí)執(zhí)行多個(gè)的,函數(shù)是不可以同時(shí)執(zhí)行的。

多線程執(zhí)行

上面介紹了單線程如何使用,多線程只需要通過循環(huán)創(chuàng)建多個(gè)線程,并循環(huán)啟動線程執(zhí)行就可以了

實(shí)例

            
import threading
from datetime import datetime
def thread_func(): # 線程函數(shù)
  print('我是一個(gè)線程函數(shù)', datetime.now())
def many_thread():
  threads = []
  for _ in range(10): # 循環(huán)創(chuàng)建10個(gè)線程
    t = threading.Thread(target=thread_func)
    threads.append(t)
  for t in threads: # 循環(huán)啟動10個(gè)線程
    t.start()
if __name__ == '__main__':
  many_thread()
          

執(zhí)行結(jié)果

            
C:\Python36\python.exe D:/MyThreading/manythread.py
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.205146
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.205146
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.206159
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.206159
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.206159
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.207139
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.207139
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.207139
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.208150
我是一個(gè)線程函數(shù) 2019-06-23 16:54:58.208150
Process finished with exit code 0
          

通過循環(huán)創(chuàng)建10個(gè)線程,并且執(zhí)行了10次線程函數(shù),但需要注意的是python的并發(fā)并非絕對意義上的同時(shí)處理,因?yàn)閱泳€程是通過循環(huán)啟動的,還是有先后順序的,通過執(zhí)行結(jié)果的時(shí)間可以看出還是有細(xì)微的差異,但可以忽略不記。當(dāng)然如果線程過多就會擴(kuò)大這種差異。我們啟動500個(gè)線程看下程序執(zhí)行時(shí)間

實(shí)例

            
import threading
from datetime import datetime
def thread_func(): # 線程函數(shù)
print('我是一個(gè)線程函數(shù)', datetime.now())
def many_thread():
threads = []
for _ in range(500): # 循環(huán)創(chuàng)建500個(gè)線程
t = threading.Thread(target=thread_func)
threads.append(t)
for t in threads: # 循環(huán)啟動500個(gè)線程
t.start()
if __name__ == '__main__':
start = datetime.today().now()
many_thread()
duration = datetime.today().now() - start
print(duration)
          

執(zhí)行結(jié)果

            
0:00:00.111657
Process finished with exit code 0
          

500個(gè)線程共執(zhí)行了大約0.11秒

那么針對這種問題我們該如何優(yōu)化呢?我們可以創(chuàng)建25個(gè)線程,每個(gè)線程執(zhí)行20次線程函數(shù),這樣在啟動下一個(gè)線程的時(shí)候,上一個(gè)線程已經(jīng)在循環(huán)執(zhí)行了,這樣就大大減少了并發(fā)的時(shí)間差異

優(yōu)化

            
import threading
from datetime import datetime
def thread_func(): # 線程函數(shù)
print('我是一個(gè)線程函數(shù)', datetime.now())
def execute_func():
for _ in range(20):
thread_func()
def many_thread():
start = datetime.now()
threads = []
for _ in range(25): # 循環(huán)創(chuàng)建500個(gè)線程
t = threading.Thread(target=execute_func)
threads.append(t)
for t in threads: # 循環(huán)啟動500個(gè)線程
t.start()
duration = datetime.now() - start
print(duration)
if __name__ == '__main__':
many_thread()
          

輸出結(jié)果 (僅看程序執(zhí)行間隔)

            
0:00:00.014959
Process finished with exit code 0
          

后面的優(yōu)化執(zhí)行500次并發(fā)一共花了0.014秒。比未優(yōu)化前的500個(gè)并發(fā)快了幾倍,如果線程函數(shù)的執(zhí)行時(shí)間比較長的話,那么這個(gè)差異會更加顯著,所以大量的并發(fā)測試建議使用后者,后者比較接近同時(shí)“并發(fā)”

守護(hù)線程

多線程還有一個(gè)重要概念就是守護(hù)線程。那么在這之前我們需要知道主線程和子線程的區(qū)別,之前創(chuàng)建的線程其實(shí)都是main()線程的子線程,即先啟動主線程main(),然后執(zhí)行線程函數(shù)子線程。

那么什么是守護(hù)線程?即當(dāng)主線程執(zhí)行完畢之后,所有的子線程也被關(guān)閉(無論子線程是否執(zhí)行完成)。默認(rèn)不設(shè)置的情況下是沒有守護(hù)線程的,主線程執(zhí)行完畢后,會等待子線程全部執(zhí)行完畢,才會關(guān)閉結(jié)束程序。

但是這樣會有一個(gè)弊端,當(dāng)子線程死循環(huán)了或者一直處于等待之中,則程序?qū)⒉粫魂P(guān)閉,被被無限掛起,我們把上述的線程函數(shù)改成循環(huán)10次, 并睡眠2秒,這樣效果會更明顯

            
import threading
from datetime import datetime
import time
def thread_func(): # 線程函數(shù)
   time.sleep(2)
i = 0
while(i < 11):
print(datetime.now())
i += 1
def many_thread():
threads = []
for _ in range(10): # 循環(huán)創(chuàng)建500個(gè)線程
t = threading.Thread(target=thread_func)
threads.append(t)
for t in threads: # 循環(huán)啟動500個(gè)線程
t.start()
if __name__ == '__main__':
many_thread()
print("thread end")
          

執(zhí)行結(jié)果

            
C:\Python36\python.exe D:/MyThreading/manythread.py
thread end
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.468612
2019-06-23 19:08:00.469559
2019-06-23 19:08:00.469559
2019-06-23 19:08:00.469559
2019-06-23 19:08:00.469559
2019-06-23 19:08:00.469559
2019-06-23 19:08:00.469559
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.470556
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.471554
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.472557
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.473548
2019-06-23 19:08:00.474545
2019-06-23 19:08:00.474545
2019-06-23 19:08:00.474545
2019-06-23 19:08:00.474545
2019-06-23 19:08:00.474545
2019-06-23 19:08:00.474545
2019-06-23 19:08:00.474545
2019-06-23 19:08:00.475552
2019-06-23 19:08:00.475552
2019-06-23 19:08:00.475552
2019-06-23 19:08:00.475552
2019-06-23 19:08:00.475552
2019-06-23 19:08:00.475552
2019-06-23 19:08:00.475552
2019-06-23 19:08:00.475552
2019-06-23 19:08:00.475552
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.476548
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
2019-06-23 19:08:00.477546
Process finished with exit code 0
          

根據(jù)上述結(jié)果可以看到主線程打印了“thread end”之后(主線程結(jié)束),子線程還在繼續(xù)執(zhí)行,并未隨著主線程的結(jié)束而結(jié)束

下面我們通過 setDaemon方法給子線程添加守護(hù)線程,我們把循環(huán)改為死循環(huán),再來看看輸出結(jié)果(注意守護(hù)線程要加在start之前)

            
import threading
from datetime import datetime
def thread_func(): # 線程函數(shù)
i = 0
while(1):
print(datetime.now())
i += 1
def many_thread():
threads = []
for _ in range(10): # 循環(huán)創(chuàng)建500個(gè)線程
t = threading.Thread(target=thread_func)
threads.append(t)
t.setDaemon(True) # 給每個(gè)子線程添加守護(hù)線程
for t in threads: # 循環(huán)啟動500個(gè)線程
t.start()

if __name__ == '__main__':
many_thread()
print("thread end")
          

輸出結(jié)果

            
2019-06-23 19:12:35.564539
2019-06-23 19:12:35.564539
2019-06-23 19:12:35.564539
2019-06-23 19:12:35.564539
2019-06-23 19:12:35.564539
2019-06-23 19:12:35.564539
2019-06-23 19:12:35.565529
2019-06-23 19:12:35.565529
2019-06-23 19:12:35.565529
thread end
Process finished with exit code 0
          

通過結(jié)果我們可以發(fā)現(xiàn),主線程關(guān)閉之后子線程也會隨著關(guān)閉,并沒有無限的循環(huán)下去,這就像程序執(zhí)行到一半強(qiáng)制關(guān)閉執(zhí)行一樣,看似暴力卻很有用,如果子線程發(fā)送一個(gè)請求未收到請求結(jié)果,那不可能永遠(yuǎn)等下去,這時(shí)候就需要強(qiáng)制關(guān)閉。所以守護(hù)線程解決了主線程和子線程關(guān)閉的問題。

阻塞線程

上面說了守護(hù)線程的作用,那么有沒有別的方法來解決上述問題呢? 其實(shí)是有的,那就是阻塞線程,這種方式更加合理,使用join()方法阻塞線程,讓主線程等待子線程執(zhí)行完成之后再往下執(zhí)行,再關(guān)閉所有子線程,而不是只要主線程結(jié)束,不管子線程是否執(zhí)行完成都終止子線程執(zhí)行。下面我們給子線程添加上join()(主要join要加到start之后)

            
import threading
from datetime import datetime
import time
def thread_func(): # 線程函數(shù)
time.sleep(1)
i = 0
while(i < 11):
print(datetime.now())
i += 1
def many_thread():
threads = []
for _ in range(10): # 循環(huán)創(chuàng)建500個(gè)線程
t = threading.Thread(target=thread_func)
threads.append(t)
t.setDaemon(True) # 給每個(gè)子線程添加守護(hù)線程
for t in threads: # 循環(huán)啟動500個(gè)線程
t.start()
for t in threads:
t.join() # 阻塞線程
if __name__ == '__main__':
many_thread()
print("thread end")
          

執(zhí)行結(jié)果

程序會一直執(zhí)行,但是不會打印“thread end”語句,因?yàn)樽泳€程并未結(jié)束,那么主線程就會一直等待。

疑問:有人會覺得這和什么都不設(shè)置是一樣的,其實(shí)會有一點(diǎn)區(qū)別的,從守護(hù)線程和線程阻塞的定義就可以看出來,如果什么都沒設(shè)置,那么主線程會先執(zhí)行完畢打印后面的“thread end”,而等待子線程執(zhí)行完畢。兩個(gè)都設(shè)置了,那么主線程會等待子線程執(zhí)行結(jié)束再繼續(xù)執(zhí)行。

而對于死循環(huán)或者一直等待的情況,我們可以給join設(shè)置超時(shí)等待,我們設(shè)置join的參數(shù)為2,那么子線程會告訴主線程讓其等待2秒,如果2秒內(nèi)子線程執(zhí)行結(jié)束主線程就繼續(xù)往下執(zhí)行,如果2秒內(nèi)子線程未結(jié)束,主線程也會繼續(xù)往下執(zhí)行,執(zhí)行完成后關(guān)閉子線程

輸出結(jié)果

            
import threading
from datetime import datetime
import time
def thread_func(): # 線程函數(shù)
time.sleep(1)
i = 0
while(1):
print(datetime.now())
i += 1
def many_thread():
threads = []
for _ in range(10): # 循環(huán)創(chuàng)建500個(gè)線程
t = threading.Thread(target=thread_func)
threads.append(t)
t.setDaemon(True) # 給每個(gè)子線程添加守護(hù)線程
for t in threads: # 循環(huán)啟動500個(gè)線程
t.start()
for t in threads:
t.join(2) # 設(shè)置子線程超時(shí)2秒
if __name__ == '__main__':
many_thread()
print("thread end")
          

你運(yùn)行程序后會發(fā)現(xiàn),運(yùn)行了大概2秒的時(shí)候,程序會數(shù)據(jù)“thread end” 然后結(jié)束程序執(zhí)行, 這就是阻塞線程的意義,控制子線程和主線程的執(zhí)行順序

總結(jié)

最好呢,再次說一下守護(hù)線程和阻塞線程的定義

  • 守護(hù)線程:子線程會隨著主線程的結(jié)束而結(jié)束,無論子線程是否執(zhí)行完畢
  • 阻塞線程:主線程會等待子線程的執(zhí)行結(jié)束,才繼續(xù)執(zhí)行

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久中文字幕久久久久91 | 久久久久久久 | 日韩hd| 国产精品免费视频网站 | 亚洲第一区第二区 | 国产精品美女久久久久久久久久久 | 精品国产一区二区亚洲人成毛片 | 久久精品国产免费观看99 | 色玖玖| 91久久精品日日躁夜夜躁国产 | 日韩激情中文字幕一区二区 | av中文在线观看 | 日日摸狠狠的摸夜夜摸 | 奇米狠狠操 | 国产亚洲欧美一区 | 久久久久久亚洲 | 亚洲国产中文字幕在线观看 | 韩国精品免费视频 | 久久香蕉综合精品国产 | 国产精品精品视频一区二区三区 | 国产精品片一区二区三区 | 成人免费大片黄在线播放 | 国产精品69久久久久水密桃 | 欧美区一区二区三 | 青娱乐激情视频 | 国产精品国产三级国产a | 久久久精品久久视频只有精品 | 久草网站 | 狠狠狠狠狠狠 | 热99re久久精品2久久久 | 国产色在线 | 亚洲精品久久久久一区二区 | 一区二区三区 日韩 | 91水蜜桃| 激情六月综合 | 欧美线在线精品观看视频 | 性爽爽| 久久久精品免费热线观看 | 久久91综合国产91久久精品 | 无码AV免费一区二区三区A片 | 亚洲国产成人va在线观看网址 |