婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Golang 之協程的用法講解

Golang 之協程的用法講解

熱門標簽:涿州代理外呼系統 阿克蘇地圖標注 電話機器人軟件免費 評價高的400電話辦理 百度地圖標注后傳給手機 壽光微信地圖標注 外呼系統用什么卡 excel地圖標注分布數據 外呼系統顯本地手機號

一、Golang 線程和協程的區別  

備注:需要區分進程、線程(內核級線程)、協程(用戶級線程)三個概念。

進程、線程 和 協程 之間概念的區別

對于 進程、線程,都是有內核進行調度,有 CPU 時間片的概念,進行 搶占式調度(有多種調度算法)

對于 協程(用戶級線程),這是對內核透明的,也就是系統并不知道有協程的存在,是完全由用戶自己的程序進行調度的,因為是由用戶程序自己控制,那么就很難像搶占式調度那樣做到強制的 CPU 控制權切換到其他進程/線程,通常只能進行 協作式調度,需要協程自己主動把控制權轉讓出去之后,其他協程才能被執行到。

goroutine 和協程區別

本質上,goroutine 就是協程。 不同的是,Golang 在 runtime、系統調用等多方面對 goroutine 調度進行了封裝和處理,當遇到長時間執行或者進行系統調用時,會主動把當前 goroutine 的CPU (P) 轉讓出去,讓其他 goroutine 能被調度并執行,也就是 Golang 從語言層面支持了協程。

Golang 的一大特色就是從語言層面原生支持協程,在函數或者方法前面加 go關鍵字就可創建一個協程。

其他方面的比較

1. 內存消耗方面

每個 goroutine (協程) 默認占用內存遠比 Java 、C 的線程少。    

goroutine:2KB     

線程:8MB

2. 線程和 goroutine 切換調度開銷方面

線程/goroutine 切換開銷方面,goroutine 遠比線程小    

線程:涉及模式切換(從用戶態切換到內核態)、16個寄存器、PC、SP...等寄存器的刷新等。    

goroutine:只有三個寄存器的值修改 - PC / SP / DX.

二、協程底層實現原理  

線程是操作系統的內核對象,多線程編程時,如果線程數過多,就會導致頻繁的上下文切換,這些 cpu 時間是一個額外的耗費。

所以在一些高并發的網絡服務器編程中,使用一個線程服務一個 socket 連接是很不明智的。于是操作系統提供了基于事件模式的異步編程模型。用少量的線程來服務大量的網絡連接和I/O操作。

但是采用異步和基于事件的編程模型,復雜化了程序代碼的編寫,非常容易出錯。因為線程穿插,也提高排查錯誤的難度。

協程,是在應用層模擬的線程,他避免了上下文切換的額外耗費,兼顧了多線程的優點。簡化了高并發程序的復雜度。舉個例子,一個高并發的網絡服務器,每一個socket連接進來,服務器用一個協程來對他進行服務。代碼非常清晰。而且兼顧了性能。

那么,協程是怎么實現的呢?

他和線程的原理是一樣的,當 a線程 切換到 b線程 的時候,需要將 a線程 的相關執行進度壓入棧,然后將 b線程 的執行進度出棧,進入 b線程 的執行序列。協程只不過是在 應用層 實現這一點。但是,協程并不是由操作系統調度的,而且應用程序也沒有能力和權限執行 cpu 調度。怎么解決這個問題?

答案是,協程是基于線程的。內部實現上,維護了一組數據結構和 n 個線程,真正的執行還是線程,協程執行的代碼被扔進一個待執行隊列中,由這 n 個線程從隊列中拉出來執行。這就解決了協程的執行問題。那么協程是怎么切換的呢?答案是:golang 對各種 io函數 進行了封裝,這些封裝的函數提供給應用程序使用,而其內部調用了操作系統的異步 io函數,當這些異步函數返回 busy 或 bloking 時,golang 利用這個時機將現有的執行序列壓棧,讓線程去拉另外一個協程的代碼來執行,基本原理就是這樣,利用并封裝了操作系統的異步函數。包括 linux 的 epoll、select 和 windows 的 iocp、event 等。

