国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

go協(xié)程、線程的本質(zhì),如何協(xié)調(diào)運作

這篇具有很好參考價值的文章主要介紹了go協(xié)程、線程的本質(zhì),如何協(xié)調(diào)運作。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

協(xié)程與線程

線程在創(chuàng)建、切換、銷毀時候,需要消耗CPU的資源。

協(xié)程就是將一段程序的運行狀態(tài)打包, 可以在線程之間調(diào)度。減少CPU在操作線程的消耗

協(xié)程、線程、進程 這塊網(wǎng)上非常多文章講了,就不多敘述了。

歸納下:

進程用分配內(nèi)存空間
線程用來分配CPU時間
協(xié)程用來精細利用線程
協(xié)程的本質(zhì)是一段包含了運行狀態(tài)的程序  后面介紹后,會對這個概念更好理解

協(xié)程的本質(zhì)

上面講了 ,協(xié)程的本質(zhì)就是 一段程序的運行狀態(tài)的打包:

  func Do() {
  	for i := 1; i <= 1000; i++ {
  		fmt.Println(i)
  		time.Sleep(time.Second)
  	}
  }

  func main() {
  	go Do()
  	select {}
  }

例如上面這段代碼,開了一個協(xié)程,然后一直循環(huán)打印。

假設程序都還有很多其他的協(xié)程也在工作,發(fā)現(xiàn)這個協(xié)程工作太久了,系統(tǒng)會進行切換別的協(xié)程,現(xiàn)在這個協(xié)程會放入?yún)f(xié)程隊列中。

問題:要做到這點,協(xié)程需要怎么保存這個執(zhí)行狀態(tài)?

  1. 需要一個函數(shù)的調(diào)用棧,記錄執(zhí)行了那些函數(shù),(例子中只有一個,正常情況下會是很多函數(shù)相互調(diào)用) 函數(shù)執(zhí)行完后,還需要回到上層函數(shù),所以要保存函數(shù)棧信息。
  1. 需要記錄當前執(zhí)行到了 那行代碼,不能把多執(zhí)行,也不能少執(zhí)行那句代碼,不然程序會不可控。
  1. 需要一個空間,存儲整個協(xié)程的數(shù)據(jù),例如變量的值等。

協(xié)程的底層定義

在runtime的runtim2.go中

  type g struct {
  // 只留了少量幾個,里面有非常多的字段。
  	stack       stack  // 調(diào)用棧
  	m         *m        // 協(xié)程關聯(lián)了一個m (GMP)
        sched     gobuf  // 協(xié)程的現(xiàn)場
  	goid         uint64   // 協(xié)程的編號
      atomicstatus atomic.Uint32 // 協(xié)程的狀態(tài)

  }

type gobuf struct {
       sp   uintptr  // 當前調(diào)用的函數(shù)
	pc   uintptr  // 執(zhí)行語句的指針
	g    guintptr
	ctxt unsafe.Pointer
	ret  uintptr
	lr   uintptr
	bp   uintptr // for framepointer-enabled architectures
}

// 棧的定義
  type stack struct {
  	lo uintptr  // 低地址
  	hi uintptr  // 高地址
  }

整體下:

假如有這么一段代碼:

  func do3() {
  	fmt.Println("dododo")
  }

  func do2() {
  	do3()
  }

  func do1() {
  	do2()
  }

  func main() {
  	go do1()
  	time.Sleep(time.Hour)
  }

在do2斷點:

go協(xié)程、線程的本質(zhì),如何協(xié)調(diào)運作

能看到下方的調(diào)用棧中,會自動插入一個 goexit 在棧頭。

小結(jié)下,整體的結(jié)構(gòu)如下:

go協(xié)程、線程的本質(zhì),如何協(xié)調(diào)運作

總結(jié):

runtime 中,協(xié)程的本質(zhì)是一個g 結(jié)構(gòu)體
stack:堆棧地址
gobuf:目前程序運行現(xiàn)場
atomicstatus: 協(xié)程狀態(tài)

線程的底層 m

操作系統(tǒng)的線程是由操作系統(tǒng)管理,這里的m只是記錄線程的信息。

