Python greenlet實(shí)現(xiàn)原理和使用示例
來源:易賢網(wǎng) 閱讀:1243 次 日期:2014-09-25 10:01:11
溫馨提示:易賢網(wǎng)小編為您整理了“Python greenlet實(shí)現(xiàn)原理和使用示例”,方便廣大網(wǎng)友查閱!

最近開始研究Python的并行開發(fā)技術(shù),包括多線程,多進(jìn)程,協(xié)程等。逐步整理了網(wǎng)上的一些資料,今天整理了一下greenlet相關(guān)的資料。

并發(fā)處理的技術(shù)背景

并行化處理目前很受重視, 因?yàn)樵诤芏鄷r(shí)候,并行計(jì)算能大大的提高系統(tǒng)吞吐量,尤其在現(xiàn)在多核多處理器的時(shí)代, 所以像lisp這種古老的語言又被人們重新拿了起來, 函數(shù)式編程也越來越流行。 介紹一個(gè)python的并行處理的一個(gè)庫: greenlet。 python 有一個(gè)非常有名的庫叫做 stackless ,用來做并發(fā)處理, 主要是弄了個(gè)叫做tasklet的微線程的東西, 而greenlet 跟stackless的最大區(qū)別是, 他很輕量級(jí)?不夠, 最大的區(qū)別是greenlet需要你自己來處理線程切換, 就是說,你需要自己指定現(xiàn)在執(zhí)行哪個(gè)greenlet再執(zhí)行哪個(gè)greenlet。

greenlet的實(shí)現(xiàn)機(jī)制

以前使用python開發(fā)web程序,一直使用的是fastcgi模式.然后每個(gè)進(jìn)程中啟動(dòng)多個(gè)線程來進(jìn)行請(qǐng)求處理.這里有一個(gè)問題就是需要保證每個(gè)請(qǐng)求響應(yīng)時(shí)間都要特別短,不然只要多請(qǐng)求幾次慢的就會(huì)讓服務(wù)器拒絕服務(wù),因?yàn)闆]有線程能夠響應(yīng)請(qǐng)求了.平時(shí)我們的服務(wù)上線都會(huì)進(jìn)行性能測試的,所以正常情況沒有太大問題.但是不可能所有場景都測試到.一旦出現(xiàn)就會(huì)讓用戶等好久沒有響應(yīng).部分不可用導(dǎo)致全部不可用.后來轉(zhuǎn)換到了coroutine,python 下的greenlet.所以對(duì)它的實(shí)現(xiàn)機(jī)制做了一個(gè)簡單的了解.

每個(gè)greenlet都只是heap中的一個(gè)python object(PyGreenlet).所以對(duì)于一個(gè)進(jìn)程你創(chuàng)建百萬甚至千萬個(gè)greenlet都沒有問題.

代碼如下:

typedef struct _greenlet {

PyObject_HEAD

char* stack_start;

char* stack_stop;

char* stack_copy;

intptr_t stack_saved;

struct _greenlet* stack_prev;

struct _greenlet* parent;

PyObject* run_info;

struct _frame* top_frame;

int recursion_depth;

PyObject* weakreflist;

PyObject* exc_type;

PyObject* exc_value;

PyObject* exc_traceback;

PyObject* dict;

} PyGreenlet;

每一個(gè)greenlet其實(shí)就是一個(gè)函數(shù),以及保存這個(gè)函數(shù)執(zhí)行時(shí)的上下文.對(duì)于函數(shù)來說上下文也就是其stack..同一個(gè)進(jìn)程的所有的greenlets共用一個(gè)共同的操作系統(tǒng)分配的用戶棧.所以同一時(shí)刻只能有棧數(shù)據(jù)不沖突的greenlet使用這個(gè)全局的棧.greenlet是通過stack_stop,stack_start來保存其stack的棧底和棧頂?shù)?如果出現(xiàn)將要執(zhí)行的greenlet的stack_stop和目前棧中的greenlet重疊的情況,就要把這些重疊的greenlet的棧中數(shù)據(jù)臨時(shí)保存到heap中.保存的位置通過stack_copy和stack_saved來記錄,以便恢復(fù)的時(shí)候從heap中拷貝回棧中stack_stop和stack_start的位置.不然就會(huì)出現(xiàn)其棧數(shù)據(jù)會(huì)被破壞的情況.所以應(yīng)用程序創(chuàng)建的這些greenlet就是通過不斷的拷貝數(shù)據(jù)到heap中或者從heap中拷貝到棧中來實(shí)現(xiàn)并發(fā)的.對(duì)于io型的應(yīng)用程序使用coroutine真的非常舒服.