由于golang是從編譯器和語言基礎庫多個層面對協程做了實現,所以,golang的協程是目前各類有協程概念的語言中實現的最完整和成熟的。十萬個協程同時運行也毫無壓力。關鍵我們不會這么寫代碼。但是總體而言,程序員可以在編寫 golang 代碼的時候,可以更多的關注業務邏輯的實現,更少的在這些關鍵的基礎構件上耗費太多精力。

三、協程的歷史以及特點  

協程(Coroutine)是在1963年由Melvin E. Conway USAF, Bedford, MA等人提出的一個概念。而且協程的概念是早于線程(Thread)提出的。但是由于協程是非搶占式的調度,無法實現公平的任務調用。也無法直接利用多核優勢。因此,我們不能武斷地說協程是比線程更高級的技術。

盡管,在任務調度上,協程是弱于線程的。但是在資源消耗上,協程則是極低的。一個線程的內存在 MB 級別,而協程只需要 KB 級別。而且線程的調度需要內核態與用戶的頻繁切入切出,資源消耗也不小。

我們把協程的基本特點歸納為:

1. 協程調度機制無法實現公平調度

2. 協程的資源開銷是非常低的,一臺普通的服務器就可以支持百萬協程。   

那么,近幾年為何協程的概念可以大熱。我認為一個特殊的場景使得協程能夠廣泛的發揮其優勢,并且屏蔽掉了劣勢 --> 網絡編程。與一般的計算機程序相比,網絡編程有其獨有的特點。

1. 高并發(每秒鐘上千數萬的單機訪問量)

2. Request/Response。程序生命期端(毫秒,秒級)

3. 高IO,低計算(連接數據庫,請求API)。   

最開始的網絡程序其實就是一個線程一個請求設計的(Apache)。后來,隨著網絡的普及,誕生了C10K問題。Nginx 通過單線程異步 IO 把網絡程序的執行流程進行了亂序化,通過 IO 事件機制最大化的保證了CPU的利用率。

至此,現代網絡程序的架構已經形成。基于IO事件調度的異步編程。其代表作恐怕就屬 NodeJS 了吧。

異步編程的槽點

異步編程為了追求程序的性能,強行的將線性的程序打亂,程序變得非常的混亂與復雜。對程序狀態的管理也變得異常困難。寫過Nginx C Module的同學應該知道我說的是什么。我們開始吐槽 NodeJS 那惡心的層層Callback。

Golang   

在我們瘋狂被 NodeJS 的層層回調惡心到的時候,Golang 作為名門之后開始走入我們的視野。并且迅速的在Web后端極速的跑馬圈地。其代表者 Docker 以及圍繞這 Docker 展開的整個容器生態圈欣欣向榮起來。其最大的賣點 – 協程 開始真正的流行與討論起來。

我們開始向寫PHP一樣來寫全異步IO的程序。看上去美好極了,仿佛世界就是這樣了。

在網絡編程中,我們可以理解為 Golang 的協程本質上其實就是對 IO 事件的封裝,并且通過語言級的支持讓異步的代碼看上去像同步執行的一樣。

四、Golang 協程的應用  

我們知道,協程(coroutine)是Go語言中的輕量級線程實現,由Go運行時(runtime)管理。

在一個函數調用前加上go關鍵字,這次調用就會在一個新的goroutine中并發執行。當被調用的函數返回時,這個goroutine也自動結束。需要注意的是,如果這個函數有返回值,那么這個返回值會被丟棄。

先看一下下面的程序代碼:

func Add(x, y int) {
    z := x + y
    fmt.Println(z)
}
 
func main() {
    for i:=0; i10; i++ {
        go Add(i, i)
    }
}

執行上面的代碼,會發現屏幕什么也沒打印出來,程序就退出了。  

對于上面的例子,main()函數啟動了10個goroutine,然后返回,這時程序就退出了,而被啟動的執行 Add() 的 goroutine 沒來得及執行。我們想要讓 main() 函數等待所有 goroutine 退出后再返回,但如何知道 goroutine 都退出了呢?這就引出了多個goroutine之間通信的問題。

