Go程式設計技巧 Goroutine的優雅控制

2021-09-17 02:38:18 字數 2373 閱讀 9836

原文:go程式設計技巧--goroutine的優雅控制

goroutine是go語言最重要的機制,goroutine將複雜的需要非同步的io呼叫抽象成同步呼叫,符合人類正常的順序思維,極大的簡化了io程式設計的難度。如同執行緒一樣,對goroutine既要掌握基本的用法,更要很好的控制goroutine的退出機制。本文介紹一種goroutine的退出思路。

通常goroutine會因為兩種情況阻塞:

io操作,比如對socketread

channel操作。對乙個chan的讀寫都有可能阻塞goroutine

對於情況1,只需要關閉對應的描述符,阻塞的goroutine自然會被喚醒。

重點討論情況2。併發程式設計,goroutine提供一種channel機制,channel類似管道,寫入者向裡面寫入資料,讀取者從中讀取資料。如果channel裡面沒有資料,讀取者將阻塞,直到有資料;如果channel裡面資料滿了,寫入者將因為無法繼續寫入資料而阻塞。

如果在整個應用程式的生命週期裡,writer和reader都表現為乙個goroutine,始終都在工作,那麼如何在應用程式結束前,通知它們終止呢?在go中,並不推薦像abort執行緒那樣,強行的終止goroutine。因此,抽象的說,必然需要保留乙個入口,能夠跟writer或reader通訊,以告知它們終止。

我們先看reader。我們首先可以想到,利用close函式關閉正在讀取的channel,從而可以喚醒reader,並退出。但是考慮到close並不能很好的處理writer(因為writer試圖寫入乙個已經close的channel,將引發異常)。因此,我們需要設計乙個額外的唯讀channel用於通知:

type routinesignal struct 

}

routinesignal的例項,應當通過外部生成並傳遞給reader,例如:

func (r *reader)init(s *routinesignal)
在reader的迴圈中,就可以這麼寫:

func (r *reader)loop() 

}}

當需要終止goroutine的時候只需要關閉這個額外的channel

close(signal.done)
看起來很完備了,這可以處理大部分的情況了。這樣做有個弊端,儘管,我們可以期望close喚醒goroutine進而退出,但是並不能知道goroutine什麼時候完成退出,因為goroutine可能在退出前還有一些善後工作,這個時候我們需要sync.waitgroup。改造一下routinesignal

type routinesignal struct 

wg sync.waitgroup

}

增加乙個sync.waitgroup的例項,在goroutine開始工作時,對wg加1,在goroutine退出前,對wg減1:

func (r *reader)loop() 

}}

外部,只需要等待waitgroup返回即可:

close(signal.done)

signal.wg.wait()

只要wait()返回就能斷定goroutine結束了。

推導一下,不難發現,對於writer也可以採用這種方法。於是,總結一下,我們建立了乙個叫routinesignal的結構,結構裡面包含乙個chan用來通知goroutine結束,包含乙個waitgroup用於goroutine通知外部完成善後。這樣,通過這個結構的例項優雅的終止goroutine,而且還可以確保goroutine終止成功。

Go語言 併發程式設計goroutine

在go語言中併發是通過goroutine實現。goroutine類似於執行緒,屬於使用者態執行緒。go語言也可以通過channel 管道 與多個goroutine進行通訊。goroutine類似於執行緒,在go語言中底層分配了乙個執行緒池,因此不需要我們對其進行管理,由go執行時的routine進行...

Go語言學習 goroutine

簡介 goroutine是go語言中最為nb的設計,也是其魅力所在,goroutine的本質是協程,是實現平行計算的核心。goroutine使用方式非常的簡單,只需使用go關鍵字即可啟動乙個協程,並且它是處於非同步方式執行,你不需要等它執行完成以後在執行以後的 go func 通過go關鍵字啟動乙個...

Go語言中Goroutine的設定

一 通過runtime包進行多核設定 1.numcpu 獲取當前系統的cpu核數 2.gomaxprocs設定當前程式執行時占用的cpu核數 版本1.6之前預設是使用1個核,而之後是全部使用。好玩的程式 func dosomething func main err return 設定核數 runti...