溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

python編程使用協(xié)程并發(fā)的優(yōu)缺點(diǎn)

發(fā)布時(shí)間:2020-09-13 12:37:52 來源:腳本之家 閱讀:187 作者:雪山飛豬 欄目:開發(fā)技術(shù)

協(xié)程

協(xié)程是一種用戶態(tài)的輕量級(jí)線程,又稱微線程。

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

優(yōu)點(diǎn):

1.無需線程上下文切換的開銷
2.無需原子操作鎖定及同步的開銷
3.方便切換控制流,簡(jiǎn)化編程模型
4.高并發(fā)+高擴(kuò)展性+低成本:一個(gè)CPU支持上萬的協(xié)程都不是問題。所以很適合用于高并發(fā)處理。

所謂原子操作是指不會(huì)被線程調(diào)度機(jī)制打斷的操作;這種操作一旦開始,就一直運(yùn)行到結(jié)束,中間不會(huì)有任何 context switch (切換到另一個(gè)線程)。

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

缺點(diǎn):

1.無法利用多核資源:協(xié)程的本質(zhì)是個(gè)單線程,它不能同時(shí)將 單個(gè)CPU 的多個(gè)核用上,協(xié)程需要和進(jìn)程配合才能運(yùn)行在多CPU上.當(dāng)然我們?nèi)粘K帉懙慕^大部分應(yīng)用都沒有這個(gè)必要,除非是cpu密集型應(yīng)用。
2.進(jìn)行阻塞(Blocking)操作(如IO時(shí))會(huì)阻塞掉整個(gè)程序

使用Gevent

gevent是python的一個(gè)并發(fā)框架,以微線程greenlet為核心,使用了epoll事件監(jiān)聽機(jī)制以及諸多其他優(yōu)化而變得高效.

•簡(jiǎn)單示例

gevent的sleep可以交出控制權(quán),當(dāng)我們?cè)谑芟抻诰W(wǎng)絡(luò)或IO的函數(shù)中使用gevent,這些函數(shù)會(huì)被協(xié)作式的調(diào)度, gevent的真正能力會(huì)得到發(fā)揮。Gevent處理了所有的細(xì)節(jié), 來保證你的網(wǎng)絡(luò)庫會(huì)在可能的時(shí)候,隱式交出greenlet上下文的執(zhí)行權(quán)。

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')
# 創(chuàng)建線程并行執(zhí)行程序
gevent.joinall([
  gevent.spawn(foo),
  gevent.spawn(bar),
]) 

  執(zhí)行結(jié)果

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() 

  執(zhí)行輸出

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

•以子類的方法使用協(xié)程

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

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() # 啟動(dòng)
for test in tests:
  test.join() # 等待執(zhí)行結(jié)束 

•使用monkey patch修改系統(tǒng)標(biāo)準(zhǔn)庫(自動(dòng)切換協(xié)程)

當(dāng)一個(gè)greenlet遇到IO操作時(shí),比如訪問網(wǎng)絡(luò),就自動(dòng)切換到其他的greenlet,等到IO操作完成,再在適當(dāng)?shù)臅r(shí)候切換回來繼續(xù)執(zhí)行。

由于IO操作非常耗時(shí),經(jīng)常使程序處于等待狀態(tài),有了gevent為我們自動(dòng)切換協(xié)程,就保證總有g(shù)reenlet在運(yùn)行,而不是等待IO。

由于切換是在IO操作時(shí)自動(dòng)完成,所以gevent需要修改Python自帶的一些標(biāo)準(zhǔn)庫,這一過程在啟動(dòng)時(shí)通過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.baidu.com/'),
  gevent.spawn(task, 'https://www.qq.com/'),
  gevent.spawn(task, 'https://www.jd.com/'),
]) 

  執(zhí)行輸出

2443 bytes received from https://www.baidu.com/

108315 bytes received from https://www.jd.com/

231873 bytes received from https://www.qq.com/

可以看出3個(gè)網(wǎng)絡(luò)操作是并發(fā)執(zhí)行的,而且結(jié)束順序不同

參考鏈接:http://hhkbp2.github.io/gevent-tutorial/

總結(jié)

以上所述是小編給大家介紹的python編程使用協(xié)程并發(fā)的優(yōu)缺點(diǎn),希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)億速云網(wǎng)站的支持!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI