1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務時間:8:30-17:00
      你可能遇到了下面的問題
      關閉右側工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      go語言如何使用模型 go語言的應用

      Go CSP并發(fā)模型

      Go的CSP并發(fā)模型

      創(chuàng)新互聯(lián)從2013年成立,先為臨滄等服務建站,臨滄等地企業(yè),進行企業(yè)商務咨詢服務。為臨滄企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務解決您的所有建站問題。

      Go實現(xiàn)了兩種并發(fā)形式。第一種是大家普遍認知的:多線程共享內(nèi)存。其實就是Java或者C++等語言中的多線程開發(fā)。另外一種是Go語言特有的,也是Go語言推薦的:CSP(communicating sequential processes)并發(fā)模型。

      CSP 是 Communicating Sequential Process 的簡稱,中文可以叫做通信順序進程,是一種并發(fā)編程模型,由 Tony Hoare 于 1977 年提出。簡單來說,CSP 模型由并發(fā)執(zhí)行的實體(線程或者進程)所組成,實體之間通過發(fā)送消息進行通信,這里發(fā)送消息時使用的就是通道,或者叫 channel。CSP 模型的關鍵是關注 channel,而不關注發(fā)送消息的實體。 Go 語言實現(xiàn)了 CSP 部分理論 。

      “ 不要以共享內(nèi)存的方式來通信,相反, 要通過通信來共享內(nèi)存。”

      Go的CSP并發(fā)模型,是通過 goroutine和channel 來實現(xiàn)的。

      goroutine 是Go語言中并發(fā)的執(zhí)行單位。其實就是協(xié)程。

      channel是Go語言中各個并發(fā)結構體(goroutine)之前的通信機制。 通俗的講,就是各個goroutine之間通信的”管道“,有點類似于Linux中的管道。

      Channel

      Goroutine

      Go語言——goroutine并發(fā)模型

      參考:

      Goroutine并發(fā)調(diào)度模型深度解析手擼一個協(xié)程池

      Golang 的 goroutine 是如何實現(xiàn)的?

      Golang - 調(diào)度剖析【第二部分】

      OS線程初始棧為2MB。Go語言中,每個goroutine采用動態(tài)擴容方式,初始2KB,按需增長,最大1G。此外GC會收縮棧空間。

      BTW,增長擴容都是有代價的,需要copy數(shù)據(jù)到新的stack,所以初始2KB可能有些性能問題。

      更多關于stack的內(nèi)容,可以參見大佬的文章。 聊一聊goroutine stack

      用戶線程的調(diào)度以及生命周期管理都是用戶層面,Go語言自己實現(xiàn)的,不借助OS系統(tǒng)調(diào)用,減少系統(tǒng)資源消耗。

      Go語言采用兩級線程模型,即用戶線程與內(nèi)核線程KSE(kernel scheduling entity)是M:N的。最終goroutine還是會交給OS線程執(zhí)行,但是需要一個中介,提供上下文。這就是G-M-P模型

      Go調(diào)度器有兩個不同的運行隊列:

      go1.10\src\runtime\runtime2.go

      Go調(diào)度器根據(jù)事件進行上下文切換。

      調(diào)度的目的就是防止M堵塞,空閑,系統(tǒng)進程切換。

      詳見 Golang - 調(diào)度剖析【第二部分】

      Linux可以通過epoll實現(xiàn)網(wǎng)絡調(diào)用,統(tǒng)稱網(wǎng)絡輪詢器N(Net Poller)。

      文件IO操作

      上面都是防止M堵塞,任務竊取是防止M空閑

      每個M都有一個特殊的G,g0。用于執(zhí)行調(diào)度,gc,棧管理等任務,所以g0的棧稱為調(diào)度棧。g0的棧不會自動增長,不會被gc,來自os線程的棧。

      go1.10\src\runtime\proc.go

      G沒辦法自己運行,必須通過M運行

      M通過通過調(diào)度,執(zhí)行G

      從M掛載P的runq中找到G,執(zhí)行G

      Golang的調(diào)度模型

      Go有四大核心模塊,基本全部體現(xiàn)在runtime,有調(diào)度系統(tǒng)、GC、goroutine、channel,那么深入理解其中的精髓可以幫助我們理解Go這一門語言!

      參考: 調(diào)度系統(tǒng)設計精要

      下面是我用Go語言簡單寫的一個調(diào)度器,大家可以看看設計思路,以及存在的問題!

      1、測試條件,調(diào)度器只啟動兩個線程,然后一個線程主要是負責循環(huán)的添加任務,一個線程循環(huán)的去執(zhí)行任務

      2、測試條件,調(diào)度器啟動三個線程,然后兩個線程去執(zhí)行任務,一個添加任務

      3、繼續(xù)測試,啟動十個線程,一個添加任務,九個執(zhí)行任務

      4、我們添加一些阻塞的任務

      執(zhí)行可以看到完全不可用

      1、 可以看到隨著M的不斷的增加,可以發(fā)現(xiàn)執(zhí)行任務的數(shù)量也不斷的減少,原因是什么呢?有興趣的同學可以加一個pprof可以看看,其實大量的在等待鎖的過程!

      2、如果我的M運行了類似于Sleep操作的方法如何解決了,我的調(diào)度器還能支撐這個量級的調(diào)度嗎?

      關于pprof如何使用:在代碼頭部加一個這個代碼:

      我們查看一下 go tool pprof main/prof.pporf

      可以看到真正執(zhí)行代碼的時間只有 0.17s + 0.02s 其他時間都被阻塞掉了!

      1、GM模型中的所有G都是放入到一個queue,那么導致所有的M取執(zhí)行任務時都會去競爭鎖,我們插入G也會去競爭鎖,所以解決這種問題一般就是減少對單一資源的競爭,那就是桶化,其實就是每個線程都分配一個隊列

      2、GM模型中沒有任務狀態(tài),只有runnable,假如任務遇到阻塞,完全可以把任務掛起再喚醒

      這里其實會遇到一個問題,假如要分配很多個線程,那么此時隨著線程的增加,也會造成隊列的增加,其實也會造成調(diào)度器的壓力,因為它需要遍歷全部線程的隊列去分配任務以及后續(xù)會講到的竊取任務!

      因為我們知道CPU的最大并行度其實取決于CPU的核數(shù),也就是我們沒必要為每個線程都去分配一個隊列,因為就算是給他們分配了,他們自己去那執(zhí)行調(diào)度,其實也會出現(xiàn)大量阻塞,原因就是CPU調(diào)度不過來這些線程!

      Go里面是只分配了CPU個數(shù)的隊列,這里就是P這個概念,你可以理解為P其實是真正的資源分配器,M很輕只是執(zhí)行程序,所有的資源內(nèi)存都維護在P上!M只有綁定P才能執(zhí)行任務(強制的)!

      這樣做的好處:

      1、首先調(diào)度程序其實就是調(diào)度不同狀態(tài)的任務,go里面為Go標記了不同的狀態(tài),其實大概就是分為:runnable,running,block等,所以如何充分調(diào)度不同狀態(tài)的G成了問題,那么關于阻塞的G如何解決,其實可以很好的解決G調(diào)度的問題!

      上面這些情況其實就分為:

      2、用戶態(tài)阻塞,一般Go里面依靠 gopark 函數(shù)去實現(xiàn),大體的代碼邏輯基本上和go的調(diào)度綁定死了

      源碼在:

      3、其實對于netpool 這種nio模型,其實內(nèi)核調(diào)用是非阻塞的,所以go開辟了一個網(wǎng)絡輪訓器隊列,來存放這些被阻塞的g,等待內(nèi)核被喚醒!那么什么時候會被喚醒了,其實就是需要等待調(diào)度器去調(diào)度了!

      4、如果是內(nèi)核態(tài)阻塞了(內(nèi)核態(tài)阻塞一般都會將線程掛起,線程需要等待被喚醒),我們此時P只能放棄此線程的權利,然后再找一個新的線程去運行P!

      關于著新線程:找有沒有idle的線程,沒有就會創(chuàng)建一個新的線程!

      關于當內(nèi)核被喚醒后的操作:因為GPM模型所以需要找到個P綁定,所以G會去嘗試找一個可用的P,如果沒有可用的P,G會標記為runnable放到全局隊列中!

      5、其實了解上面大致其實就了解了Go的基本調(diào)度模型

      答案文章里慢慢品味!

      如果某個 G 執(zhí)行時間過長,其他的 G 如何才能被正常的調(diào)度? 這便涉及到有關調(diào)度的兩個理念:協(xié)作式調(diào)度與搶占式調(diào)度。協(xié)作式和搶占式這兩個理念解釋起來很簡單: 協(xié)作式調(diào)度依靠被調(diào)度方主動棄權;搶占式調(diào)度則依靠調(diào)度器強制將被調(diào)度方被動中斷。

      例如下面的代碼,我本地的版本是 go1.13.5

      執(zhí)行: GOMAXPROCS=1 配置全局只能有一個P

      可以看到main函數(shù)無法執(zhí)行!也就是那個go 空轉搶占了整個程序

      備注:

      但是假如我換為用 1.14+版本執(zhí)行,有興趣的話可以使用我的docker鏡像,直接可以拉取: fanhaodong/golang:1.15.11 和 fanhaodong/golang:1.13.5

      首先我們知道G/M/P,G可能和M也可能和P解除綁定,那么關于數(shù)據(jù)變量放在哪哇!其實這個就是逃逸分析!

      輸出可以看到其實沒有發(fā)生逃逸,那是因為 demo被拷貝它自己的棧空間內(nèi)

      備注:

      -gcflags"-N -l -m" 其中 -N禁用優(yōu)化-l禁止內(nèi)聯(lián)優(yōu)化,-m打印逃逸信息

      那么繼續(xù)改成這個

      可以看到發(fā)現(xiàn) demo對象其實被逃逸到了堆上!這就是不會出現(xiàn)類似于G如果被別的M執(zhí)行,其實不會出現(xiàn)內(nèi)存分配位置的問題!

      所以可以看到demo其實是copy到了堆上!這就是g逃逸的問題,和for循環(huán)一樣的

      執(zhí)行可以發(fā)現(xiàn),其實x已經(jīng)逃逸到了堆上,所以你所有的g都引用的一個對象,如何解決了

      如何解決了,其實很簡單

      也談goroutine調(diào)度器

      圖解Go運行時調(diào)度器

      Go語言回顧:從Go 1.0到Go 1.13

      Go語言原本

      調(diào)度系統(tǒng)設計精要

      Scalable Go Scheduler Design Doc

      golang的線程模型——GMP模型

      內(nèi)核線程(Kernel-Level Thread ,KLT)

      輕量級進程(Light Weight Process,LWP):輕量級進程就是我們通常意義上所講的線程,由于每個輕量級進程都由一個內(nèi)核線程支持,因此只有先支持內(nèi)核線程,才能有輕量級進程

      用戶線程與系統(tǒng)線程一一對應,用戶線程執(zhí)行如lo操作的系統(tǒng)調(diào)用時,來回切換操作開銷相對比較大

      多個用戶線程對應一個內(nèi)核線程,當內(nèi)核線程對應的一個用戶線程被阻塞掛起時候,其他用戶線程也阻塞不能執(zhí)行了。

      多對多模型是可以充分利用多核CPU提升運行效能的

      go線程模型包含三個概念:內(nèi)核線程(M),goroutine(G),G的上下文環(huán)境(P);

      GMP模型是goalng特有的。

      P與M一般是一一對應的。P(上下文)管理著一組G(goroutine)掛載在M(內(nèi)核線程)上運行,圖中左邊藍色為正在執(zhí)行狀態(tài)的goroutine,右邊為待執(zhí)行狀態(tài)的goroutiine隊列。P的數(shù)量由環(huán)境變量GOMAXPROCS的值或程序運行runtime.GOMAXPROCS()進行設置。

      當一個os線程在執(zhí)行M1一個G1發(fā)生阻塞時,調(diào)度器讓M1拋棄P,等待G1返回,然后另起一個M2接收P來執(zhí)行剩下的goroutine隊列(G2、G3...),這是golang調(diào)度器厲害的地方,可以保證有足夠的線程來運行剩下所有的goroutine。

      當G1結束后,M1會重新拿回P來完成,如果拿不到就丟到全局runqueue中,然后自己放到線程池或轉入休眠狀態(tài)。空閑的上下文P會周期性的檢查全局runqueue上的goroutine,并且執(zhí)行它。

      另一種情況就是當有些P1太閑而其他P2很忙碌的時候,會從其他上下文P2拿一些G來執(zhí)行。

      詳細可以翻看下方第一個參考鏈接,寫得真好。

      最后用大佬的總結來做最后的收尾————

      Go語言運行時,通過核心元素G,M,P 和 自己的調(diào)度器,實現(xiàn)了自己的并發(fā)線程模型。調(diào)度器通過對G,M,P的調(diào)度實現(xiàn)了兩級線程模型中操作系統(tǒng)內(nèi)核之外的調(diào)度任務。整個調(diào)度過程中會在多種時機去觸發(fā)最核心的步驟 “一整輪調(diào)度”,而一整輪調(diào)度中最關鍵的部分在“全力查找可運行G”,它保證了M的高效運行(換句話說就是充分使用了計算機的物理資源),一整輪調(diào)度中還會涉及到M的啟用停止。最后別忘了,還有一個與Go程序生命周期相同的系統(tǒng)監(jiān)測任務來進行一些輔助性的工作。

      淺析Golang的線程模型與調(diào)度器

      Golang CSP并發(fā)模型

      Golang線程模型


      本文題目:go語言如何使用模型 go語言的應用
      文章轉載:http://www.ef60e0e.cn/article/ddjhigj.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        固阳县| 平南县| 泸西县| 维西| 金塔县| 龙岩市| 会理县| 边坝县| 迭部县| 曲阜市| 四会市| 许昌县| 鄂尔多斯市| 克拉玛依市| 黑龙江省| 虹口区| 四川省| 南平市| 平遥县| 大城县| 怀仁县| 庐江县| 澎湖县| 鲜城| 清流县| 慈溪市| 田林县| 全椒县| 汾阳市| 林甸县| 峨边| 平南县| 淅川县| 江北区| 怀化市| 辽宁省| 泌阳县| 贡觉县| 沂南县| 巴楚县| 中西区|