Go編程技巧--Goroutine的優雅控制

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

原文:Go編程技巧--Goroutine的優雅控制

Goroutine是Go語言最重要的機制,Goroutine將複雜的需要非同步IO調用抽象成同步調用,符合人類正常的順序思維,極大的簡化了IO編程的難度。如同線程一樣,對Goroutine既要掌握基本的用法,更要很好的控制Goroutine的退出機制。本文介紹一種Goroutine的退出思路。

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

  1. IO操作,比如對SocketRead

  2. 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 {    done <-chan struct{}}

routineSignal的執行個體,應當通過外部產生並傳遞給reader,例如:

func (r *reader)init(s *routineSignal) {    r.signal = s}

在reader的迴圈中,就可以這麼寫:

func (r *reader)loop() {    for {        select {        case <-r.signal.done:            return        case <-r.queue:            ....        }    }}

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

close(signal.done)

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

type routineSignal struct {    done chan struct{}    wg   sync.WaitGroup}

增加一個sync.WaitGroup的執行個體,在Goroutine開始工作時,對wg加1,在Goroutine退出前,對wg減1:

func (r *reader)loop() {    r.signal.wg.Add(1)    defer r.signal.wg.Done()    for {        select {        case <-r.signal.done:            return        case <-r.queue:            ....        }    }}

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

close(signal.done)signal.wg.Wait()

只要Wait()返回就能斷定Goroutine結束了。

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.