annidy / notes

0 stars 0 forks source link

go semaphore #312

Open annidy opened 3 months ago

annidy commented 3 months ago

311 中使用chan来控制并发数,其它语言一般都是用信号量来实现,只是go语言标准库没有提供接口,所以大多数情况用chan来代替。

扩展包有提供semaphore,改造后如下

import (
    "context"
    "log"
    "sync"

    "golang.org/x/sync/semaphore"
)

func transform5[A, B any](p int, xs []A, f func(A) B) []B {
    ret := make([]B, len(xs))
    sem := semaphore.NewWeighted(int64(p))
    ctx := context.TODO()
    for i := 0; i < len(xs); i++ {
        if err := sem.Acquire(ctx, 1); err != nil {
            log.Printf("Failed to acquire semaphore: %v", err)
            break
        }
        go func(i int) {
            defer sem.Release(1)
            ret[i] = f(xs[i])
        }(i)
    }
    if err := sem.Acquire(ctx, int64(p)); err != nil {
        log.Printf("Failed to acquire semaphore: %v", err)
    }
    return ret
}

NewWeighted有以下优势

  1. 支持context,因此可以被cancel
  2. PV操作可以大于1
  3. 当资源很多时节约内存。资源可用是用一个整数,而不是像chan需要申请buffer。
  4. Acquire还有一个特性是FIFO,这点是chan不具备的

至于性能嘛,两者没差别。