阻塞,非阻塞,同步,異步html
進程運行的三個狀態: 運行,就緒,阻塞.編程
執行的角度:瀏覽器
阻塞: 程序運行時,遇到了IO,程序掛起,cpu被切走.併發
非阻塞: 程序沒有遇到IO,程序遇到IO可是我經過某種手段,讓cpu強行運行個人程序.app
提交任務的角度:dom
同步: 提交一個任務,自任務開始運行直到此任務結束(可能有IO),返回一個返回值以後,我在提交下一個任務.異步
異步: 一次提交多個任務,而後我就直接執行下一行代碼.函數
返回結果如何回收?url
給三個老師發佈任務:線程
同步: 先告知第一個老師完成寫書的任務,我從原地等待,等他兩天以後完成了,告訴完事了,我在發佈下一個任務......
異步:
直接將三個任務告知三個老師,我就忙個人我,直到三個老師完成以後,告知我.
同步調用,異步調用
1. 異步調用 # 異步調用返回值如何接收? 未解決. from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time import random import os def task(i): print(f'{os.getpid()}開始任務') time.sleep(random.randint(1,3)) print(f'{os.getpid()}任務結束') return i if __name__ == '__main__': # 異步調用 pool = ProcessPoolExecutor() for i in range(10): pool.submit(task,i) pool.shutdown(wait=True) # shutdown: 讓個人主進程等待進程池中全部的子進程都結束任務以後,在執行. 有點相似與join. # shutdown: 在上一個進程池沒有完成全部的任務以前,不容許添加新的任務. # 一個任務是經過一個函數實現的,任務完成了他的返回值就是函數的返回值. print('===主') # 2. 同步調用 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time import random import os def task(i): print(f'{os.getpid()}開始任務') time.sleep(random.randint(1,3)) print(f'{os.getpid()}任務結束') return i if __name__ == '__main__': # 同步調用 pool = ProcessPoolExecutor() for i in range(10): obj = pool.submit(task,i) # obj是一個動態對象,返回的當前的對象的狀態,有可能運行中,可能(就緒阻塞),還多是結束了. # obj.result() 必須等到這個任務完成後,返回告終果以後,在執行下一個任務. print(f'任務結果:{obj.result()}') pool.shutdown(wait=True) # shutdown: 讓個人主進程等待進程池中全部的子進程都結束任務以後,在執行. 有點相似與join. # shutdown: 在上一個進程池沒有完成全部的任務以前,不容許添加新的任務. # 一個任務是經過一個函數實現的,任務完成了他的返回值就是函數的返回值. print('===主') # 3 異步如何取結果??? # 方式一: 異步調用,統一回收結果. # from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # import time # import random # import os # # def task(i): # print(f'{os.getpid()}開始任務') # time.sleep(random.randint(1,3)) # print(f'{os.getpid()}任務結束') # return i # # if __name__ == '__main__': # # # 異步調用 # 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('===主') # 統一回收結果: 我不能立刻收到任何一個已經完成的任務的返回值,我只能等到全部的任務所有結束統一回收. # 第二種方式: from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time import random import os def task(i): print(f'{os.getpid()}開始任務') time.sleep(random.randint(1,3)) print(f'{os.getpid()}任務結束') return i if __name__ == '__main__': # 異步調用 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('===主')
異步調用+回調函數
瀏覽器工做原理, 向服務端發送一個請求,服務端驗證你的請求,若是正確,給你的瀏覽器返回一個文件, # 瀏覽器接收到文件,將文件裏面的代碼渲染成你看到的漂亮美麗的模樣. # 什麼叫爬蟲? # 1. 利用代碼模擬一個瀏覽器,進行瀏覽器的工做流程獲得一堆源代碼. # 2. 對源代碼進行數據清洗獲得我想要數據. # import requests # ret = requests.get('http://www.baidu.com') # if ret.status_code == 200: # print(ret.text) """ # 版本一: # from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # import time # import random # import os # import requests # # # def task(url): # '''模擬的就是爬取多個源代碼 必定有IO操做''' # ret = requests.get(url) # if ret.status_code == 200: # return ret.text # # def parse(content): # '''模擬對數據進行分析 通常沒有IO''' # return len(content) # # # if __name__ == '__main__': # '''串行 耗費時間長,不可取 # ret = task('http://www.baidu.com') # print(parse(ret)) # # ret = task('http://www.JD.com') # print(parse(ret)) # # ret = task('http://www.taobao.com') # print(parse(ret)) # # ret = task('https://www.cnblogs.com/jin-xin/articles/7459977.html') # print(parse(ret)) # # ''' # # 開啓線程池,併發並行的執行 # url_list = [ # 'http://www.baidu.com', # 'http://www.JD.com', # 'http://www.JD.com', # 'http://www.JD.com', # 'http://www.taobao.com', # 'https://www.cnblogs.com/jin-xin/articles/7459977.html', # 'https://www.luffycity.com/', # 'https://www.cnblogs.com/jin-xin/articles/9811379.html', # 'https://www.cnblogs.com/jin-xin/articles/11245654.html', # 'https://www.sina.com.cn/', # # ] # pool = ThreadPoolExecutor(4) # 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())) # # ''' # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) # parse(res.result()) ''' # print('===主') ''' # 版本一: # 1. 異步發出10個任務,併發的執行,可是統一的接收全部的任務的返回值.(效率低,不能實時的獲取結果) # 2. 分析結果流程是串行,影響效率. # for res in obj_list: # print(parse(res.result())) ''' # 版本二: 針對版本一的缺點2,改進,讓串行編程併發或者並行. # from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor # import time # import random # import os # import requests # # # def task(url): # '''模擬的就是爬取多個源代碼 必定有IO操做''' # ret = requests.get(url) # if ret.status_code == 200: # return parse(ret.text) # # # def parse(content): # '''模擬對數據進行分析 通常沒有IO''' # return len(content) # # # if __name__ == '__main__': # # # 開啓線程池,併發並行的執行 # url_list = [ # 'http://www.baidu.com', # 'http://www.JD.com', # 'http://www.JD.com', # 'http://www.JD.com', # 'http://www.taobao.com', # 'https://www.cnblogs.com/jin-xin/articles/7459977.html', # 'https://www.luffycity.com/', # 'https://www.cnblogs.com/jin-xin/articles/9811379.html', # 'https://www.cnblogs.com/jin-xin/articles/11245654.html', # 'https://www.sina.com.cn/', # # ] # pool = ThreadPoolExecutor(4) # obj_list = [] # for url in url_list: # obj = pool.submit(task, url) # obj_list.append(obj) # ''' # # 1 在開一個線程進程池,併發並行的處理. 再開一個線程進程池,開銷大. # # 2 將原來的任務擴大, # 版本一: # 線程池設置4個線程, 異步發起10個任務,每一個任務是經過網頁獲取源碼, 併發執行, # 最後統一用列表回收10個任務, 串行着分析源碼. # 版本二: # 線程池設置4個線程, 異步發起10個任務,每一個任務是經過網頁獲取源碼+數據分析, 併發執行, # 最後將全部的結果展現出來. # 耦合性加強了. # 併發執行任務,此任務最好是IO阻塞,才能發揮最大的效果 # ''' # pool.shutdown(wait=True) # for res in obj_list: # [obj1, obj2,obj3....obj10] # print(res.result()) # """ # 版本三: # 基於 異步調用回收全部任務的結果我要作到實時回收結果, # 併發執行任務每一個任務只是處理IO阻塞的,不能增長新得功能. # 異步調用 + 回調函數 from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor import time import random import os import requests def task(url): '''模擬的就是爬取多個源代碼 必定有IO操做''' ret = requests.get(url) if ret.status_code == 200: return ret.text def parse(obj): '''模擬對數據進行分析 通常沒有IO''' print(len(obj.result())) if __name__ == '__main__': # 開啓線程池,併發並行的執行 url_list = [ 'http://www.baidu.com', 'http://www.JD.com', 'http://www.JD.com', 'http://www.JD.com', 'http://www.taobao.com', 'https://www.cnblogs.com/jin-xin/articles/7459977.html', 'https://www.luffycity.com/', 'https://www.cnblogs.com/jin-xin/articles/9811379.html', 'https://www.cnblogs.com/jin-xin/articles/11245654.html', 'https://www.sina.com.cn/', ] pool = ThreadPoolExecutor(4) for url in url_list: obj = pool.submit(task, url) obj.add_done_callback(parse) ''' 線程池設置4個線程, 異步發起10個任務,每一個任務是經過網頁獲取源碼, 併發執行, 當一個任務完成以後,將parse這個分析代碼的任務交由剩餘的空閒的線程去執行,你這個線程繼續去處理其餘任務. 若是進程池+回調: 回調函數由主進程去執行. 若是線程池+回調: 回到函數由空閒的線程去執行. ''' # 異步 回調是一回事兒? # 異步站在發佈任務的角度, # 站在接收結果的角度: 回調函數 按順序接收每一個任務的結果,進行下一步處理. # 異步 + 回調: # 異步處理的IO類型. # 回調處理非Io