中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在python中使用協程實現并發

發布時間:2021-03-22 17:05:55 來源:億速云 閱讀:203 作者:Leah 欄目:開發技術

怎么在python中使用協程實現并發?相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

協程

協程是一種用戶態的輕量級線程,又稱微線程。

協程擁有自己的寄存器上下文和棧,調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧。因此:協程能保留上一次調用時的狀態(即所有局部狀態的一個特定組合),每次過程重入時,就相當于進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置。

優點:

  1. 無需線程上下文切換的開銷

  2. 無需原子操作鎖定及同步的開銷

  3. 方便切換控制流,簡化編程模型

  4. 高并發+高擴展性+低成本:一個CPU支持上萬的協程都不是問題。所以很適合用于高并發處理。

所謂原子操作是指不會被線程調度機制打斷的操作;這種操作一旦開始,就一直運行到結束,中間不會有任何 context switch (切換到另一個線程)。

原子操作可以是一個步驟,也可以是多個操作步驟,但是其順序是不可以被打亂,或者切割掉只執行部分。視作整體是原子性的核心。

缺點:

  1. 無法利用多核資源:協程的本質是個單線程,它不能同時將 單個CPU 的多個核用上,協程需要和進程配合才能運行在多CPU上.當然我們日常所編寫的絕大部分應用都沒有這個必要,除非是cpu密集型應用。

  2. 進行阻塞(Blocking)操作(如IO時)會阻塞掉整個程序

使用Gevent

gevent是python的一個并發框架,以微線程greenlet為核心,使用了epoll事件監聽機制以及諸多其他優化而變得高效.

  • 簡單示例

gevent的sleep可以交出控制權,當我們在受限于網絡或IO的函數中使用gevent,這些函數會被協作式的調度, gevent的真正能力會得到發揮。Gevent處理了所有的細節, 來保證你的網絡庫會在可能的時候,隱式交出greenlet上下文的執行權。

import gevent
def foo():
  print('running in foo')
  gevent.sleep(0)
  print('com back from bar in to foo')
def bar():
  print('running in bar')
  gevent.sleep(0)
  print('com back from foo in to bar')
# 創建線程并行執行程序
gevent.joinall([
  gevent.spawn(foo),
  gevent.spawn(bar),
])

執行結果

running in foo
running in bar
com back from bar in to foo
com back from foo in to bar

  • 同步異步

import random
import gevent
def task(pid):
  gevent.sleep(random.randint(0, 2) * 0.001)
  print('Task %s done' % pid)
def synchronous():
  for i in range(1, 10):
    task(i)
def asynchronous():
  threads = [gevent.spawn(task, i) for i in range(10)]
  gevent.joinall(threads)
print('Synchronous:')
synchronous()
print('Asynchronous:')
asynchronous()

執行輸出

Synchronous:
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Task 5 done
Task 6 done
Task 7 done
Task 8 done
Task 9 done
Asynchronous:
Task 1 done
Task 4 done
Task 5 done
Task 9 done
Task 6 done
Task 0 done
Task 2 done
Task 3 done
Task 7 done
Task 8 done

  • 以子類的方法使用協程

可以子類化Greenlet類,重載它的_run方法,類似多線程和多進程模塊

import gevent
from gevent import Greenlet
class Test(Greenlet):
  def __init__(self, message, n):
    Greenlet.__init__(self)
    self.message = message
    self.n = n
  def _run(self):
    print(self.message, 'start')
    gevent.sleep(self.n)
    print(self.message, 'end')
tests = [
  Test("hello", 3),
  Test("world", 2),
]
for test in tests:
  test.start() # 啟動
for test in tests:
  test.join() # 等待執行結束
  • 使用monkey patch修改系統標準庫(自動切換協程)

當一個greenlet遇到IO操作時,比如訪問網絡,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。

由于IO操作非常耗時,經常使程序處于等待狀態,有了gevent為我們自動切換協程,就保證總有greenlet在運行,而不是等待IO。

由于切換是在IO操作時自動完成,所以gevent需要修改Python自帶的一些標準庫,這一過程在啟動時通過monkey patch完成

import gevent
import requests
from gevent import monkey
monkey.patch_socket()
def task(url):
  r = requests.get(url)
  print('%s bytes received from %s' % (len(r.text), url))
gevent.joinall([
  gevent.spawn(task, 'https://www.123.com/'),
  gevent.spawn(task, 'https://www.45.com/'),
  gevent.spawn(task, 'https://www.65.com/'),
])

看完上述內容,你們掌握怎么在python中使用協程實現并發的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

高邑县| 尉氏县| 宁武县| 曲阜市| 麟游县| 奇台县| 上虞市| 阿合奇县| 宁南县| 白朗县| 鞍山市| 淮南市| 海丰县| 巴彦县| 隆回县| 四川省| 泾阳县| 读书| 东丽区| 乐陵市| 绍兴市| 壶关县| 梅河口市| 宁安市| 成武县| 武夷山市| 休宁县| 嘉定区| 新闻| 象州县| 蒙城县| 阿拉善左旗| 沙田区| 阳信县| 错那县| 林口县| 云浮市| 马龙县| 孟连| 彰武县| 休宁县|