主要优化
- err_group:去掉多余 goroutine,避免潜在泄漏;并把并发 append 改为按下标写
入,消除数据竞争。
- err_group 测试稳定性增强:放宽超时并增加结果长度断言。
- semaphore:修复等待队列元素类型断言错误(*waiter);补充非法参数校验(负数
acquire/release)。
- SemaChan:修复 Lock/Unlock 逻辑(初始化令牌桶),避免永久阻塞。
- observer:修复“每次 Notify 都启动新 fanout 协程”的问题:改为 sync.Once 只启动一次
fanOut。
- observer:修复并发读写观察者列表问题:给 Attach/Detach/fanOut 增加读写锁保护。
- observer:去掉 fanout 内部额外再起 goroutine和自动关闭所有 observer 的行为,避
免重复关闭/竞态风险(仍保留 Detach 时关闭单个 observer)。
- lock_free:修复可取消延迟队列的计数错误与 timers map 并发访问问题。
- lock_free:checkAckStatus 改为非阻塞读取,避免入队路径被卡住。
- routine:提供默认空任务并忽略 nil taskFn,防止空指针调用。
- ticker:发送改为非阻塞,Stop 幂等化,降低阻塞和重复关闭风险。
- query_builder:WaitAndGo 增加 goroutine 内 panic 转 error;测试里
的 GORM filter 链式写法修正。
新增测试
- 新增 semaphore 测试,覆盖 Acquire/Release/TryAcquire 与 SemaChan 并发上限。
97 lines
2.2 KiB
Go
97 lines
2.2 KiB
Go
package cyclic_barrier
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/marusama/cyclicbarrier"
|
|
"golang.org/x/sync/semaphore"
|
|
"math/rand"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
H2OHydrogenNum = 2 // 氢原子数量
|
|
H2OOxygenNum = 1 // 氧原子数量
|
|
)
|
|
|
|
// H2O 水分子结构体
|
|
type H2O struct {
|
|
semaH *semaphore.Weighted
|
|
semaO *semaphore.Weighted
|
|
cb cyclicbarrier.CyclicBarrier
|
|
}
|
|
|
|
func NewH2O() *H2O {
|
|
return &H2O{
|
|
semaH: semaphore.NewWeighted(H2OHydrogenNum), // 氢原子的信号量
|
|
semaO: semaphore.NewWeighted(H2OOxygenNum), // 氧原子的信号量
|
|
cb: cyclicbarrier.New(H2OHydrogenNum + H2OOxygenNum), // 循环栅栏,用来控制合成
|
|
}
|
|
}
|
|
|
|
func (h *H2O) hydrogen(releaseHydrogen func()) {
|
|
if err := h.semaH.Acquire(context.Background(), 1); err != nil { // 占用氢原子空槽
|
|
fmt.Println("Hydrogen Acquire err:", err)
|
|
}
|
|
|
|
releaseHydrogen()
|
|
if err := h.cb.Await(context.Background()); err != nil { // 等待栅栏放行
|
|
fmt.Println("Hydrogen Await err:", err)
|
|
}
|
|
|
|
h.semaH.Release(1) // 释放氢原子空槽
|
|
}
|
|
|
|
func (h *H2O) oxygen(releaseOxygen func()) {
|
|
if err := h.semaO.Acquire(context.Background(), 1); err != nil { // 占用氧原子空槽
|
|
fmt.Println("Oxygen Acquire err:", err)
|
|
}
|
|
|
|
releaseOxygen()
|
|
if err := h.cb.Await(context.Background()); err != nil { // 等待栅栏放行
|
|
fmt.Println("Oxygen Await err:", err)
|
|
}
|
|
|
|
h.semaO.Release(1) // 释放氧原子空槽
|
|
}
|
|
|
|
func (h *H2O) Gen(num uint) <-chan string {
|
|
// 计算总共需要生成的原子数量
|
|
sum := H2OHydrogenNum + H2OOxygenNum
|
|
numInt := int(num)
|
|
// 用来存放生成的原子
|
|
ch := make(chan string, numInt*sum)
|
|
releaseHydrogen := func() {
|
|
ch <- "H"
|
|
}
|
|
releaseOxygen := func() {
|
|
ch <- "O"
|
|
}
|
|
var wg sync.WaitGroup
|
|
|
|
// 使用 WaitGroup 等待所有的 goroutine 完成
|
|
wg.Add(numInt * sum)
|
|
for i := 0; i < numInt*H2OHydrogenNum; i++ {
|
|
go func() {
|
|
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
|
h.hydrogen(releaseHydrogen)
|
|
wg.Done()
|
|
}()
|
|
}
|
|
for i := 0; i < numInt*H2OOxygenNum; i++ {
|
|
go func() {
|
|
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
|
h.oxygen(releaseOxygen)
|
|
wg.Done()
|
|
}()
|
|
}
|
|
|
|
go func() {
|
|
wg.Wait()
|
|
close(ch)
|
|
}()
|
|
|
|
return ch
|
|
}
|