在工程上,有兩種最常見的并發通信模型:共享內存 和 消息。

下面的例子,使用了鎖變量(屬于一種共享內存)來同步協程,事實上 Go 語言主要使用消息機制(channel)來作為通信模型

package main 
import (
    "fmt"
    "sync"
    "runtime"
)
 
var counter int = 0 
func Count(lock *sync.Mutex) {
    lock.Lock() // 上鎖
    counter++
    fmt.Println("counter =", counter)
    lock.Unlock()   // 解鎖
}
 
func main() {
    lock := sync.Mutex{}
 
    for i:=0; i10; i++ {
        go Count(lock)
    }
    for {
        lock.Lock() // 上鎖
        c := counter
        lock.Unlock()   // 解鎖
 
        runtime.Gosched() // 出讓時間片
 
        if c >= 10 {
            break
        }
    }
}

channel

消息機制認為每個并發單元是自包含的、獨立的個體,并且都有自己的變量,但在不同并發單元間這些變量不共享。每個并發單元的輸入和輸出只有一種,那就是消息。

channel 是 Go 語言在語言級別提供的 goroutine 間的通信方式,我們可以使用 channel 在多個 goroutine 之間傳遞消息。channel是進程內的通信方式,因此通過 channel 傳遞對象的過程和調用函數時的參數傳遞行為比較一致,比如也可以傳遞指針等。channel 是類型相關的,一個 channel 只能傳遞一種類型的值,這個類型需要在聲明 channel 時指定。

channel的聲明形式為:

var chanName chan ElementType

舉個例子,聲明一個傳遞int類型的channel:

var ch chan int

使用內置函數 make() 定義一個channel:

ch := make(chan int)

在channel的用法中,最常見的包括寫入和讀出:

// 將一個數據value寫入至channel,這會導致阻塞,直到有其他goroutine從這個channel中讀取數據
ch - value
// 從channel中讀取數據,如果channel之前沒有寫入數據,也會導致阻塞,直到channel中被寫入數據為止
value := -ch

默認情況下,channel的接收和發送都是阻塞的,除非另一端已準備好。

我們還可以創建一個帶緩沖的channel:

c := make(chan int, 1024)
// 從帶緩沖的channel中讀數據
for i:=range c {
  ...
}

此時,創建一個大小為1024的int類型的channel,即使沒有讀取方,寫入方也可以一直往channel里寫入,在緩沖區被填完之前都不會阻塞。

可以關閉不再使用的channel:

close(ch)

應該在生產者的地方關閉channel,如果在消費者的地方關閉,容易引起panic;

現在利用channel來重寫上面的例子:

func Count(ch chan int) {
    ch - 1
    fmt.Println("Counting")
}
 
func main() {
 
    chs := make([] chan int, 10)
 
    for i:=0; i10; i++ {
        chs[i] = make(chan int)
        go Count(chs[i])
    }
 
    for _, ch := range(chs) {
        -ch
    }
}

在這個例子中,定義了一個包含10個channel的數組,并把數組中的每個channel分配給10個不同的goroutine。在每個goroutine完成后,向goroutine寫入一個數據,在這個channel被讀取前,這個操作是阻塞的。

在所有的goroutine啟動完成后,依次從10個channel中讀取數據,在對應的channel寫入數據前,這個操作也是阻塞的。

這樣,就用channel實現了類似鎖的功能,并保證了所有goroutine完成后main()才返回。

另外,我們在將一個channel變量傳遞到一個函數時,可以通過將其指定為單向channel變量,從而限制該函數中可以對此channel的操作。

select

在UNIX中,select()函數用來監控一組描述符,該機制常被用于實現高并發的socket服務器程序。Go語言直接在語言級別支持select關鍵字,用于處理異步IO問題,大致結構如下:

select {
    case - chan1:
    // 如果chan1成功讀到數據
     
    case chan2 - 1:
    // 如果成功向chan2寫入數據
 
    default:
    // 默認分支
}

select默認是阻塞的,只有當監聽的channel中有發送或接收可以進行時才會運行,當多個channel都準備好的時候,select是隨機的選擇一個執行的。

