亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python并發(fā)編程協(xié)程(Coroutine)之Gevent詳解

 更新時間:2017年12月27日 11:54:22   作者:python修行路  
這篇文章主要介紹了Python并發(fā)編程協(xié)程(Coroutine)之Gevent詳解,具有一定借鑒價值,需要的朋友可以參考下

Gevent官網文檔地址:http://www.gevent.org/contents.html

基本概念

我們通常所說的協(xié)程Coroutine其實是corporateroutine的縮寫,直接翻譯為協(xié)同的例程,一般我們都簡稱為協(xié)程。

在linux系統(tǒng)中,線程就是輕量級的進程,而我們通常也把協(xié)程稱為輕量級的線程即微線程。

進程和協(xié)程

下面對比一下進程和協(xié)程的相同點和不同點:

相同點:

我們都可以把他們看做是一種執(zhí)行流,執(zhí)行流可以掛起,并且后面可以在你掛起的地方恢復執(zhí)行,這實際上都可以看做是continuation,關于這個我們可以通過在linux上運行一個hello程序來理解:

shell進程和hello進程:

開始,shell進程在運行,等待命令行的輸入

執(zhí)行hello程序,shell通過系統(tǒng)調用來執(zhí)行我們的請求,這個時候系統(tǒng)調用會講控制權傳遞給操作系統(tǒng)。操作系統(tǒng)保存shell進程的上下文,創(chuàng)建一個hello進程以及其上下文并將控制權給新的hello進程。

hello進程終止后,操作系統(tǒng)恢復shell進程的上下文,并將控制權傳回給shell進程

shell進程繼續(xù)等待下個命令的輸入

當我們掛起一個執(zhí)行流的時,我們要保存的東西:

棧,其實在你切換前你的局部變量,以及要函數的調用都需要保存,否則都無法恢復

寄存器狀態(tài),這個其實用于當你的執(zhí)行流恢復后要做什么

而寄存器和棧的結合就可以理解為上下文,上下文切換的理解:

CPU看上去像是在并發(fā)的執(zhí)行多個進程,這是通過處理器在進程之間切換來實現的,操作系統(tǒng)實現這種交錯執(zhí)行的機制稱為上下文切換

操作系統(tǒng)保持跟蹤進程運行所需的所有狀態(tài)信息。這種狀態(tài),就是上下文。

在任何一個時刻,操作系統(tǒng)都只能執(zhí)行一個進程代碼,當操作系統(tǒng)決定把控制權從當前進程轉移到某個新進程時,就會進行上下文切換,即保存當前進程的上下文,恢復新進程的上下文,然后將控制權傳遞到新進程,新進程就會從它上次停止的地方開始。

不同點:

執(zhí)行流的調度者不同,進程是內核調度,而協(xié)程是在用戶態(tài)調度,也就是說進程的上下文是在內核態(tài)保存恢復的,而協(xié)程是在用戶態(tài)保存恢復的,很顯然用戶態(tài)的代價更低

進程會被強占,而協(xié)程不會,也就是說協(xié)程如果不主動讓出CPU,那么其他的協(xié)程,就沒有執(zhí)行的機會。

對內存的占用不同,實際上協(xié)程可以只需要4K的棧就足夠了,而進程占用的內存要大的多

從操作系統(tǒng)的角度講,多協(xié)程的程序是單進程,單協(xié)程

線程和協(xié)程

既然我們上面也說了,協(xié)程也被稱為微線程,下面對比一下協(xié)程和線程:

線程之間需要上下文切換成本相對協(xié)程來說是比較高的,尤其在開啟線程較多時,但協(xié)程的切換成本非常低。

同樣的線程的切換更多的是靠操作系統(tǒng)來控制,而協(xié)程的執(zhí)行由我們自己控制

我們通過下面的圖更容易理解:

從上圖可以看出,協(xié)程只是在單一的線程里不同的協(xié)程之間切換,其實和線程很像,線程是在一個進程下,不同的線程之間做切換,這也可能是協(xié)程稱為微線程的原因吧

繼續(xù)分析協(xié)程:

Gevent

Gevent是一種基于協(xié)程的Python網絡庫,它用到Greenlet提供的,封裝了libevent事件循環(huán)的高層同步API。它讓開發(fā)者在不改變編程習慣的同時,用同步的方式寫異步I/O的代碼。

使用Gevent的性能確實要比用傳統(tǒng)的線程高,甚至高很多。但這里不得不說它的一個坑:

Monkey-patching,我們都叫猴子補丁,因為如果使用了這個補丁,Gevent直接修改標準庫里面大部分的阻塞式系統(tǒng)調用,包括socket、ssl、threading和select等模塊,而變?yōu)閰f(xié)作式運行。但是我們無法保證你在復雜的生產環(huán)境中有哪些地方使用這些標準庫會由于打了補丁而出現奇怪的問題

第三方庫支持。得確保項目中用到其他用到的網絡庫也必須使用純Python或者明確說明支持Gevent

既然Gevent用的是Greenlet,我們通過下圖來理解greenlet:

每個協(xié)程都有一個parent,最頂層的協(xié)程就是man thread或者是當前的線程,每個協(xié)程遇到IO的時候就把控制權交給最頂層的協(xié)程,它會看那個協(xié)程的IO event已經完成,就將控制權給它。

下面是greenlet一個例子

from greenlet import greenlet

def test1(x,y):
  z = gr2.switch(x+y)
  print(z)

def test2(u):
  print(u)
  gr1.switch(42)

gr1 = greenlet(test1)
gr2 = greenlet(test2)

gr1.switch("hello",'world')

