首頁 >後端開發 >Python教學 >python greenlet 實作機制

python greenlet 實作機制

巴扎黑
巴扎黑原創
2016-12-09 14:45:471262瀏覽

最近使用python開發web程式,一直使用的是fastcgi模式.然後每個進程中啟動多個線程來進行請求處理.這裡有一個問題就是需要保證每個請求響應時間都要特別短,不然只要多請求幾次慢的就會讓伺服器拒絕服務,因為沒有線程能夠響應請求了.平時我們的服務上線都會進行性能測試的,所以正常情況沒有太大問題.但是不可能所有場景都測試到.一旦出現就會讓用戶等好久沒有回應.部分不可用導致全部不可用.後來轉換到了coroutine,python 下的greenlet.所以對它的實現機製做了一個簡單的了解. 
每個greenlet都只是heap中的一個python object(PyGreenlet).所以對於一個進程你創建百萬甚至千萬個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;

每一個greenlet其實就是一個函數,以及保存這個函數執行時的上下文.對於函數來說上下文也就是其stack..同一個進程的所有的greenlets共用一個共同的操作系統分配的用戶棧.所以同一時刻只能有棧數據不衝突的greenlet使用這個全局的棧.greenlet是通過stack_stop,stack_start來保存其stack的棧底和堆疊的,如果出現將要執行的greenlet的stack_stop和目前棧中的greenlet重疊的情況,就要把這些重疊的greenlet的棧中數據臨時保存到heap中.保存的位置通過stack_copy和stack_saved來記錄,以便恢復的時候從heap中拷貝回棧中stack_stop和stack_start的位置.不然就會出現其棧資料會被破壞的情況.所以應用程式創建的這些greenlet就是透過不斷的拷貝資料到heap中或從heap中拷貝到堆疊中來實現並發的.對於io型的應用程式使用coroutine真的非常舒服. 

下面是greenlet的一個簡單的棧空間模型(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()


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:短URL生成轉換下一篇:短URL生成轉換