Go語言沒有對channel提供直接的超時處理機制,但我們可以利用select來間接實現,例如:

timeout := make(chan bool, 1) 
go func() {
    time.Sleep(1e9)
    timeout - true
}()
 
switch {
    case - ch:
    // 從ch中讀取到數據
 
    case - timeout:
    // 沒有從ch中讀取到數據,但從timeout中讀取到了數據
}

這樣使用select就可以避免永久等待的問題,因為程序會在timeout中獲取到一個數據后繼續執行,而無論對ch的讀取是否還處于等待狀態。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。

您可能感興趣的文章:
  • Go 并發實現協程同步的多種解決方法
  • go等待一組協程結束的操作方式
  • golang協程池模擬實現群發郵件功能
  • 解決go在函數退出后子協程的退出問題
  • Go使用協程交替打印字符
  • go 協程返回值處理操作
  • 淺談golang for 循環中使用協程的問題
  • Go并發:使用sync.WaitGroup實現協程同步方式

標簽:蘭州 雞西 汕頭 梅河口 吐魯番 重慶 銅川 欽州

巨人網絡通訊聲明:本文標題《Golang 之協程的用法講解》,本文關鍵詞  Golang,之協,程,的,用法,講解,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Golang 之協程的用法講解》相關的同類信息!
  • 本頁收集關于Golang 之協程的用法講解的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    国产欧美精品一区| 奇米一区二区三区av| 婷婷中文字幕综合| 国产精品一区二区免费不卡| 色综合网色综合| 久久久亚洲精品一区二区三区 | 日本亚洲最大的色成网站www| 国产麻豆精品在线| 欧美三级电影在线看| 欧美经典一区二区| 免费高清成人在线| 欧美群妇大交群中文字幕| 国产精品色哟哟| 国产一区二区看久久| 欧美精品亚洲二区| 亚洲电影中文字幕在线观看| 成人晚上爱看视频| 欧美韩国日本一区| 久久99久久久久| 欧美一二区视频| 日本不卡免费在线视频| 欧美日韩三级视频| 亚洲成人免费在线| 91黄色免费看| 亚洲乱码国产乱码精品精98午夜 | 国产精品一级片在线观看| 91麻豆精品国产综合久久久久久| 亚洲一区欧美一区| 欧美色综合久久| 亚洲激情图片qvod| 91豆麻精品91久久久久久| 亚洲日本va午夜在线影院| 成人精品视频一区二区三区| 久久久久久综合| 国产成人h网站| 国产日韩欧美精品综合| 成人aaaa免费全部观看| 国产日韩精品一区二区浪潮av| 国产伦精品一区二区三区免费| 日韩精品一区二区三区在线| 毛片av中文字幕一区二区| 欧美成人精品福利| 国内成人精品2018免费看| 久久中文字幕电影| 99久久精品免费看国产免费软件| 亚洲特级片在线| 在线观看视频91| 天堂蜜桃一区二区三区| 欧美一级一级性生活免费录像| 麻豆一区二区99久久久久| 欧美国产欧美综合| 91国产成人在线| 七七婷婷婷婷精品国产| 久久综合av免费| 一本色道亚洲精品aⅴ| 日韩va欧美va亚洲va久久| 久久人人97超碰com| 成人国产精品免费网站| 亚洲电影在线播放| 精品人在线二区三区| 99久久婷婷国产| 五月婷婷综合网| 国产拍欧美日韩视频二区| 在线观看免费视频综合| 另类综合日韩欧美亚洲| 国产精品美女久久久久久久| 欧美性一区二区| 久久av老司机精品网站导航| 中文字幕av一区二区三区高| 日本精品视频一区二区| 国产精品性做久久久久久| 亚洲国产日韩综合久久精品| 欧美精品一区二区三区视频| 97精品电影院| 久久99精品国产麻豆婷婷| 亚洲欧美国产三级| 欧美一区二区三区喷汁尤物| 成人18视频日本| 精品午夜久久福利影院| 亚洲午夜电影在线| 中文字幕不卡在线播放| 日韩免费成人网| 欧美丝袜第三区| 国产91精品免费| 日本91福利区| 亚洲自拍另类综合| 国产精品毛片无遮挡高清| 91精品午夜视频| 欧美专区亚洲专区| 99视频热这里只有精品免费| 国产一区二区看久久| 日本 国产 欧美色综合| 亚洲第一二三四区| 亚洲天堂成人在线观看| 欧美国产激情二区三区| 久久综合久久鬼色| 日韩欧美一区二区三区在线| 欧美日韩在线三区| 欧亚洲嫩模精品一区三区| 成年人网站91| 成人性视频网站| 国产老肥熟一区二区三区| 欧美aⅴ一区二区三区视频| 亚洲一区视频在线| 一区二区三区在线视频观看 | 蜜臀久久久99精品久久久久久| 一区二区三区视频在线观看| 国产精品成人一区二区三区夜夜夜| 久久综合狠狠综合久久综合88 | 一本久道久久综合中文字幕| 成人免费视频播放| av电影一区二区| 99精品国产99久久久久久白柏| 成人一区二区在线观看| 粉嫩嫩av羞羞动漫久久久| 国产白丝网站精品污在线入口| 高清日韩电视剧大全免费| 国产成人自拍网| 岛国一区二区在线观看| 成人动漫一区二区三区| av一区二区不卡| 99re在线视频这里只有精品| 91捆绑美女网站| 欧美亚洲丝袜传媒另类| 欧美伦理电影网| 欧美一区二区三区成人| 精品福利二区三区| 国产欧美一区二区三区在线看蜜臀 | 免费高清成人在线| 黄色小说综合网站| 粉嫩绯色av一区二区在线观看| 国产jizzjizz一区二区| 成人sese在线| 欧美偷拍一区二区| 日韩精品一区二区三区在线播放 | 日韩一区二区精品在线观看| 欧美大片一区二区| 国产蜜臀av在线一区二区三区| 国产精品第四页| 婷婷综合另类小说色区| 国产精品资源在线看| 97久久精品人人澡人人爽| 欧美日韩精品福利| 久久午夜国产精品| 亚洲欧美日韩精品久久久久| 亚洲第一电影网| 国产在线视频一区二区| 色噜噜夜夜夜综合网| 日韩免费看的电影| 亚洲人成亚洲人成在线观看图片| 日本一不卡视频| 99re66热这里只有精品3直播 | 欧美成人伊人久久综合网| 国产精品无码永久免费888| 一区二区三区影院| 国产麻豆视频精品| 欧美性感一区二区三区| 欧美极品美女视频| 麻豆精品在线看| 色噜噜偷拍精品综合在线| 久久这里只有精品首页| 亚洲线精品一区二区三区八戒| 国产高清无密码一区二区三区| 欧美美女喷水视频| 国产精品麻豆视频| 国内精品嫩模私拍在线| 欧美视频中文字幕| 国产精品久久久久影院亚瑟| 毛片基地黄久久久久久天堂| 欧美午夜电影一区| 国产精品无圣光一区二区| 精品伊人久久久久7777人| 欧美日韩高清在线播放| 一区二区三区四区五区视频在线观看| 国产成人精品一区二区三区网站观看| 在线电影国产精品| 亚洲影院在线观看| av中文一区二区三区| 久久久综合视频| 久久99精品一区二区三区| 91精品黄色片免费大全| 亚洲午夜久久久久久久久电影院| av影院午夜一区| 欧美韩国一区二区| 国产激情视频一区二区在线观看| 日韩一卡二卡三卡国产欧美| 亚洲成人在线免费| 欧美老肥妇做.爰bbww视频| 亚洲精品菠萝久久久久久久| 色综合久久久久网| 亚洲欧洲精品天堂一级| 成人丝袜高跟foot| 一区精品在线播放| 99在线热播精品免费| 亚洲视频香蕉人妖| 在线免费观看一区| 亚洲综合无码一区二区| 欧美在线不卡一区| 亚洲成va人在线观看| 日韩精品一区二区三区中文不卡|