截取部分代碼:
type m struct {
	g0      *g     // goroutine with scheduling stack
	id            int64 // id號
	morebuf gobuf  // gobuf arg to morestack	
	curg          *g       // 當前運行的g
	p             puintptr // attached p for executing go code (nil if not executing go code)
	mOS // 系統(tǒng)線程信息
}

go 是go程序啟動創(chuàng)建的第一個協(xié)程,用來操控調(diào)度器的,第二個是主協(xié)程,可以看下 go啟動那篇

小結(jié):

runtime 中將操作系統(tǒng)線程抽象為 m結(jié)構(gòu)體
g0:g0協(xié)程,操作調(diào)度器
curg:current g,目前線程運行的g
mOs:操作系統(tǒng)線程信息

如何工作

協(xié)程究竟是如何在 線程中工作的 ?

先講總結(jié),然后跟著總結(jié)往下看:

go協(xié)程、線程的本質(zhì),如何協(xié)調(diào)運作

這是單個線程的循環(huán),沒有P的存在。

1. schedule() 是線程獲取 協(xié)程的入口方法

線程通過執(zhí)行 g0協(xié)程棧,獲取 待執(zhí)行的 協(xié)程

也就是意味著,每次線程執(zhí)行 這個schedule方法,就意味著會切換一個 協(xié)程。
這個結(jié)論很重要,后面 協(xié)程調(diào)度時候,會大量看到調(diào)用這個方法。

在runtime的 proc.go下面能看到這個方法,這里只留了兩行代碼,
只和目前邏輯相關的,這個方法后面還要多次讀
   func schedule() {
  	gp, inheritTime, tryWakeP := findRunnable() // blocks until work is available
  	execute(gp, inheritTime)
  }
這里的gp就是 待執(zhí)行的g

 可以和上面的圖對上,這里去  `Runnable` 找一個協(xié)程。然后,調(diào)用 `execute` 方法。
 至于怎么去找的,知道GMP的肯定都知道,這個后面聊。

也只有部分代碼,和這里業(yè)務相關的
 func execute(gp *g, inheritTime bool) {
  	mp := getg().m  //獲取m,線程的抽象
  	mp.curg = gp   // 還記得 m的定義 里面有個 當前的 g 在這里賦值了
  	gp.m = mp      // g的定義也有個 m,這里也賦值了
  	gogo(&gp.sched)
  }

到gogo
func gogo(buf *gobuf) // 只有定義,說明是匯編實現(xiàn)的,而且是平臺相關的
     
// func gogo(buf *gobuf)  
// 這里把 g的gobuf傳過去了,gobuf 存著 sp 和 pc ,當前的執(zhí)行函數(shù),和執(zhí)行語句
//  到這里就基本對應上了
// restore state from Gobuf; longjmp
TEXT runtime·gogo(SB), NOSPLIT, $0-8
	MOVQ	buf+0(FP), BX		// gobuf
	MOVQ	gobuf_g(BX), DX
	MOVQ	0(DX), CX		// make sure g != nil
	JMP	gogo<>(SB)

//  插入了 goexit的棧針 然后開始運行業(yè)務 
TEXT gogo<>(SB), NOSPLIT, $0
	get_tls(CX)
	MOVQ	DX, g(CX)
	MOVQ	DX, R14		// set the g register
	MOVQ	gobuf_sp(BX), SP	// restore SP 插入了 goexit的棧針
	MOVQ	gobuf_ret(BX), AX
	MOVQ	gobuf_ctxt(BX), DX
	MOVQ	gobuf_bp(BX), BP
	MOVQ	$0, gobuf_sp(BX)	// clear to help garbage collector
	MOVQ	$0, gobuf_ret(BX)
	MOVQ	$0, gobuf_ctxt(BX)
	MOVQ	$0, gobuf_bp(BX)
	MOVQ	gobuf_pc(BX), BX
	JMP	BX

在運行業(yè)務之前 jmp bx,都還在 g0的協(xié)程棧上。

目前,已經(jīng)把開始執(zhí)行,到執(zhí)行都整理了一遍,但是,沒有講 goexit 插入 到底有什么作用?

經(jīng)驗豐富的伙伴大致能猜到, 當執(zhí)行完了協(xié)程的任務后,需要回到 schedule方法中, 線程重新去執(zhí)行別的協(xié)程,這就是 goexit的作用

