亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go?并發(fā)編程協(xié)程及調(diào)度機(jī)制詳情

 更新時間:2022年09月08日 11:13:27   作者:宇宙之一粟  
這篇文章主要介紹了Go并發(fā)編程協(xié)程及調(diào)度機(jī)制詳情,協(xié)程是Go語言最大的特色之一,goroutine的實現(xiàn)其實是通過協(xié)程,更多相關(guān)內(nèi)容需要的朋友可以參考一下

前言:

協(xié)程(coroutine)是 Go 語言最大的特色之一,goroutine 的實現(xiàn)其實是通過協(xié)程。

協(xié)程的概念

協(xié)程一詞最早出現(xiàn)在 1963 年發(fā)表的論文中,該論文的作者為美國計算機(jī)科學(xué)家 Melvin E.Conway。著名的康威定律:“設(shè)計系統(tǒng)的架構(gòu)受制于產(chǎn)生這些設(shè)計的組織的溝通結(jié)構(gòu)。” 也是這個作者。

協(xié)程是一種用戶態(tài)的輕量級線程,可以想成一個線程里面可以有多個協(xié)程,而協(xié)程的調(diào)度完全由用戶控制,協(xié)程也會有自己的 registers、context、stack 等等,并且由協(xié)程的調(diào)度器來控制說目前由哪個協(xié)程執(zhí)行,哪個協(xié)程要被 block 住。

而相對于 Thread 及 Process 的調(diào)度,則是由 CPU 內(nèi)核去進(jìn)行調(diào)度,因此操作系統(tǒng)其實會有所謂許多的調(diào)度算法,并且可以進(jìn)行搶占式調(diào)度,可以主動搶奪執(zhí)行的控制權(quán)。

反之,協(xié)程是不行的,只能進(jìn)行非搶占式的調(diào)度。 可以理解成,如果 coroutine 被 block 住,則會在用戶態(tài)直接切換另外一個 coroutine 給此 thread 繼續(xù)執(zhí)行,這樣其他 coroutine 就不會被 block 住,讓資源能夠有效的被利用,借此實現(xiàn) Concurrent 的概念。

協(xié)程與線程

線程 是 CPU 調(diào)度的基本單位,多個線程可以通過共享進(jìn)程的資源,通過共享內(nèi)存等方式來進(jìn)行線程間通信。

協(xié)程 可理解為輕量級線程,與線程相比,協(xié)程不受操作系統(tǒng)系統(tǒng)調(diào)度,協(xié)程調(diào)度由用戶應(yīng)用程序提供,協(xié)程調(diào)度器按照調(diào)度策略把協(xié)程調(diào)度到線程中運(yùn)行。

  • 協(xié)程只需花幾 KB 就可以被創(chuàng)立,線程則需要幾 MB 的內(nèi)存才能創(chuàng)立
  • 切換開銷方面,協(xié)程遠(yuǎn)遠(yuǎn)低于線程,切換的速度也因此大幅提升

goroutine 的誕生

Golang 語言的 goroutine 其實就是協(xié)程,特別的是在語言層面直接原生支持創(chuàng)立協(xié)程,并在 runtime、系統(tǒng)調(diào)用等多方面對 goroutine 調(diào)度進(jìn)行封裝及處理。

相對于 Java 的建立線程,操作系統(tǒng)是會直接建立一個線程與其對應(yīng),而多個線程的間互相切換需要通過內(nèi)核線程來進(jìn)行,會有較大的上下文切換開銷,造成的資源耗費(fèi),而 goroutine 是在代碼上直接實現(xiàn)切換,不需要經(jīng)過內(nèi)核線程。

goroutine 的優(yōu)勢:

  • 與線程相比, goroutine 非常便宜,可以根據(jù)應(yīng)用程序的需求自動分配, 但在線程的大小通常是固定的
  • 使用 goroutine 訪問共享內(nèi)存的時候 透過 channel 可以避免競態(tài)條件的發(fā)生

比如,我們計算一個數(shù)字的質(zhì)數(shù),可以寫出如下的代碼:

package main

import (
	"fmt"
	"time"
)

func main() {
	num := 300000
	start := time.Now()
	for i := 1; i <= num; i++ {
		if isPrime(i) {
			fmt.Println(i)
		}
	}
	end := time.Now()
	fmt.Println(end.Unix()-start.Unix(), "seconds")
}
func isPrime(num int) bool {
	if num == 1 {
		return false
	} else if num == 2 {
		return true
	} else {
		for i := 2; i < num; i++ {
			if num%i == 0 {
				return false
			}
		}
		return true
	}
}

