摘要:怎么記錄呢這里就可以回到上面我們需要了解的幾個棧操作了。這個時候,如果函數執行完了想去執行函數的時候,就按照這個流程再保存,然后再把剛才存放的函數給復制到棧中。
gevent文檔:that uses greenlet to provide a high-level synchronous API.
意思是:使用greenlet來提供高級同步API。
那greenlet又是怎樣一種機制呢?這個后面會稍微簡單的講一下原理,不過在后續的幾篇會著重分析它的源碼。在開始之前先看看提到的幾個關鍵字『高級』、『同步』,高級不高級暫時還不知道,畢竟在實際生產環境中才看得到效果。而同步這個概念,不知道大家理解深不深刻,總之我當初理解不是很深刻,所以遇到了就聊聊唄!
同步不明白為什么會叫同步,總是讓我有一種錯覺,讓我聯想到的第一個詞匯就是同時進行。不知道大家是不是和我一樣,至少我看到同步是不會去想到它的正確意思。我曾一度懷疑是不是翻譯錯了,但是在質疑別人錯之前,應該先質疑一下自己。所以我開始懷疑我的語文沒學好,然后我去查了一下漢語詞典,結果就悲劇了,我已經開始懷疑我的人生了。 %>_<%
同步:指兩個或兩個以上隨時間變化的量在變化過程中保持一定的相對關系。
《光明日報》1984.6.2:“城市改革的步子要加快,要從解決國家與企業、企業與職工的關系入手,把適合于當前情況的各項改革措施初步配起套來,同步進行。
從上面引用的話應該可以看出,國家與企業、企業與職工,都是兩個相對的關系,有著各自的利益。但是他們必須合作才能完成一個共同目標,例如買票看電影。這個場景有兩個動作需要完成,一個出票、一個買票,只有出票才能買票,并且這個買票的人還只能傻等,不能做其他事。
同步真心不是同時進行,所以還是要多讀書啊!尤其是語文!
為什么這里會講到同步呢?其實不講也是可以的,和理解greenlet原理沒有多大關系,但是和理解gevent的特性有那么點關系,因為聽別人說gevent能夠讓你用這種同步的代碼寫出異步的感覺,同步的代碼好理解也好處理。我沒有驗證過,所以我也不知道,真正的原因是感覺這個概念很容易混淆,所以就來講講了。
Greenlet還記得在協程篇中學習的嗎?花了較長篇幅講協程及從其子例程演變的過程。而greenlet就是python中實現Coroutine「協程」的一個基礎庫。前面我們了解了協程的相關概念及思想,但我們還不知道它在底層是怎樣實現的。只知道它有個特別的地方,就是能夠和進程、線程一樣保存上下文,那協程的上下文是怎樣保存的呢?
源碼初探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_start、stack_stop、stack_copy、stack_saved。
其實仔細想想,你會發現非常的簡單。假設有『函數A』和『函數B』,『函數A』進棧執行到一半的時候需要調用『函數B』,沒事這個簡單,我們可以將『函數B』進棧(圖stack-01)。
好了『函數B』進棧了,可它現在又想調用『函數A』了,怎么辦?讓『函數A』進棧(圖stack-02),這個其實就是普通的函數調用,此『函數A』并不是第一次進棧的那個『函數A』,而是重新在棧中創建的一個實例,該實例的數據并不是之前『函數A』的數據,可是我想要之前『函數A』的數據啊!所以這個方法并不能實現我們想要的切換。
那怎樣才能做到我們想要的呢?很簡單,既然『函數B』完成了當前的任務,它就應該退出來了,但并不是直接出棧,而是通過某種方式將現有的state給記錄下來,方便下次用到的時候能夠找到。怎么記錄呢?這里就可以回到上面我們需要了解的幾個棧操作了。
首先,每個greenlet都有屬于它們自己的stack_start和stack_stop,通過這兩個可以找到你準備出棧的greenlet也就是『函數B』的所有數據,之后再調用PyMem_Realloc這個方法,就可以在heap中創建一個內存空間用來存放『函數B』,地址為stack_copy,大小為stack_saved字節,通過這兩個就可以定位到你存放的『函數B』的數據了(圖stack-03)。
之后變成下面(圖stack-04)這樣了。這個時候,如果『函數A』執行完了想去執行『函數B』的時候,就按照這個流程再保存,然后再把剛才存放的『函數B』給復制到C棧中。因為已經知道了stack_copy和stack_saved,所以也就不怕找不到它了。
整個greenlet切換流程大概就是這個樣子了,不過到了這里不知道大家會不會有些疑問,雖然保存了stack_copy和stack_saved,但是『函數B』已經出棧了,不是就沒有這個對象了嗎?那這兩個參數是由誰來保存呢?
其實這個對象從來就沒有被銷毀,只要這個greenlet沒有正常退出,它的對象就一直都存在著,因為Greenlet還維護著一個鏈表,它保存著所有沒有徹底退出的greenlet對象,『函數B』出棧并不是完全退出了,只是不參與這次行動。具體的細節就要等到下一篇或者下下篇的源碼剖析來講解了。
因為最近工作比較忙,換了一個部門,加上之前對源碼理解不夠,也就不敢隨便發表。當然現在發表的也不敢說絕對正確,這些僅僅是我個人的理解,歡迎大神來指正。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/37354.html
摘要:不過不管怎樣,就當多學習了一些其他知識,況且分析源碼肯定少不了對這些知識的了解。官方文檔描述里面提到了,在這個模塊中指的就是,一般稱它為方法列表。返回一個指向它創建的模塊對象的指針。 showImg(http://young-py.github.io/imgs/yyzt3.jpg); 在greenlet篇中只是簡單講述了一下greenlet原理,不知道有沒有人對源碼感興趣的,不過我還...
摘要:一旦有事件產生可能是一次出現好多個事件,就會按照優先級依次調用每個事件的回調函數。注意,是有超時的,所以一些無法以文件描述符的形式存在的事件也可以有機會被觸發。 這一篇主要想跟大家分享一下 Gevent 實現的基礎邏輯,也是有同學對這個很感興趣,所以貼出來跟大家一起分享一下。 Greenlet 我們知道 Gevent 是基于 Greenlet 實現的,greenlet 有的時候也被...
摘要:隨著我們對于效率的追求不斷提高,基于單線程來實現并發又成為一個新的課題,即只用一個主線程很明顯可利用的只有一個情況下實現并發。作為的補充可以檢測操作,在遇到操作的情況下才發生切換協程介紹協程是單線程下的并發,又稱微線程,纖程。 引子 之前我們學習了線程、進程的概念,了解了在操作系統中進程是資源分配的最小單位,線程是CPU調度的最小單位。按道理來說我們已經算是把cpu的利用率提高很多了。...
摘要:所以與多線程相比,線程的數量越多,協程性能的優勢越明顯。值得一提的是,在此過程中,只有一個線程在執行,因此這與多線程的概念是不一樣的。 真正有知識的人的成長過程,就像麥穗的成長過程:麥穗空的時候,麥子長得很快,麥穗驕傲地高高昂起,但是,麥穗成熟飽滿時,它們開始謙虛,垂下麥芒。 ——蒙田《蒙田隨筆全集》 上篇論述了關于python多線程是否是雞肋的問題,得到了一些網友的認可,當然也有...
摘要:協程,又稱微線程,纖程。最大的優勢就是協程極高的執行效率。生產者產出第條數據返回更新值更新消費者正在調用第條數據查看當前進行的線程函數中有,返回值為生成器庫實現協程通過提供了對協程的基本支持,但是不完全。 協程,又稱微線程,纖程。英文名Coroutine協程看上去也是子程序,但執行過程中,在子程序內部可中斷,然后轉而執行別的子程序,在適當的時候再返回來接著執行。 最大的優勢就是協程極高...
閱讀 2987·2021-11-23 09:51
閱讀 1011·2021-09-26 09:55
閱讀 3959·2021-09-22 14:58
閱讀 1486·2021-09-08 09:35
閱讀 1082·2021-08-26 14:16
閱讀 886·2019-08-23 18:17
閱讀 2067·2019-08-23 16:45
閱讀 704·2019-08-23 15:55