Go常见并发任务
仅执行一次
比如实现线程安全的单利模式
除了用 sync.Once 实现,我们还可以利用 package 的 init() 函数去实现
package once_test
import (
"fmt"
"sync"
"testing"
"unsafe"
)
type Singleton struct {}
var singleInstance *Singleton
var once sync.Once
func GetSingletonObj() *Singleton {
once.Do(func() {
fmt.Println("Create Obj")
singleInstance = new(Singleton)
})
return singleInstance
}
func TestGetSingletonObj(t *testing.T) {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
obj := GetSingletonObj()
fmt.Printf("%x\n", unsafe.Pointer(obj)) // 将16进制转为
wg.Done()
}()
}
wg.Wait()
}
仅需任意任务完成
比如我们去同不同的服务器上取相同的数据,只要有一个返回就结束全部任务。
思路:我直接获取buffer channel的第一个值就可以了
package any_reply_test
import (
"fmt"
"runtime"
"testing"
"time"
)
func runTask(id int) string {
time.Sleep(10 * time.Millisecond)
return fmt.Sprintf("The result is from %d", id)
}
func FirstResponse() string {
numOfRunner := 10
ch := make(chan string, numOfRunner) // 必须为 buffer channel,不然会导致 goroutine 阻塞
for i := 0; i < numOfRunner; i++ {
go func(i int) {
ret := runTask(i)
ch <- ret
}(i)
}
return <-ch
}
func TestFirstResponse(t *testing.T) {
t.Log("Before:", runtime.NumGoroutine()) // 当前系统中的协程数,2
t.Log(FirstResponse())
time.Sleep(time.Second * 1)
t.Log("After:", runtime.NumGoroutine()) // 当前系统中的协程数,2
}
所有任务都完成
可以使用 sync.WaitGroup,还有利用 channel 的实现
package all_rep_test
import (
"fmt"
"runtime"
"testing"
"time"
)
func runTask(id int) string {
time.Sleep(10 * time.Millisecond)
return fmt.Sprintf("The result if from %d", id)
}
func AllResponse() string {
numOfRunner := 10
ch := make(chan string, numOfRunner)
for i := 0; i < numOfRunner; i++ {
go func(i int) {
ret := runTask(i)
ch <- ret
}(i)
}
finalRet := ""
for j := 0; j < numOfRunner; j++ {
finalRet += <-ch + "\n"
}
return finalRet
}
func TestAllResponse(t *testing.T) {
t.Log("Before:", runtime.NumGoroutine())
t.Log(AllResponse())
time.Sleep(time.Second * 1)
t.Log("After:", runtime.NumGoroutine())
}