同步調用 異步調用+回調機制

1 同步調用 異步調用+回調機制    提交任務的兩種方式:    什麼是同步異步    任務執行的三種狀態:        同步調用vs阻塞,兩種不一樣的'等'的效果    異步回調  ******        什麼是異步回調?        爲何須要回調?(好比 燒水壺,水燒開後 水壺會發出響聲)        注意點:            回調函數何時被執行?            誰在執行回調函數?            線程的異步回調同步:    #所謂同步,就是在發出一個功能調用時,在沒有獲得結果以前,該調用就不會返回。    按照這個定義,其實絕大多數函數都是同步調用。可是通常而言,    咱們在說同步、異步的時候,特指那些須要其餘部件協做或者須要必定時間完成的任務。#舉例:    #1. multiprocessing.Pool下的apply #發起同步調用後,就在原地等着任務結束,                根本不考慮任務是在計算仍是在io阻塞,總之就是一股腦地等任務結束    #2. concurrent.futures.ProcessPoolExecutor().submit(func,).result()    #3. concurrent.futures.ThreadPoolExecutor().submit(func,).result()異步:    #異步的概念和同步相對。當一個異步功能調用發出後,調用者不能馬上獲得結果。    當該異步功能完成後,經過狀態、通知或回調來通知調用者。若是異步功能用狀態來通知,    那麼調用者就須要每隔必定時間檢查一次,效率就很低    (有些初學多線程編程的人,總喜歡用一個循環去檢查某個變量的值,這實際上是一 種很嚴重的錯誤)。    若是是使用通知的方式,效率則很高,由於異步功能幾乎不須要作額外的操做。至於回調函數,其實和通知沒太多區別。#舉例:    #1. multiprocessing.Pool().apply_async() #發起異步調用後,並不會等待任務結束才返回,            相反,會當即獲取一個臨時結果(並非最終的結果,多是封裝好的一個對象)。    #2. concurrent.futures.ProcessPoolExecutor(3).submit(func,)    #3. concurrent.futures.ThreadPoolExecutor(3).submit(func,)阻塞:    #阻塞調用是指調用結果返回以前,當前線程會被掛起(如遇到io操做)。    函數只有在獲得結果以後纔會將阻塞的線程激活。有人也許會把阻塞調用和同步調用等同起來,    實際上他是不一樣的。對於同步調用來講,不少時候當前線程仍是激活的,只是從邏輯上當前函數沒有返回而已。#舉例:    #1. 同步調用:apply一個累計1億次的任務,該調用會一直等待,        直到任務返回結果爲止,但並未阻塞住(即使是被搶走cpu的執行權限,那也是處於就緒態);    #2. 阻塞調用:當socket工做在阻塞模式的時候,        若是沒有數據的狀況下調用recv函數,則當前線程就會被掛起,直到有數據爲止。非阻塞:    #非阻塞和阻塞的概念相對應,指在不能馬上獲得結果以前也會馬上返回,同時該函數不會阻塞當前線程。小結:#1. 同步與異步針對的是函數/任務的調用方式:同步就是當一個進程發起一個函數(任務)調用的時候,    一直等到函數(任務)完成,而進程繼續處於激活狀態。而異步狀況下是當一個進程發起一個函數(任務)調用的時候,    不會等函數返回,而是繼續往下執行當,函數返回的時候經過狀態、通知、事件等方式通知進程任務完成。#2. 阻塞與非阻塞針對的是進程或線程:阻塞是當請求不能知足的時候就將進程掛起,而非阻塞則不會阻塞當前進程2.線程隊列 ***    隊列    堆棧    優先級隊列三、單線程下實現併發(***)      什麼是協程            併發            併發實現的本質=切換+保存狀態(兩類切換)        高性能分析:        爲何須要協程        如何實現協程(三種)        協程的應用場景:        總結點:====================================1 同步調用 異步調用+回調機制    提交任務的兩種方式:        同步調用 :提交任務必須等待任務完成,才能執行下一行        異步調用 :提交任務不須要等待任務完成,當即執行下一行    線程任務執行的三種狀態:        阻塞            阻塞   遇到了IO操做  失去了CPU的執行權        非阻塞:            就緒            運行            同步調用vs阻塞,兩種不一樣的'等'的效果                同步調用的等 好比通過上千億次計算,運行時間過長致使,被操做系統拿走執行權限,處於就緒態,非阻塞                阻塞的等 好比通過IO操做,sleep了100秒,這是阻塞    異步回調  ******        什麼是異步回調?            發起了一個異步任務 子線程或子進程任務完成後 調用一個函數來通知任務發起方        爲何須要回調?(好比 燒水壺,水燒開後 水壺會發出響聲)            因爲任務是異步執行 任務發起方不知道啊何時完成            因此使用回調的方式告訴發起方任務執行結果 其餘方式也能夠將數據交還給主進程            1.shutdown  主進程會等到全部任務完成  # 相似於join的功能pool.shutdown(wait=True)            2.result函數 會阻塞直到任務完成            都會阻塞  致使效率下降 因此使用回調        注意點:            回調函數何時被執行? 子進程任務完成時            誰在執行回調函數? 主進程            線程的異步回調:                使用方式都相同  惟一的不一樣是執行回調函數 是子線程在執行            from  concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor            pool = ThreadPoolExecutor()            def get_data_task(url):                return text            def parser_data(f):                print(f.result())            if __name__ == '__main__':                f = pool.submit(get_data_task,url)  #get_data_task生產數據                f.add_done_callback(parser_data)  #parser_data處理數據2.線程隊列 *** 見38複習    隊列    堆棧    優先級隊列三、單線程下實現併發(***)      什麼是協程:              單線程下實現併發,在應用程序級別實現多個任務之間切換+保存狀態            併發:看起來是同時運行            併發實現的本質=切換+保存狀態            切換:                一、遇到IO阻塞會切換(能夠提高運行效率)                二、佔用cpu時間過長或者有一個優先級更高的任務搶走了cpu           優勢:                1.協程的切換開銷更小,屬於程序級別的切換,操做系統徹底感知不到,由於更加輕量級                2.單線程內就能夠實現併發的效果,最大限度地利用cpu           缺點:                1.協程的本質是單線程下,沒法利用多核,能夠是一個程序開啓多個進程,每一個進程內開啓多個線程,每一個線程下開啓協程                2.協程指的是單個線程,於是一旦協程出現阻塞,將會阻塞整個線程        高性能分析:         單純地切換,或者說麼有遇到io操做也切換,反而會下降效率         檢測單線程下的IO行爲,實現遇到IO當即切換到其餘任務執行        爲何用協程?  多線程實現併發 有什麼問題?            TCP程序中 處理客戶端的鏈接 須要子線程  可是子線程依然會阻塞                一旦阻塞 CPU切走 可是沒法保證是否切到當前程序            提升效率的解決方案 是想辦法儘量多的佔用CPU                當程序遇到阻塞時 切換到別的任務 注意使用程序內切換        協程的實現            1 yield 把函數作成了生成器 生成器會自動保存狀態            2 greenlet 幫咱們封裝yield 能夠實現任務切換                    建立對象時 制定任務就是函數 在函數中手動來switch切換任務 不能檢測到IO行爲            3 gevent 封裝了grennlet  既可以切換執行 也能檢測IO            使用gevent須要配合monkey補丁 monkey補丁內部將本來阻塞的模塊 替換爲了非阻塞的            monkey必須放在導入(須要檢測IO的模塊)模塊以前            monkey.patch_all()            gevent核心函數spawn(函數名)            join讓主線程等待全部任務執行完成才結束        協程的應用場景:            (沒有IO絕對不使用協程) TCP 多客戶端實現方式            1.來一個客戶端就來一個進程     資源消耗較大            2.來一個客戶端就來一個線程     也不能無限開            3.用進程池 或 線程池  仍是一個線程或進程只能維護一個鏈接            4.協程 一個線程就能夠處理多個客戶端  遇到io就切到另外一個        總結協程特色:            必須在只有一個單線程裏實現併發,(將io阻塞時間用於執行計算 能夠提升效率 原理:一直使用CPU直到超時)            修改共享數據不需加鎖            用戶程序裏本身保存多個控制流的上下文棧            附加:一個協程遇到IO操做自動切換到其它協程                (如何實現檢測IO,yield、greenlet都沒法實現,就用到了gevent模塊(select機制))            from gevent import monkey;monkey.patch_all()            import gevent            def eat():                print('eat food 1')                time.sleep(2)                print('eat food 2')            def play():                print('play 1')                time.sleep(1)                print('play 2')            g1=gevent.spawn(eat)            g2=gevent.spawn(play)            gevent.joinall([g1,g2])
相關文章
相關標籤/搜索