python之gevent(1)

????因?yàn)閜ython線程的性能問題,在python中使用多線程運(yùn)行代碼經(jīng)常不能達(dá)到預(yù)期的效果。而有些時(shí)候我們的邏輯中又需要開更高的并發(fā),或者簡單的說,就是讓我們的代碼跑的更快,在同樣時(shí)間內(nèi)執(zhí)行更多的有效邏輯、減少無用的等待。gevent就是一個(gè)現(xiàn)在很火、支持也很全面的python第三方協(xié)程庫。
????gevent是python的一個(gè)并發(fā)框架,以微線程greenlet為核心,使用了epoll事件監(jiān)聽機(jī)制以及諸多其他優(yōu)化而變得高效。而且其中有個(gè)monkey類,將現(xiàn)有基于Python線程直接轉(zhuǎn)化為greenlet(類似于打patch)。在運(yùn)行時(shí)的具體流程大概就是:
????當(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。同時(shí)也因?yàn)橹挥幸粋€(gè)線程在執(zhí)行,會(huì)極大的減少上下文切換的成本。

gevent基本使用

# -*- coding: utf-8 -*-

import gevent


def f1():
    for i in range(5):
        print 'run func: f1, index: %s ' % i
        gevent.sleep(0)


def f2():
    for i in range(5):
        print 'run func: f2, index: %s ' % i
        gevent.sleep(0)


t1 = gevent.spawn(f1)
t2 = gevent.spawn(f2)
gevent.joinall([t1, t2])

運(yùn)行后輸出如下圖所示:


image.png

????由圖中可以看出,f1和f2是交叉打印信息的,因?yàn)樵诖a執(zhí)行的過程中,我們?nèi)藶槭褂胓event.sleep(0)創(chuàng)建了一個(gè)阻塞,gevent在運(yùn)行到這里時(shí)就會(huì)自動(dòng)切換函數(shù)切換函數(shù)。也可以在執(zhí)行的時(shí)候sleep更長時(shí)間,可以發(fā)現(xiàn)兩個(gè)函數(shù)基本是同時(shí)運(yùn)行然后各自等待。

????在實(shí)際運(yùn)用的過程中,我們?nèi)绻行枰ㄟ^人為sleep來增加時(shí)間間隔或者確保部分邏輯安全的時(shí)候,此處使用就很方便了。當(dāng)然,更多時(shí)候我們還是在需要進(jìn)行網(wǎng)絡(luò)請(qǐng)求的時(shí)候使用gevent:

# -*- coding: utf-8 -*-

from gevent import monkey; monkey.patch_all()
import gevent
import requests
from datetime import datetime


def f(url):
    print 'time: %s, GET: %s' % (datetime.now(), url)
    resp = requests.get(url)
    print 'time: %s, %d bytes received from %s.' % (
        datetime.now(), len(resp.text), url)


gevent.joinall([
        gevent.spawn(f, 'https://www.python.org/'),
        gevent.spawn(f, 'https://www.yahoo.com/'),
        gevent.spawn(f, 'https://github.com/'),
])

運(yùn)行上述代碼,結(jié)果如下:


image.png

由上圖可以看出,程序基本在同一時(shí)間觸發(fā)了對(duì)三個(gè)網(wǎng)站的請(qǐng)求,然后各自進(jìn)行,分別結(jié)束。也就是當(dāng)gevent發(fā)現(xiàn)阻塞之后,讓當(dāng)前急需執(zhí)行,然后自動(dòng)切換到了另外的請(qǐng)求中運(yùn)行。

加鎖

如果需要在使用gevent的時(shí)候加鎖,也是非常方便的:

# -*- coding: utf-8 -*-

import gevent
from gevent.lock import Semaphore

sem = Semaphore(1)


def f1():
    for i in range(5):
        sem.acquire()
        print 'run f1, this is ', i
        sem.release()
        gevent.sleep(1)


def f2():
    for i in range(5):
        sem.acquire()
        print 'run f2, that is ', i
        sem.release()
        gevent.sleep(0.3)


t1 = gevent.spawn(f1)
t2 = gevent.spawn(f2)
gevent.joinall([t1, t2])

運(yùn)行結(jié)果如下:


image.png

由輸出可以發(fā)現(xiàn),程序會(huì)同時(shí)判斷是否在sleep以及是否有鎖兩種情況,然后執(zhí)行當(dāng)前的最有操作。

小結(jié)

????gevent的優(yōu)勢不僅僅是在代碼中調(diào)用方便,厲害的是它擁有的monkey機(jī)制。假設(shè)你不愿意修改原來已經(jīng)寫好的python代碼,但是又想充分利用gevent機(jī)制,那么你就可以用monkey來做到這一點(diǎn)。你所要做的就是在文件開頭打一個(gè)patch,那么它就會(huì)自動(dòng)替換你原來的thread、socket、time、multiprocessing等代碼,全部變成gevent框架。這一切都是由gevent自動(dòng)完成的。注意這個(gè)patch是在所有module都import了之后再打,否則沒有效果。
????甚至在編寫的Web App代碼的時(shí)候,不需要引入gevent的包,也不需要改任何代碼,僅僅在部署的時(shí)候,用一個(gè)支持gevent的WSGI服務(wù)器,就可以獲得數(shù)倍的性能提升。

本文簡單介紹了gevent的使用,下一篇將對(duì)gevent的部分源碼進(jìn)行分析。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 協(xié)程 閱讀目錄 一 引子 二 協(xié)程介紹 三 Greenlet模塊 四 Gevent模塊 引子 之前我們學(xué)習(xí)了線程、...
    go以恒閱讀 787評(píng)論 0 1
  • 迭代、迭代器、生成器、協(xié)程、yield、greenlet、gevent、進(jìn)程線程協(xié)程對(duì)比、gevent多任務(wù)圖片下...
    Cestine閱讀 531評(píng)論 0 0
  • 必備的理論基礎(chǔ) 1.操作系統(tǒng)作用: 隱藏丑陋復(fù)雜的硬件接口,提供良好的抽象接口。 管理調(diào)度進(jìn)程,并將多個(gè)進(jìn)程對(duì)硬件...
    drfung閱讀 3,746評(píng)論 0 5
  • 一、總體內(nèi)容 1.1、協(xié)程的介紹 1.2、迭代器以及迭代器的應(yīng)用 1.3、生成器(生成器與迭代器保存的都是生成數(shù)據(jù)...
    IIronMan閱讀 892評(píng)論 0 1
  • 目錄 一、開啟線程的兩種方式 在python中開啟線程要導(dǎo)入threading,它與開啟進(jìn)程所需要導(dǎo)入的模塊mul...
    CaiGuangyin閱讀 2,468評(píng)論 1 16

友情鏈接更多精彩內(nèi)容