<input id="ohw05"></input>
  • <table id="ohw05"><menu id="ohw05"></menu></table>
  • <var id="ohw05"></var>
  • <code id="ohw05"><cite id="ohw05"></cite></code>
    <label id="ohw05"></label>
    <var id="ohw05"></var>
  • Ruby的GIL

     

    一、什么是GIL

    GIL即全局解釋鎖(global interpreter lock),這個鎖環繞著Ruby代碼的執行,在一個多線程上下文中,任何時候只有一個線程可以執行Ruby代碼。因此即使在多核的機器上運行多線程應用,在特定時間點上也只有一個線程和一個核心在忙碌,GIL一直保護著Ruby內核,以免競爭條件造成數據混亂。

     

    二、GIL產生原因

    首先,Ruby線程依托于原生操作系統線程,所以Ruby線程的調度也是源于操作系統的線程調度程序。其次,對于Ruby來說其實沒有什么操作是線程安全的,比如最簡單的數組附加,如下:

    arr = []
    arr << ‘str1’

    Ruby中的數組附加其實包含許多步驟,在其底層實現上是包含一大堆代碼:

    VALUE rb_ary_push(VALUE ary, VALUE iterm)
    {
        long idx = RARRAY_LEN(ary);
        ary_ensure_room_for_push(ary, 1);
        RARRAY_ASET(ary, idx, item);
        ARY_SET_LEN(ary, idx + 1);
        return ary;
    }

    這段代碼揭示了數據附加包含以下幾個步驟:

    1.    獲取數組當前長度;

    2.    檢查數組是否有空間容納新的元素;

    3.    將元素附加到數組;

    4.    修改數據長度+1

    由于這么一系列操作不是線程安全的,所以在多線程應用中,會頻繁發生上下文切換,這樣就可能會發生一些匪夷所思的錯誤,為此,我們需要使這些操作具有原子性,所以我們需要使用GIL來解決這個問題。GIL保衛著系統的內部狀態,使用GIL,就不需要在數據結構周圍使用任何鎖或者同步機制。如果兩個線程不能夠同時改變內部狀態,也就不會有競爭條件發生了。

     

    三、GIL的實現原理

    Ruby的線程依托于原生的操作系統的線程,但是當一個Ruby線程希望在其原生操作系統線程中執行代碼的時,必須要先獲得GIL,如下圖所示,在特定時間點上只有一個線程可以獲取GIL,于是Ruby的代碼執行是完全不能并行的。

     

    那么Ruby如何保證GIL被線程獨霸呢?Ruby提供了一個計時器線程,這個線程是僅存在于Ruby內部的原生線程,當Ruby啟動并只有主線程運行時,定時器線程處于沉睡狀態,但一旦有線程等待GIL,定時器線程就會被喚醒。定時器線程是用于避免一個線程獨霸GIL的情況,每經過一定周期,定時器線程在當前持有GIL的線程上設置一個中斷標志,Ruby會檢查這些中斷標志,被設置中斷標志的線程會停止運行并釋放GIL,這樣,別的線程就可以獲取GIL繼而執行其代碼。

     

     

    四、總結

    GILRuby內部實現細節,是為了保證Ruby內部執行的安全,它保證了RubyC實現的底層方法的原子性

    PS:以上內容都是基于CRuby的,對于JRuby或者Rubinius來說,它們是可以真正做到多線程并發執行的。

    posted @ 2022-05-12 00:40  阿拉懶神燈  閱讀(16)  評論(0編輯  收藏  舉報
    国产美女a做受大片观看