Go控制併發

2022-03-19 14:07:21 字數 3887 閱讀 1275

目錄非同步返回結果

多路復用和超時控制

channel的關閉和廣播

任務的取消

關聯任務的取消

在 go 中可以使用 sync.mutex 或者 sync.rwmutex 來實現

sync.mutex: 互斥鎖

sync.rwmutex:一種特殊型別的鎖,其允許多個唯讀操作並行執行,但寫操作會完全互斥。

sync.waitgroup:一種特殊的計數器,這個計數器需要在多個goroutine操作時做到安全並且提供提供在其減為零之前一直等待的一種方法。

package share_mem

import (

"sync"

"testing"

"time"

)// 非執行緒安全

func testcounter(t *testing.t) ()

} time.sleep(1 * time.second)

t.logf("counter = %d", counter)

}// 執行緒安全

func testcounterthreadsafe(t *testing.t) ()

// 加鎖

mut.lock()

counter++

}()} time.sleep(1 * time.second) // 防止主協程執行過快,子協程還沒有執行完就結束了

t.logf("counter = %d", counter)

}// 執行緒安全及等待子 goroutine 執行結束

func testcounterwaitgroup(t *testing.t) ()

mut.lock()

counter++

wg.done() // -1

}()} wg.wait()

t.logf("counter=%d", counter)

}

csp(communicating sequential processes 通訊資料程序)是指依賴於通道(channel)完成通訊實體(process)之間的協調

csp中channel是第一類物件,它不關注傳送訊息的實體,而關注與傳送訊息時使用的channel。

go 語言抽象出了 csp 中的 channel 和 process(go 中對應 goroutine),底層實現並沒有關係。

所以,凡是用到 goroutine 和 channel 實現的併發都可以歸類到 csp 併發

非同步返回在 go 中可以用 goroutine + channel 實現,我們將原函式返回的結果放入 channel, 從 channel 中獲取返回結果之前,我們可以再做一些其他事。

由下面的測試**可以得出,buffer channel 更適合服務端開發。

package async_test

import (

"fmt"

"testing"

"time"

)func service() string

func othertask()

// 序列

func testservice(t *testing.t)

// 非同步執行

// 將 service 的結果放入 channel, 並將 channel 返回

func asyncservice() chan string ()

return retch

}func testasyncservice(t *testing.t)

當我們需要從多個 channel 中接受訊息時,就要用到 select 多路復用。

注意:如果多個 case 同時就緒時,select 會隨機地選擇乙個執行,這樣來保證每乙個 channel 都有平等的被 select 的機會。

package async_test

import (

"fmt"

"testing"

"time"

)func service() string

func othertask()

// 非同步執行

// 將 service 的結果放入 channel, 並將 channel 返回

func asyncservice() chan string ()

return retch

}func testselect(t *testing.t)

}

當我們使用乙個生產者與多個消費者進行互動時,我們可以通過close(channel)來廣播式的告訴所有的消費者去停止消費。

package channel_close

import (

"fmt"

"sync"

"testing"

)func dataproducer(ch chan int, wg *sync.waitgroup)

close(ch)

wg.done()

}()}func datareceiver(ch chan int, wg *sync.waitgroup) else

} wg.done()

}()}func testchannel(t *testing.t)

如果我們開啟很多 goroutine, 需要全部取消的時候可以有兩種方式:通過共享變數取消、通過 select + channel 廣播取消

package cancel_by_close

import (

"fmt"

"testing"

"time"

)var cancelflag bool

// 通過共享變數取消

func testcancel1(t *testing.t)

}fmt.println(i, "cancelled")

}(i)

} cancelflag = true

time.sleep(time.millisecond * 10)

}func iscancelled(cancelchan chan struct{}) bool

}func cancel1(cancelchan chan struct{}) {}

}func cancel2(cancelchan chan struct{})

// 通過 select + channel 廣播取消

func testcancel(t *testing.t) , 0)

for i := 0; i < 5; i++ )

}fmt.println(i, "cancelled")

}(i, cancelchan)

} //cancel1(cancelchan) // 只會取消其中乙個任務

cancel2(cancelchan) // 所有任務全部取消

time.sleep(time.millisecond * 10)

}

當我們啟動的子任務又啟動了孫子任務又啟動了曾孫子任務這種關聯任務的取消我們要用到context

package ctx_test

import (

"context"

"fmt"

"testing"

"time"

)func iscancelled(ctx context.context) bool

}func testcancel(t *testing.t)

time.sleep(time.millisecond * 5)

}fmt.println(i, "cancelled")

}(i, ctx)

} cancel()

time.sleep(time.second * 1)

}

Go併發控制 channel

雖然上次提過的sync控制併發很簡單,但是他有一定的侷限性,他也只能控制能過讓所有的goroutine在程式結束時完成,並不能干涉各個goroutine,下面我們介紹一種更好的方式,就是利用通道 首先先說用channel控制併發在程式結束之前完成 func main ch sum fmt.print...

go 增加併發控制的併發ping

參照anyevent coro版的ping功能實現.golang沒有方便的pop shift語法,只能自己按陣列進行計數 gorouting版本的並行ping package main import ping fmt time strconv var fin chan string 用於實現join...

mysql 併發控制 mysql併發控制

mysql併發控制 當有多個查詢需要同時修改同乙個資料,就會產生併發控制的問題。mysql可以在兩個層面進行併發控制 伺服器層和儲存引擎層。mysql通過加鎖實現併發控制 鎖有兩類 讀鎖 共享鎖,即乙個讀鎖不會阻塞其它讀鎖,多個使用者可同時讀取同乙個資源,而不互相干擾。寫鎖 排他鎖,即乙個寫鎖會阻塞...