greenlet(run=None, parent=None): 創(chuàng)建一個greenlet實例.
gr.parent:每一個協(xié)程都有一個父協(xié)程,當前協(xié)程結束后會回到父協(xié)程中執(zhí)行,該 屬性默認是創(chuàng)建該協(xié)程的協(xié)程.
gr.run: 該屬性是協(xié)程實際運行的代碼. run方法結束了,那么該協(xié)程也就結束了.
gr.switch(*args, **kwargs): 切換到gr協(xié)程.
gr.throw(): 切換到gr協(xié)程,接著拋出一個異常.

下面是gevent的一個例子:

import gevent
def func1():
  print("start func1")
  gevent.sleep(1)
  print("end func1")
def func2():
  print("start func2")
  gevent.sleep(1)
  print("end func2")

gevent.joinall(
  [
    gevent.spawn(func1),
    gevent.spawn(func2)
  ]
)

關于gevent中隊列的使用

gevent中也有自己的隊列,但是有一個場景我用的過程中發(fā)現一個問題,就是如果我在協(xié)程中通過這個q來傳遞數據,如果對了是空的時候,從隊列獲取數據的那個協(xié)程就會被切換到另外一個協(xié)程中,這個協(xié)程用于往隊列里put放入數據,問題就出在,gevent不認為這個放入數據為IO操作,并不會切換到上一個協(xié)程中,會把這個協(xié)程的任務完成后在切換到另外一個協(xié)程。我原本想要實現的效果是往對了放入數據后就會切換到get的那個協(xié)程。(或許我這里理解有問題)下面是測試代碼:

import gevent
from gevent.queue import Queue
def func():
  for i in range(10):

    print("int the func")
    q.put("test")
def func2():
  for i in range(10):
    print("int the func2")
    res = q.get()
    print("--->",res)
q = Queue()
gevent.joinall(
  [
    gevent.spawn(func2),
    gevent.spawn(func),
  ]
)

這段代碼的運行效果為:

如果我在fun函數的q.put("test")后面添加gevent.sleep(0),就會是如下效果:

原本我預測的在不修改代碼的情況下就應該是第二個圖的結果,但是實際卻是第一個圖的結果(這個問題可能是我自己沒研究明白,后面繼續(xù)研究)

關于Gevent的問題

就像我上面說的gevent和第三方庫配合使用會有一些問題,可以總結為:
python協(xié)程的庫可以直接monkey path
C寫成的庫可以采用豆瓣開源的greenify來打patch(這個功能自己準備后面做測試)

不過總的來說gevent目前為止還是有很多缺陷,并且不是官網標準庫,而在python3中有一個官網正在做并且在3.6中已經穩(wěn)定的庫asyncio,這也是一個非常具有野心的庫,非常建議學習,我也準備后面深入了解

總結

以上就是本文關于Python并發(fā)編程協(xié)程(Coroutine)之Gevent詳解的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

相關文章

  • python實戰(zhàn)教程之OCR文字識別方法匯總

    python實戰(zhàn)教程之OCR文字識別方法匯總

    ocr是一種光學字符識別技術,簡單來說它能夠識別出圖像中的文字并且將其給取出來,下面這篇文章主要給大家介紹了關于python實戰(zhàn)教程之OCR文字識別方法的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-05-05
  • 用實例解釋Python中的繼承和多態(tài)的概念

    用實例解釋Python中的繼承和多態(tài)的概念

    這篇文章主要介紹了用實例解釋Python中的繼承和多態(tài)的概念,繼承和多臺是學習每一門面對對象的編程語言時都必須掌握的重要知識,需要的朋友可以參考下
    2015-04-04
  • Python基礎之元類詳解

    Python基礎之元類詳解

    這篇文章主要介紹了Python基礎之元類詳解,文中有非常詳細的代碼示例,對正在學習python基礎的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • Python實現給圖片添加文字或圖片水印

    Python實現給圖片添加文字或圖片水印

    在現今的數字化時代,網絡上的圖片泛濫,盜圖現象也越來越嚴重。因此,在發(fā)布文章時,為了保護自己的原創(chuàng)作品版權,很多人選擇使用水印來保護他們的圖片。本文就和大家分享了Python實現給圖片添加文字或圖片水印的方法,需要的可以收藏一下
    2023-05-05
  • 解決django中ModelForm多表單組合的問題

    解決django中ModelForm多表單組合的問題

    今天小編就為大家分享一篇解決django中ModelForm多表單組合的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07
  • python創(chuàng)建和刪除目錄的方法

    python創(chuàng)建和刪除目錄的方法

    這篇文章主要介紹了python創(chuàng)建和刪除目錄的方法,涉及Python操作目錄的相關技巧,非常具有實用價值,需要的朋友可以參考下
    2015-04-04
  • Sanic框架安裝與簡單入門示例

    Sanic框架安裝與簡單入門示例

    這篇文章主要介紹了Sanic框架安裝與簡單用法,結合實例形式簡單分析了Sanic框架的概念、原理、pip命令安裝以及使用方法,需要的朋友可以參考下
    2018-07-07
  • 理解python中生成器用法

    理解python中生成器用法

    本篇文章給大家詳細介紹了python中的生成器用法以及原理,有興趣的朋友參考學習下吧。
    2017-12-12
  • python中eval與int的區(qū)別淺析

    python中eval與int的區(qū)別淺析

    這篇文章主要給大家介紹了關于python中eval與int的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家學習或者使用python具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-08-08
  • Python3將數據保存為txt文件的方法

    Python3將數據保存為txt文件的方法

    這篇文章主要介紹了Python3將數據保存為txt文件的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09

最新評論