goexit

匯編實現(xiàn)
TEXT runtime·goexit(SB),NOSPLIT|TOPFRAME,$0-0
BYTE	$0x90	// NOP
CALL	runtime·goexit1(SB)	//  去調(diào)用 goexit1 這個方法

// Finishes execution of the current goroutine.
func goexit1() {
	mcall(goexit0) // 通過mcall 調(diào)用goexit0  
}

 // mcall switches from the g to the g0 stack and invokes fn(g),
 // 切換到 g0 棧
 func mcall(fn func(*g))
 就是只,上面的都是在 業(yè)務協(xié)程中,運行的,到這里,開始使用 g0棧去運行,goexit0

// goexit continuation on g0. 
func goexit0(gp *g) {
	mp := getg().m
	pp := mp.p.ptr()

	casgstatus(gp, _Grunning, _Gdead)
	gcController.addScannableStack(pp, -int64(gp.stack.hi-gp.stack.lo))
	if isSystemGoroutine(gp, false) {
		sched.ngsys.Add(-1)
	}
	gp.m = nil
	locked := gp.lockedm != 0
	gp.lockedm = 0
	mp.lockedg = 0
	gp.preemptStop = false
	gp.paniconfault = false
	gp._defer = nil // should be true already but just in case.
	gp._panic = nil // non-nil for Goexit during panic. points at stack-allocated data.
	gp.writebuf = nil
	gp.waitreason = waitReasonZero
	gp.param = nil
	gp.labels = nil
	gp.timer = nil
	schedule()
}
// 對結(jié)束的g進行了一些置0的工作,然后調(diào)用了 schedule()

schedule() 意味著 為現(xiàn)在的線程,切換協(xié)程。

到此,和上面的圖都對應上了。但是目前還是單線程,多線程時候,是如何工作了,下篇再聊。文章來源地址http://www.zghlxwxcb.cn/news/detail-747829.html