上面的代碼用 num := 300000 來測試,也就是從 1~300000 之間來看那些數(shù)字會是質(zhì)數(shù),如果是質(zhì)數(shù)的話就把質(zhì)數(shù)輸出,最后看到最終花費(fèi)了 37 秒。運(yùn)行結(jié)果如下:

使用 goroutine 加快速度

package main

import (
	"fmt"
	"time"
)

func main() {
	num := 300000
	start := time.Now()
	for i := 1; i <= num; i++ {
		go findPrimes(i)
	}

	end := time.Now()
	time.Sleep(5 * time.Second)
	fmt.Println(end.Unix()-start.Unix(), "seconds")
}

func findPrimes(num int) {
	if num == 1 {
		return
	} else if num == 2 {
		fmt.Println(num)
	} else {
		for i := 2; i < num; i++ {
			if num%i == 0 {
				return
			}
		}
		fmt.Println(num)
	}
}

go findPrimes 這條語句就可以開啟一個 goroutine,因此以主程序來說這樣等于是開啟 300000 個 goroutine 來各自判斷自己拿到 num 是不是質(zhì)數(shù)這樣。

用 time. Sleep 來休息五秒來讓 main 主程序不要被關(guān)閉,否則由于開啟 goroutine 之后代碼會繼續(xù)往下執(zhí)行,如果沒做 sleep 的話會導(dǎo)致主程序關(guān)閉,主程序一關(guān)閉 goroutine 就跟著關(guān)閉了,我們就看不出效果了。

這邊運(yùn)行之后會發(fā)現(xiàn)輸出的質(zhì)數(shù)出現(xiàn)并不是從小到大的,這是因為這些 goroutine 是一起做事情的,所以誰先做完誰就先輸出這樣。

運(yùn)行結(jié)果如下,最后花費(fèi)了大概 11 秒:

goroutine 的機(jī)制原理

理解 goroutine 機(jī)制的原理,關(guān)鍵是理解 Go 語言是如何實現(xiàn)調(diào)度器模型的。

計算機(jī)科學(xué)領(lǐng)域的任何問題都可以通過添加間接中間層來解決。GPM 模型就是這一理論的實踐者。

Go 語言中支撐整個調(diào)度器實現(xiàn)的主要有 4 個重要結(jié)構(gòu),分別是 machine(簡稱 M )、goroutine(簡稱 G )、processor(簡稱 P )、Scheduler(簡稱 Sched), 前三個定義在 runtime.h 中,Sched 定義在 proc.c 中。

  • Sched 結(jié)構(gòu)就是調(diào)度器,它維護(hù)有存儲 M 和 G 的隊列以及調(diào)度器的一些狀態(tài)信息等
  • M 結(jié)構(gòu)是 Machine,系統(tǒng)線程,它由操作系統(tǒng)管理和調(diào)度的,goroutine 就是跑在 M 之上的; M 是一個很大的結(jié)構(gòu),里面維護(hù)小對象內(nèi)存 cache(mcache)、當(dāng)前執(zhí)行的 goroutine、隨機(jī)數(shù)發(fā)生器等等非常多的信息。
  • P 結(jié)構(gòu)是 Processor,處理器,它的主要用途就是用來執(zhí)行 goroutine 的,它維護(hù)了一個 goroutine 隊列,即 runqueue。 Processor 是讓我們從 N:1 調(diào)度到 M:N 調(diào)度的重要部分。
  • G 是 goroutine 實現(xiàn)的核心結(jié)構(gòu),它包含了棧,指令指針,以及其他對調(diào)度 goroutine 很重要的信息,例如其阻塞的 channel。

我們分別用三角形,矩形和圓形表示 Machine Processor 和 Goroutine:

在單核處理器的場景下,所有 goroutine 運(yùn)行在同一個 M 系統(tǒng)線程中,每一個 M 系統(tǒng)線程維護(hù)一個 Processor,任何時刻,一個 Processor 中只有一個 goroutine,其他 goroutine 在 runqueue 中等待。

一個 goroutine 運(yùn)行完自己的時間片后,讓出上下文,回到 runqueue 中。 多核處理器的場景下,為了運(yùn)行 goroutines,每個 M 系統(tǒng)線程會持有一個 Processor 。

可以看到 Go 的并發(fā)用起來非常簡單,用了一個語法糖將內(nèi)部復(fù)雜的實現(xiàn)結(jié)結(jié)實實的包裝了起來。

其內(nèi)部可以用下面這張圖來概述:

