<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] ## 3、對于操作系統而言進程、線程以及Goroutine協程的區別 進程、線程、協程實際上都是為并發而生。 但是他們的各自的模樣是完全不一致的,下面我們來分析一下他們各自的特點和關系。 > 本文不重點介紹什么是進程和線程,而是提煉進程、線程、協程干貨。且是基于Linux下的進程、線程解釋 ### 一、進程內存 進程,可執行程序運行中形成一個獨立的內存體,這個內存體**有自己獨立的地址空間(Linux會給每個進程分配一個虛擬內存空間32位操作系統為4G, 64位為很多T),有自己的堆**,上級掛靠單位是操作系統。**操作系統會以進程為單位,分配系統資源(CPU時間片、內存等資源),進程是資源分配的最小單位**。 ![](https://img.kancloud.cn/0c/b1/0cb1ed04a93464cb956ea90c665bc753_1920x1080.jpeg) ### 二、線程內存 **線程,有時被稱為輕量級進程(Lightweight Process,LWP),是操作系統調度(CPU調度)執行的最小單位**。 ![](https://img.kancloud.cn/2d/ed/2dedacbd2329a32154ff7c67daa32014_1920x1080.jpeg) 多個線程共同“寄生”在一個進程上,除了擁有各自的棧空間,其他的內存空間都是一起共享。所以由于這個特性,使得線程之間的內存關聯性很大,互相通信就很簡單(堆區、全局區等數據都共享,需要加鎖機制即可完成同步通信),但是同時也讓線程之間生命體聯系較大,比如一個線程出問題,到底進程問題,也就導致了其他線程問題。 ### 三、執行單元 對于Linux來講,不區分進程還是線程,他們都是一個單獨的執行單位,CPU一視同仁,均分配時間片。 ![](https://img.kancloud.cn/c1/71/c171ab94f524ca77454c5d073e92d37b_1920x1080.jpeg) 所以,如果一個進程想更大程度的與其他進程搶占CPU的資源,那么多開線程是一個好的辦法。 如上圖,進程A沒有開線程,那么默認就是`1個線程`,對于內核來講,它只有1個`執行單元`,進程B開了`3個線程`,那么在內核中,該進程就占有3個`執行單元`。CPU的視野是只能看見內核的,它不知曉誰是進程和誰是線程,誰和誰是一家人。時間片輪詢平均調度分配。那么進程B擁有的3個單元就有了資源供給的優勢。 ### 四、切換問題與協程 我們通過上述的描述,可以知道,線程越多,進程利用(或者)搶占的cpu資源就越高。 ![](https://img.kancloud.cn/87/bd/87bd387feb78a4c176183aa32ccb09db_1920x1080.jpeg) 那么是不是線程可以無限制的多呢? 答案當然不是的,我們知道,當我們cpu在內核態切換一個`執行單元`的時候,會有一個時間成本和性能開銷 ![](https://img.kancloud.cn/77/cb/77cbfe6b8879c74b91a56df2d5d12346_1920x1080.jpeg) 其中性能開銷至少會有兩個開銷 * 切換內核棧 * 切換硬件上下文 > 這兩個切換,我們沒必要太深入研究,可以理解為他所帶來的后果和影響是 > --- * 保存寄存器中的內容 將之前執行流程的狀態保存。 * CPU高速緩存失效 頁表查找是一個很慢的過程,因此通常使用Cache來緩存常用的地址映射,這樣可以加速頁表查找,這個cache就是TLB.當進程切換后頁表也要進行切換,頁表切換后TLB就失效了,cache失效導致命中率降低,那么虛擬地址轉換為物理地址就會變慢,**表現出來的就是程序運行會變慢**。 > --- 綜上,我們不能夠大量的開辟,因為`線程執行流程`越多,cpu在切換的時間成本越大。很多編程語言就想了辦法,既然我們不能左右和優化cpu切換線程的開銷,那么,我們能否讓cpu內核態不切換`執行單元`, 而是在用戶態切換執行流程呢? 很顯然,我們是沒權限修改操作系統內核機制的,那么只能在用戶態再來一個`偽執行單元`,那么就是`協程`了。 ![](https://img.kancloud.cn/9e/57/9e57356a5c3bae08845455e754a2e887_1920x1080.jpeg) ### 五、協程的切換成本 協程切換比線程切換快主要有兩點: (1)協程切換**完全在用戶空間進行**線程切換涉及**特權模式切換,需要在內核空間完成**; (2)協程切換相比線程切換**做的事情更少**,線程需要有內核和用戶態的切換,系統調用過程。 #### 協程切換成本: 協程切換非常簡單,就是把**當前協程的 CPU 寄存器狀態保存起來,然后將需要切換進來的協程的 CPU 寄存器狀態加載的 CPU 寄存器上**就 ok 了。而且**完全在用戶態進行**,一般來說一次協程上下文切換最多就是**幾十ns** 這個量級。 #### 線程切換成本: 系統內核調度的對象是線程,因為線程是調度的基本單元(進程是資源擁有的基本單元,進程的切換需要做的事情更多,這里占時不討論進程切換),而**線程的調度只有擁有最高權限的內核空間才可以完成**,所以線程的切換涉及到**用戶空間和內核空間的切換**,也就是特權模式切換,然后需要操作系統調度模塊完成**線程調度(task***struct),*而且除了和協程相同基本的 CPU 上下文,還有線程私有的棧和寄存器等,說白了就是上下文比協程多一些,其實簡單比較下 task_strcut 和 任何一個協程庫的 coroutine 的 struct 結構體大小就能明顯區分出來。而且特權模式切換的開銷確實不小,隨便搜一組測試數據 [3],隨便算算都比協程切換開銷大很多。 **進程占用多少內存** 4g **線程占用多少內存** 線程跟不同的操作系統版本有有差異 ```bash $ulimit -s 8192 ``` 單位`kb` 但線程基本都是維持Mb的量級單位,一般是4~64Mb不等, 多數維持約10M上下 **協程占用多少內存** 測試環境 ```bash $ more /proc/cpuinfo | grep "model name" model name : Intel(R) Core(TM) i7-5775R CPU @ 3.30GHz model name : Intel(R) Core(TM) i7-5775R CPU @ 3.30GHz (2個CPU ) $ grep MemTotal /proc/meminfo MemTotal: 2017516 kB (2G內存) $ getconf LONG_BIT 64 (64位操作系統) $ uname -a Linux ubuntu 4.15.0-91-generic #92-Ubuntu SMP Fri Feb 28 11:09:48 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux ``` 測試程序 ```go package main import ( "time" ) func main() { for i := 0; i < 200000; i++ { go func() { time.Sleep(5 * time.Second) }() } time.Sleep(10 * time.Second) } ``` 程序運行前 ```bash top - 00:16:24 up 7:08, 1 user, load average: 0.08, 0.03, 0.01 任務: 288 total, 1 running, 218 sleeping, 0 stopped, 0 zombie %Cpu0 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st %Cpu1 : 0.3 us, 0.3 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 2017516 total, 593836 free, 1163524 used, 260156 buff/cache KiB Swap: 969960 total, 574184 free, 395776 used. 679520 avail Mem ``` free的mem為1163524, 程序運行中 ```bash top - 00:17:12 up 7:09, 1 user, load average: 0.04, 0.02, 0.00 任務: 290 total, 1 running, 220 sleeping, 0 stopped, 0 zombie %Cpu0 : 4.0 us, 1.0 sy, 0.0 ni, 95.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st %Cpu1 : 8.8 us, 1.4 sy, 0.0 ni, 89.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 2017516 total, 89048 free, 1675844 used, 252624 buff/cache KiB Swap: 969960 total, 563688 free, 406272 used. 168812 avail Mem ``` free的mem為1675844, 所以**20萬個協程占用了約 50萬KB****平均一個協程占用約2.5KB** 那么,go的協程切換成本如此小,占用也那么小,是否可以無限開辟呢?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看