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())
}

猜你喜欢

转载自www.cnblogs.com/wuyongqiang/p/12126431.html
今日推荐