下面是greenlet的一個(gè)簡單的棧空間模型(from greenlet.c)

代碼如下:

A PyGreenlet is a range of C stack addresses that must be

saved and restored in such a way that the full range of the

stack contains valid data when we switch to it.

Stack layout for a greenlet:

| ^^^ |

| older data |

| |

stack_stop . |_______________|

. | |

. | greenlet data |

. | in stack |

. * |_______________| . . _____________ stack_copy + stack_saved

. | | | |

. | data | |greenlet data|

. | unrelated | | saved |

. | to | | in heap |

stack_start . | this | . . |_____________| stack_copy

| greenlet |

| |

| newer data |

| vvv |

下面是一段簡單的greenlet代碼.

代碼如下:

from greenlet import greenlet

def test1():

print 12

gr2.switch()

print 34

def test2():

print 56

gr1.switch()

print 78

gr1 = greenlet(test1)

gr2 = greenlet(test2)

gr1.switch()

目前所討論的協(xié)程,一般是編程語言提供支持的。目前我所知提供協(xié)程支持的語言包括python,lua,go,erlang, scala和rust。協(xié)程不同于線程的地方在于協(xié)程不是操作系統(tǒng)進(jìn)行切換,而是由程序員編碼進(jìn)行切換的,也就是說切換是由程序員控制的,這樣就沒有了線程所謂的安全問題。

所有的協(xié)程都共享整個(gè)進(jìn)程的上下文,這樣協(xié)程間的交換也非常方便。

相對(duì)于第二種方案(I/O多路復(fù)用),使得使用協(xié)程寫的程序?qū)⒏拥闹庇^,而不是將一個(gè)完整的流程拆分成多個(gè)管理的事件處理。協(xié)程的缺點(diǎn)可能是無法利用多核優(yōu)勢,不過,這個(gè)可以通過協(xié)程+進(jìn)程的方式來解決。

協(xié)程可以用來處理并發(fā)來提高性能,也可以用來實(shí)現(xiàn)狀態(tài)機(jī)來簡化編程。我用的更多的是第二個(gè)。去年年底接觸python,了解到了python的協(xié)程概念,后來通過pycon china2011接觸到處理yield,greenlet也是一個(gè)協(xié)程方案,而且在我看來是更可用的一個(gè)方案,特別是用來處理狀態(tài)機(jī)。

目前這一塊已經(jīng)基本完成,后面抽時(shí)間總結(jié)一下。

總結(jié)一下:

1)多進(jìn)程能夠利用多核優(yōu)勢,但是進(jìn)程間通信比較麻煩,另外,進(jìn)程數(shù)目的增加會(huì)使性能下降,進(jìn)程切換的成本較高。程序流程復(fù)雜度相對(duì)I/O多路復(fù)用要低。

2)I/O多路復(fù)用是在一個(gè)進(jìn)程內(nèi)部處理多個(gè)邏輯流程,不用進(jìn)行進(jìn)程切換,性能較高,另外流程間共享信息簡單。但是無法利用多核優(yōu)勢,另外,程序流程被事件處理切割成一個(gè)個(gè)小塊,程序比較復(fù)雜,難于理解。

3)線程運(yùn)行在一個(gè)進(jìn)程內(nèi)部,由操作系統(tǒng)調(diào)度,切換成本較低,另外,他們共享進(jìn)程的虛擬地址空間,線程間共享信息簡單。但是線程安全問題導(dǎo)致線程學(xué)習(xí)曲線陡峭,而且易出錯(cuò)。

4)協(xié)程有編程語言提供,由程序員控制進(jìn)行切換,所以沒有線程安全問題,可以用來處理狀態(tài)機(jī),并發(fā)請(qǐng)求等。但是無法利用多核優(yōu)勢。

上面的四種方案可以配合使用,我比較看好的是進(jìn)程+協(xié)程的模式。

更多信息請(qǐng)查看IT技術(shù)專欄

更多信息請(qǐng)查看腳本欄目
易賢網(wǎng)手機(jī)網(wǎng)站地址:Python greenlet實(shí)現(xiàn)原理和使用示例
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2025國考·省考課程試聽報(bào)名

  • 報(bào)班類型
  • 姓名
  • 手機(jī)號(hào)
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 加入群交流 | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號(hào):hfpxwx
咨詢QQ:526150442(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專用圖標(biāo)