Python 37 进程池与线程池 、 协程
一:進程池與線程池
提交任務的兩種方式:
1、同步調用:提交完一個任務之后,就在原地等待,等任務完完整整地運行完畢拿到結果后,再執行下一行代碼,會導致任務是串行執行
2、異步調用:提交完一個任務之后,不是原地等待,而是直接執行下一行代碼,會導致任務是并發執行的,結果future對象會在任務運行完畢后自動傳給回調函數
?
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor import time, random, osdef task(name, n):print('%s%s is running' % (name, os.path.getpid()))time.sleep(random.randint(1, 3))return n ** 2if __name__ == '__main__':# print(os.cpu_count())p = ProcessPoolExecutor(4)l = []for i in range(5):# 同步提交# res = p.submit(task, '進程pid:', i).result()# print(res)# 異步提交future=p.submit(task,'進程pid:',i)l.append(future)p.shutdown(wait=True) # 關閉進程池的入口,并且在原地等待進程池內所有任務運行完畢for future in l:print(future.result)print('主') View Code from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time,random,os import requestsdef get(url):print('%s GET %s' %(os.getpid(),url))time.sleep(3)response=requests.get(url)if response.status_code == 200:res=response.textelse:res='下載失敗'parse(res)def parse(res):time.sleep(1)print('%s 解析結果為%s' %(os.getpid(),len(res)))if __name__ == '__main__':urls=['https://www.baidu.com','https://www.sina.com.cn','https://www.tmall.com','https://www.jd.com','https://www.python.org','https://www.openstack.org','https://www.baidu.com','https://www.baidu.com','https://www.baidu.com',]p=ProcessPoolExecutor(9)l=[]start=time.time()for url in urls:future=p.submit(get,url)l.append(future)p.shutdown(wait=True)print('主',time.time()-start) View Code from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time,random,os import requestsdef get(ur1):print('%s GET %s'%(os.getpid(),ur1))time.sleep(3)response=requests.get(ur1)if response.status_code==200:res=response.textelse:res='下載失敗'parse(res)def parse(res):time.sleep(1)print('%s 解析結果為%s'%(os.getpid(),len(res)))if __name__ == '__main__':urls=['https://www.baidu.com''https://www.youku.com''https://www.wangyiyun.com''https://www.baidu.com''https://www.baidu.com''https://www.baidu.com']p=ProcessPoolExecutor(9)l=[]start=time.time()for url in urls:future=p.submit(get,url)l.append(future)p.shutdown(wait=True)print('主',time.time()-start) View Code from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor from threading import current_thread import time, random, os import requsetsdef get(url):print('%s GET %s' % (current_thread().name, url))time.sleep(3)respose = requsets.get(url)if respose.status_code == 200:res = respose.textelse:res = '下載失敗'return resdef parse(future):time.sleep(1)res = future.result()print('%s 解析結果為%s' % (current_thread().name, len(res)))if __name__ == '__main__':urls = ['https://www.baidu.com''https://www.youku.com''https://www.wangyiyun.com''https://www.baidu.com''https://www.baidu.com''https://www.baidu.com']p = ProcessPoolExecutor(9)start = time.time()for url in urls:future = p.submit(get, url)# 異步調用:提交完一個任務之后,不是原地等待,# 而是直接執行下一行代碼,會導致任務是并發執行的,# 結果future對象會在任務運行完畢后自動傳給回調函數future.add_done_callback(parse) # parse會在任務運行完畢后自動觸發,然后接收一個參數future對象 p.shutdown(wait=True)print('主', time.time() - start)print('主', os.getpid()) View Code from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from threading import current_thread import time,random,os import requestsdef get(url):print('%s GET %s'%(current_thread().name,url))time.sleep(3)response=requests.get(url)if response.status_code==200:res=response.textelse:res='下載失敗'return resdef parse(future):time.sleep(1)res=future.result()print('%s 解析結果為%s'%(current_thread().name,len(res)))if __name__ == '__main__':urls = ['https://www.baidu.com''https://www.youku.com''https://www.wangyiyun.com''https://www.baidu.com''https://www.baidu.com''https://www.baidu.com']p=ThreadPoolExecutor(4)for url in urls:future=p.submit(get,url)future.add_done_callback(parse)p.shutdown(wait=True)print('主',current_thread().name) View Code?
二:協程
協程介紹
協程是單線程下的并發,又稱微線程,英文名 Coroutine
一句話說明什么是線程:協程是一種后能耗態的輕量級線程,即協程是由用戶程序自己控制調度的。
需要強調的是:
#1. python的線程屬于內核級別的,即由操作系統控制調度(如單線程遇到io或執行時間過長就會被迫交出cpu執行權限,切換其他線程運行) #2. 單線程內開啟協程,一旦遇到io,就會從應用程序級別(而非操作系統)控制切換,以此來提升效率(!!!非io操作的切換與效率無關)對比操作系統控制線程的切換,用戶在單線程內控制協程的切換
優點如下:
#1. 協程的切換開銷更小,屬于程序級別的切換,操作系統完全感知不到,因而更加輕量級 #2. 單線程內就可以實現并發的效果,最大限度地利用cpu缺點如下:
#1. 協程的本質是單線程下,無法利用多核,可以是一個程序開啟多個進程,每個進程內開啟多個線程,每個線程內開啟協程 #2. 協程指的是單個線程,因而一旦協程出現阻塞,將會阻塞整個線程總結協程特點:
1、必須在只有一個單線程里實現并發
2、修改共享數據不需要加鎖
3、用戶程序里總結保存多個控制流的上下文棧
4、附加:一個協程遇到IO操作自動切換到其它協程(如何實現檢測IO,yield,greenlet都無法實現,就用到了gevent模塊(select機制))
?
基于單線程下實現并發,只有一個主線程(如下圖:可利用的CPU只有一個)的情況下實現并發,并發的本質:切換+保存狀態
CPU正在運行一個任務,會在兩種情況下自習其他任務(切換由操作系統強制控制),一種情況是該任務發生了阻塞,另外一種情況是該任務占用時間過長或有一個優先級更高的程序代替了它
#串行執行 import time def func1():for i in range(10000):i+1def func2():for i in range(10000):i+1start=time.time() func1() func2() stop=time.time() print(stop -start) 串行執行?
#1 yiled可以保存狀態,yield的狀態保存與操作系統的保存線程狀態很像,但是yield是代碼級別控制的,更輕量級 #2 send可以把一個函數的結果傳給另外一個函數,以此實現單線程內程序之間的切換?
#基于yield并發執行 import time def func1():while True:print('func1')10000+1yielddef func2():g=func1()for i in range(10000):print('func2')time.sleep(100)i+1next(g)start=time.time() func2() stop=time.time() print(stop-start) yield并發執行?ps:在介紹進程理論時,提及進程的三種執行狀態,而線程才是執行單位,所以可以將上圖理解為線程的三種狀態
?
轉載于:https://www.cnblogs.com/zedong/p/9622750.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Python 37 进程池与线程池 、 协程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java MyEclipse 实现微信跳
- 下一篇: Python 实现微信小程序的用户登录