到了這里,關于go協(xié)程、線程的本質(zhì),如何協(xié)調(diào)運作的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 港大&谷歌提出GO-NeRF:在NeRF中生成協(xié)調(diào)且高質(zhì)量的3D對象

    港大&谷歌提出GO-NeRF:在NeRF中生成協(xié)調(diào)且高質(zhì)量的3D對象

    盡管在3D生成方面取得了進展,但在作為NeRF表示的現(xiàn)有3D場景中直接創(chuàng)建3D對象仍然是未經(jīng)探索的。這個過程不僅需要高質(zhì)量的3D對象生成,還需要將生成的3D內(nèi)容無縫地合成到現(xiàn)有的NeRF中。為此,作者提出了一種新方法,GO-NeRF,能夠利用場景上下文進行高質(zhì)量和諧調(diào)的3D對象

    2024年01月18日
    瀏覽(32)
  • 詳解區(qū)塊鏈技術,如何運作

    詳解區(qū)塊鏈技術,如何運作

    區(qū)塊鏈是數(shù)字加密貨幣比特幣的核心技術。區(qū)塊鏈是一個分布式數(shù)據(jù)庫,包含參與方之間已執(zhí)行和共享的所有交易或數(shù)字事件的記錄。每一筆交易都經(jīng)過系統(tǒng)大多數(shù)參與者的驗證。它包含每筆交易的每一條記錄。比特幣是最流行的加密貨幣,也是區(qū)塊鏈的一個例子。區(qū)塊鏈技

    2023年04月15日
    瀏覽(15)
  • python正則+多線程(代理)+線程池+協(xié)程

    常用元字符 . 匹配除換行符以外的任意字符 w 匹配字幕或數(shù)字或下劃線 s 匹配任意空白字符 d 匹配數(shù)字 n 匹配一個換行符 t 匹配一個制表符 W 匹配非字母或數(shù)字或下劃線 D 匹配非數(shù)字 S 匹配非空白符 a|b 匹配字符a或b () 匹配括號內(nèi)的表達式,也表示一個組 […] 匹配字符

    2024年02月16日
    瀏覽(17)
  • Go 方法介紹,理解“方法”的本質(zhì)

    目錄 Go 方法介紹,理解“方法”的本質(zhì) 一、認識 Go 方法 1.1 基本介紹 1.2 聲明 1.2.1 引入 1.2.2 一般聲明形式 1.2.3 receiver 參數(shù)作用域 1.2.4 receiver 參數(shù)的基類型約束 1.2.5 方法聲明的位置約束 1.2.6 如何使用方法 二、方法的本質(zhì) 三、巧解難題 我們知道,Go 語言從設計伊始,就不支

    2024年02月06日
    瀏覽(25)
  • go-GMP 協(xié)程切換時機 和 協(xié)程實戰(zhàn)

    go-GMP 協(xié)程切換時機 和 協(xié)程實戰(zhàn)

    當m在執(zhí)行某個g的時候,g非常耗時,例如一個for循環(huán),每次循環(huán)sleep1分鐘,循環(huán)1000次。 這個例子看似無聊,卻是很難解決的,成功的避開了2個系統(tǒng)切換時機。 如果這個時候,一直執(zhí)行這個g,別的g就會得不到執(zhí)行,例如有g是處理用戶支付的,這樣就會造成收錢不積極。 本

    2024年02月05日
    瀏覽(23)
  • 【Go 基礎篇】Go語言字符類型:解析字符的本質(zhì)與應用

    字符類型是計算機編程中用于表示文本和字符的數(shù)據(jù)類型,是構(gòu)建字符串的基本單位。在Go語言(Golang)中,字符類型具有獨特的特點和表示方式,包括Unicode編碼、字符字面值以及字符操作。本篇博客將深入探討Go語言中的字符類型,介紹字符的編碼方式、字符字面值的表示

    2024年02月13日
    瀏覽(22)
  • Go簡單實現(xiàn)協(xié)程池

    Go簡單實現(xiàn)協(xié)程池

    首先就是進程、線程、協(xié)程講解老三樣。 進程:? 本質(zhì)上是一個獨立執(zhí)行的程序,進程是操作系統(tǒng)進行資源分配和調(diào)度的基本概念,操作系統(tǒng)進行資源分配和調(diào)度的一個獨立單位。 線程:? 是操作系統(tǒng)能夠進行運算調(diào)度的最小單位。它被包含在進程之中,是進程中的實際運作單

    2024年02月08日
    瀏覽(18)
  • go 協(xié)程并發(fā)數(shù)控制

    go 協(xié)程并發(fā)數(shù)控制

    錯誤的寫法: 這里的-ch 是為了從channel 中讀取 數(shù)據(jù),為了不使channel通道被寫滿,阻塞 go 協(xié)程數(shù)的創(chuàng)建。但是請注意,go workForDraw(v, wg) 是不阻塞后續(xù)的-ch 執(zhí)行的,所以就一直go workForDraw(v, wg) 拉起新的協(xié)程。這么是達不到控制協(xié)程并發(fā)數(shù)10 的目的 正確的寫法: 直接將-ch 寫入

    2024年02月12日
    瀏覽(18)
  • 比特幣如何運作?區(qū)塊鏈、網(wǎng)絡、交易

    免責聲明:觀點來自原文作者,與本人無關,文章僅供參考學習,請自行辨別真?zhèn)?,切勿跟風,風險自擔。 翻譯原文:https://www.blockpit.io/blog/how-does-bitcoin-work 比特幣是一種革命性的數(shù)字貨幣,由化名中本聰?shù)哪涿耸炕驁F體于 2008 年發(fā)明。它是世界上第一個加密貨幣,負責將

    2024年03月24日
    瀏覽(24)
  • 為什么需要協(xié)調(diào)能力?如何提高協(xié)調(diào)能力?

    協(xié)調(diào)能力指的是協(xié)作與調(diào)和,屬于綜合性能力的體現(xiàn),涉及到表達,溝通,邏輯等方面,在日常生活中缺乏協(xié)調(diào)能力,也許影響并不太大,但是如果在職業(yè)發(fā)展中,協(xié)調(diào)能力就尤為重要,尤其是某些職業(yè)崗位,對協(xié)調(diào)能力有更高的要求。 在我們的職業(yè)生涯中,團隊協(xié)作是永恒

    2024年02月07日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包