日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

异步同步、阻塞非阻塞、异步回调、线程队列和协程

發布時間:2025/7/14 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 异步同步、阻塞非阻塞、异步回调、线程队列和协程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  今天學習了異步同步、阻塞非阻塞、異步回調、線程隊列和協程

  一、異步同步和阻塞非阻塞

  線程的三種狀態:

    1、就緒

    2、運行

    3、阻塞

  阻塞:遇到了IO操作 ?代碼卡住 ?無法執行下一行 ?CPU會切換到其他任務

  非阻塞: 與阻塞相反 代碼正在執行(運行狀態) 或處于就緒狀態

  阻塞和非阻塞描述的是運行的狀態

  同步:提交任務必須等待任務完成,才能執行下一行

  異步:提交任務不需要等待任務完成,立即執行下一行

  指的是一種提交任務的方式

  二、異步回調

    為什么回調:子進程幫助主進程完成任務 處理任務的結果應該交還給主進程
    其他方式也可以將數據交還給主進程

      1、shutdown ?主進程會等到所有任務完成

      2、result函數 ?會阻塞直到任務完成

    注意:

      回調函數什么時候被執行?子進程完成時

      誰在執行回調函數?主進程

    線程的異步回調

      使用方式都相同 ?唯一的不同是執行回調函數 是子線程在執行

#進程利用回調完成生產者消費者
from
concurrent.futures import ProcessPoolExecutor import os pool = ProcessPoolExecutor()#爬蟲 從網絡某個地址獲取一個HTML文件 import requests #該模塊用于網絡請求 #生產數據 def get_data_task(url):print(os.getpid(),'正在生產數據!')response = requests.get(url)text = response.content.decode('utf-8')return text#處理數據 def parser_data(f):print(os.getpid(),'處理數據')print('正在解析:長度%s'%len(f.result()))urls = [ 'http://www.baidu.com', 'http://www.baidu.com', 'http://www.baidu.com', 'http://www.baidu.com' ]if __name__ == '__main__':for url in urls:f = pool.submit(get_data_task,url)f.add_done_callback(parser_data) #回調函數是主進程在執行#因為子進程是負責獲取數據的 然而數據怎么處理 子進程并不知道 應該把數據還給主進程print('over') #線程利用回調完成生產者消費者 from concurrent.futures import ThreadPoolExecutor from threading import current_threadpool = ThreadPoolExecutor #爬蟲 從網絡某個地址獲取一個HTML文件 import requests #該模塊用于網絡(HTTP)請求 #生產數據 def get_data_task(url):print(current_thread(),'正在生產數據!')response = requests.get(url)text = response.content.decode('utf-8')return text#處理數據 def parser_data(f):print(current_thread(),'處理數據')print('正在解析:長度%s'%len(f.result()))urls = [ 'http://www.baidu.com', 'http://www,baidu.com', 'http://www.baidu.com', 'http://www.baidu.com' ]if __name__ =='__main__':for url in urls:f = pool.submit(get_data_task,url)f.add_done_callback(parser_data) #因為是子線程在執行回調函數 所以沒有主次之分 任何子線程都可以對函數進行回調print('over')

  三、線程隊列

  

import queue #普通隊列 先進先出 q = queue.Queue() q.put('a') q.put('b') print(q.get()) print(q.get())#堆棧隊列 先進后出 函數調用就是進棧 函數結束就出棧 遞歸造成棧溢出 q2 = queue.LifoQueue() q2.put('a') q2.put('b') print('q2.get()')#優先級隊列 q3 = queue.PriorityQueue() #數值越小優先級越高 優先級相同時 比較大小 小的先取 q3.put((-100,'c')) q3.put((1,'a')) q3.put((100,b)) print(q3.get())

  四、協程

    協程的目的是在單線程下實現并發

    單線程下實現并發 將io阻塞時間用于執行計算 可以提高效率 原理:一直使用CPU直到超時

    怎么實現單線程并發?

    并發 ?指的是 ?看起來像是同時運行 實際是在任務間來回切換 同時需要保存執行的狀態

    任務是一堆代碼 可以用函數裝起來

    1.如何讓兩個函數切換執行

      yield可以保存函數的執行狀態

      通過生成器可以實現偽并發

      并發不一定提升效率 ?反而會降低效率 當任務全是計算時

    2.如何知道發生了io?從而切換執行

      目前咱們實現不了。。

    第三方模塊 greenlet 可以實現并發 但是不能檢測io

    第三方模塊 gevent 封裝greenlet 可以實現單線程并發 并且能夠檢測io操作 自動切換

    

#用yield實現兩個函數切換執行 import time def task():while True:print('task1')time.sleep(4)yield 1def task2():g = task()while True:try:print('task2')next(g)except Exception:print('任務完成')break task2() #使用greenlet模塊實現并發 import greenlet import time def task1():print('task1 1')time.sleep(2)g2.switch()print('task1 2')g2.swith()def task2():print('task2 1')g1.switch()print('task2 2')g1 = greenlet.greenlet(task1) g2 = greenlet.greenlte(task2) g1.switch() #1.實例化greenlet得到一個對象 傳入要執行的任務 #2.先讓某個任務執行起來 使用對象調用switch #3.在任務的執行過程中 手動調用switch來切換 #使用gevent模塊實現單線程的并發 from gevent import monkey monkey.patch_all() import gevent import time 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]) print('')#1.spawn函數傳入你的任務 #2.調用join 去開啟任務 #3.檢測io操作需要打mokey補丁 就是一個函數 在程序最開始的地方調用它

?

轉載于:https://www.cnblogs.com/xiaocaiyang/p/9954077.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的异步同步、阻塞非阻塞、异步回调、线程队列和协程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。