在單核處理器的場景下,所有 goroutine 運(yùn)行在同一個 M 系統(tǒng)線程中,每一個 M 系統(tǒng)線程維護(hù)一個 Processor,任何時刻,一個 Processor 中只有一個 goroutine,其他 goroutine 在 runqueue 中等待。一個 goroutine 運(yùn)行完自己的時間片后,讓出上下文,回到 runqueue 中。 多核處理器的場景下,為了運(yùn)行 goroutines,每個 M 系統(tǒng)線程會持有一個 Processor 。

在正常情況下,scheduler 會按照上面的流程進(jìn)行調(diào)度,但是線程會發(fā)生阻塞等情況,看一下goroutine對線程阻塞等的處理。

到此這篇關(guān)于Go 并發(fā)編程協(xié)程及調(diào)度機(jī)制詳情的文章就介紹到這了,更多相關(guān)Go 調(diào)度機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言使用singleflight解決緩存擊穿

    Go語言使用singleflight解決緩存擊穿

    在構(gòu)建高性能的服務(wù)時,緩存是優(yōu)化數(shù)據(jù)庫壓力和提高響應(yīng)速度的關(guān)鍵技術(shù),但使用緩存也會帶來一些問題,其中就包括緩存擊穿,下面我們就來看看Go語言中如何使用singleflight解決緩存擊穿問題吧
    2024-03-03
  • golang1.23版本之前 Timer Reset方法無法正確使用

    golang1.23版本之前 Timer Reset方法無法正確使用

    在Go 1.23之前,使用`time.Reset`函數(shù)時需要先調(diào)用`Stop`并明確從timer的channel中抽取出東西,以避免潛在的問題,然而,這在實際代碼中難以實現(xiàn),因為設(shè)置定時器狀態(tài)和發(fā)送channel的操作并不是原子的,在某些情況下,這會導(dǎo)致timer在不應(yīng)該觸發(fā)時提前觸發(fā)
    2025-01-01
  • 在golang xorm中使用postgresql的json,array類型的操作

    在golang xorm中使用postgresql的json,array類型的操作

    這篇文章主要介紹了在golang xorm中使用postgresql的json,array類型的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 使用gin框架搭建簡易服務(wù)的實現(xiàn)方法

    使用gin框架搭建簡易服務(wù)的實現(xiàn)方法

    go語言web框架挺多的,本文就介紹了一下如何使用gin框架搭建簡易服務(wù)的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Go中使用操作符進(jìn)行數(shù)學(xué)運(yùn)算的示例代碼

    Go中使用操作符進(jìn)行數(shù)學(xué)運(yùn)算的示例代碼

    在編程中有效地執(zhí)行數(shù)學(xué)運(yùn)算是一項需要開發(fā)的重要技能,本文主要介紹了Go中使用操作符進(jìn)行數(shù)學(xué)運(yùn)算的示例代碼,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • 深入了解Golang中Slice切片的使用

    深入了解Golang中Slice切片的使用

    本文主要為大家詳細(xì)介紹了Golang中Slice切片的使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2023-02-02
  • Go語言使用Gob傳輸數(shù)據(jù)

    Go語言使用Gob傳輸數(shù)據(jù)

    本文主要介紹了Go語言使用Gob傳輸數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Golang迭代如何在Go中循環(huán)數(shù)據(jù)結(jié)構(gòu)使用詳解

    Golang迭代如何在Go中循環(huán)數(shù)據(jù)結(jié)構(gòu)使用詳解

    這篇文章主要為大家介紹了Golang迭代之如何在Go中循環(huán)數(shù)據(jù)結(jié)構(gòu)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 詳解Go中如何進(jìn)行進(jìn)行內(nèi)存優(yōu)化和垃圾收集器管理

    詳解Go中如何進(jìn)行進(jìn)行內(nèi)存優(yōu)化和垃圾收集器管理

    這篇文章主要為大家詳細(xì)介紹了Go中如何進(jìn)行進(jìn)行內(nèi)存優(yōu)化和垃圾收集器管理,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以了解下
    2023-11-11
  • Go語言字典(map)用法實例分析【創(chuàng)建,填充,遍歷,查找,修改,刪除】

    Go語言字典(map)用法實例分析【創(chuàng)建,填充,遍歷,查找,修改,刪除】

    這篇文章主要介紹了Go語言字典(map)用法,結(jié)合實例形式較為詳細(xì)的分析了Go語言字典的創(chuàng)建、填充、遍歷、查找、修改、刪除等操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2017-02-02

最新評論