阻塞、非阻塞、同步与异步
阻塞、非阻塞、同步與異步
阻塞與非阻塞
進程運行的三種狀態(tài):運行、就緒、阻塞
阻塞和非阻塞:
? 阻塞:程序運行時,遇到了IO,程序掛起,cpu被切走.
? 非阻塞: 程序沒有遇到IO,程序遇到IO但是我通過某種手段,讓cpu強行運行我的程序.
提交任務(wù)的角度:
? 同步: 提交一個任務(wù),自任務(wù)開始運行直到此任務(wù)結(jié)束(可能有IO),返回一個返回值之后,我在提交下一個任務(wù).
? 異步:一次提交多個任務(wù),然后我就直接執(zhí)行下一行代碼.
同步調(diào)用與異步調(diào)用
同步調(diào)用:
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time import random import osdef task(i):print(f'{os.getpid()}開始任務(wù)')time.sleep(random.randint(1,3))print(f'{os.getpid()}任務(wù)結(jié)束')return i if __name__ == '__main__':# 同步調(diào)用pool = ProcessPoolExecutor()for i in range(10):obj = pool.submit(task,i)# obj是一個動態(tài)對象,返回的當(dāng)前的對象的狀態(tài),有可能運行中,可能(就緒阻塞),還可能是結(jié)束了.# obj.result() 必須等到這個任務(wù)完成后,返回了結(jié)果之后,在執(zhí)行下一個任務(wù).print(f'任務(wù)結(jié)果:{obj.result()}') # 進程執(zhí)行完成后返回結(jié)果pool.shutdown(wait=True)# shutdown: 讓我的主進程等待進程池中所有的子進程都結(jié)束任務(wù)之后,在執(zhí)行. 有點類似與join.# shutdown: 在上一個進程池沒有完成所有的任務(wù)之前,不允許添加新的任務(wù).# 一個任務(wù)是通過一個函數(shù)實現(xiàn)的,任務(wù)完成了他的返回值就是函數(shù)的返回值.print('===主')異步調(diào)用:
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time import random import osdef task(i):print(f'{os.getpid()}開始任務(wù)')time.sleep(random.randint(1,3))print(f'{os.getpid()}任務(wù)結(jié)束')return i if __name__ == '__main__':# 異步調(diào)用pool = ProcessPoolExecutor()for i in range(10):pool.submit(task,i) # 未解決異步調(diào)用返回值問題pool.shutdown(wait=True)print('===主')異步調(diào)用獲取結(jié)果的兩種方式:
? 方式1:統(tǒng)一回收結(jié)果: 任務(wù)結(jié)束后對所有動態(tài)對象取結(jié)果,獲取函數(shù)返回值
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time import random import osdef task(i):print(f'{os.getpid()}開始任務(wù)')time.sleep(random.randint(1,3))print(f'{os.getpid()}任務(wù)結(jié)束')return iif __name__ == '__main__':# 異步調(diào)用pool = ProcessPoolExecutor()l1 = []for i in range(10):obj = pool.submit(task,i)l1.append(obj)pool.shutdown(wait=True)print(l1)for i in l1:print(i.result())print('===主') # 結(jié)果: 12708開始任務(wù) 8632開始任務(wù) 1848開始任務(wù) 14544開始任務(wù) 10704開始任務(wù) 18776開始任務(wù) 18480開始任務(wù) 18548開始任務(wù) 13916開始任務(wù) 17144開始任務(wù) 1848任務(wù)結(jié)束 14544任務(wù)結(jié)束 18548任務(wù)結(jié)束 8632任務(wù)結(jié)束 10704任務(wù)結(jié)束 18480任務(wù)結(jié)束 13916任務(wù)結(jié)束 17144任務(wù)結(jié)束 12708任務(wù)結(jié)束 18776任務(wù)結(jié)束 [<Future at 0x232b4a377b8 state=finished returned int>, <Future at 0x232b4a82c88 state=finished returned int>, <Future at 0x232b4a82d30 state=finished returned int>, <Future at 0x232b4a82dd8 state=finished returned int>, <Future at 0x232b4a82e80 state=finished returned int>, <Future at 0x232b4a82f28 state=finished returned int>, <Future at 0x232b4a8d048 state=finished returned int>, <Future at 0x232b4a8d128 state=finished returned int>, <Future at 0x232b4a8d208 state=finished returned int>, <Future at 0x232b4a8d2e8 state=finished returned int>] 0 1 2 3 4 5 6 7 8 9 ===主? 方式2:異步調(diào)用+回調(diào)函數(shù)
異步調(diào)用+回調(diào)函數(shù)
requests模塊:
瀏覽器工作原理: 服務(wù)端發(fā)送一個請求,服務(wù)端驗證你的請求,如果正確,給你的瀏覽器返回一個文件,瀏覽器接收到文件,將文件里面的代碼渲染成你看到的漂亮美麗的模樣.
爬蟲原理:
1. 利用代碼模擬一個瀏覽器,進行瀏覽器的工作流程得到一堆源代碼.
2. 對源代碼進行數(shù)據(jù)清洗得到我想要數(shù)據(jù).
import requests ret = requests.get('http://www.baidu.com') if ret.status_code == 200:print(ret.text)引入回調(diào)函數(shù)的三個過程:
版本1:
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import requestsdef task(url):content = requests.get(url)return content.textdef parse(obj):return len(obj.result())if __name__ == '__main__':pool = ThreadPoolExecutor(4)url_list = ['http://www.JD.com','http://www.JD.com', 'https://home.cnblogs.com/u/lifangzheng/','https://wizardforcel.gitbooks.io/gopl-zh/content/ch0/ch0-01.html', 'https://www.pypypy.cn/#/','https://www.liaoxuefeng.com/', 'https://home.cnblogs.com/u/lifangzheng/','https://home.cnblogs.com/u/lifangzheng/', 'https://gitee.com/clover16', 'https://gitee.com/clover16']obj_list = []for url in url_list:obj = pool.submit(task,url)obj_list.append(obj)pool.shutdown(wait=True)for res in obj_list:print(parse(res.result())) # 版本一的兩個缺陷: # 1. 異步發(fā)出10個任務(wù),并發(fā)的執(zhí)行,但是統(tǒng)一的接收所有的任務(wù)的返回值.(效率低,不能實時的獲取結(jié)果) # 2. 分析結(jié)果流程是串行,影響效率.版本2:(基于版本一的第二個缺點改進而來)
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import requestsdef task(url):content = requests.get(url)return parse(content.text)def parse(obj):return len(obj.result()) # 嵌套函數(shù),并發(fā)執(zhí)行中分析結(jié)果,增加了函數(shù)的耦合性 # 并發(fā)執(zhí)行任務(wù),每個任務(wù)是通過網(wǎng)頁獲取源碼+數(shù)據(jù)分析,此任務(wù)最好是IO阻塞,才能發(fā)揮最大的效果 if __name__ == '__main__':pool = ThreadPoolExecutor(4)url_list = ['http://www.JD.com','http://www.JD.com', 'https://home.cnblogs.com/u/lifangzheng/','https://wizardforcel.gitbooks.io/gopl-zh/content/ch0/ch0-01.html', 'https://www.pypypy.cn/#/','https://www.liaoxuefeng.com/', 'https://home.cnblogs.com/u/lifangzheng/','https://home.cnblogs.com/u/lifangzheng/', 'https://gitee.com/clover16', 'https://gitee.com/clover16']obj_list = []for url in url_list:obj = pool.submit(task,url)obj_list.append(obj)pool.shutdown(wait=True)for res in obj_list:print(parse(res.result()))版本3:
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import requestsdef task(url):content = requests.get(url)return content.textdef parse(obj):print(len(obj.result()))if __name__ == '__main__':pool = ThreadPoolExecutor(4)url_list = ['http://www.JD.com','http://www.JD.com', 'https://home.cnblogs.com/u/lifangzheng/','https://wizardforcel.gitbooks.io/gopl-zh/content/ch0/ch0-01.html', 'https://www.pypypy.cn/#/','https://www.liaoxuefeng.com/', 'https://home.cnblogs.com/u/lifangzheng/','https://home.cnblogs.com/u/lifangzheng/', 'https://gitee.com/clover16', 'https://gitee.com/clover16']for url in url_list:obj = pool.submit(task,url)obj.add_done_callback(parse) # add_done_callback函數(shù)無返回值# 線程發(fā)布后,由空閑線程執(zhí)行回調(diào)函數(shù)PS:異步處理IO類型,回調(diào)處理非IO類型
異步調(diào)用和回調(diào)函數(shù)的關(guān)系?
異步站在發(fā)布任務(wù)的角度,回調(diào)站在接收結(jié)果的角度: 回調(diào)函數(shù) 按順序接收每個任務(wù)的結(jié)果,進行下一步處理.
線程池+回調(diào)函數(shù)和進程池+回調(diào)函數(shù)的小區(qū)別:
進程池+回調(diào): 回調(diào)函數(shù)由主進程去執(zhí)行,線程池+回調(diào): 回到函數(shù)由空閑的線程去執(zhí)行.
轉(zhuǎn)載于:https://www.cnblogs.com/lifangzheng/p/11415016.html
總結(jié)
以上是生活随笔為你收集整理的阻塞、非阻塞、同步与异步的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 递归锁、信号量、GIL锁、基于多线程的s
- 下一篇: 线程queue、事件event及协程