算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
go-concurrency-review【设计与创意】Review and implement safe concurrency patterns in Go: goroutines, channels, sync primitives, context propagation, and goroutine lifecycle management. Use when writing concurrent code, reviewing async patterns, checking thread safety, debugging race conditions, or designing producer/consumer pipelines. Trigger examples: "check thread safety", "review …
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Concurrency in Go is powerful and deceptively easy to get wrong. These patterns prevent goroutine leaks, data races, and deadlocks.
Detailed reference material, loaded on demand:
references/channels.md — sizing, signalling, producer shutdown.references/mutex-and-atomics.md — mutex placement, lock scope, atomics,
sync.Once.Read a reference file only when the section below is not enough.
Pick the mode that matches the request before starting:
go statements and shared state.-race report, deadlock). Start from "Auditing Large Codebases"
and the Race Detection section to localize it.For a full concurrency audit, run these independent passes rather than one linear read:
go statement
(grep -rn "go func\|go [a-zA-Z]" --include="*.go") and verify each
has a termination path (context, closed channel, WaitGroup).context.Context.If your environment supports delegating work to parallel sub-agents or
tasks, assign each pass to one; otherwise run them in order. Findings
must cite file.go:line. Always finish with go test -race ./....
EVERY goroutine MUST have a clear termination path. No fire-and-forget.
errgroup for coordinated goroutines:g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
return fetchUsers(ctx)
})
g.Go(func() error {
return fetchOrders(ctx)
})
if err := g.Wait(); err != nil {
return fmt.Errorf("fetch data: %w", err)
}
func (w *Worker) Run(ctx context.Context) error {
for {
select {
case <-ctx.Done():
return ctx.Err()
case job := <-w.jobs:
if err := w.process(job); err != nil {
w.logger.Error("process job", slog.Any("error", err))
}
}
}
}
// ✅ Good — caller controls lifecycle
go worker.Run(ctx)
// ❌ Bad — function secretly starts goroutine
func NewWorker() *Worker {
w := &Worker{}
go w.run() // hidden goroutine — caller has no control
return w
}
100 is a bug waiting for the day production is slower than
staging.struct{}, and close(done) broadcasts to every
receiver at once.defer close(ch) in the producing goroutine. Every send sits in a select
against ctx.Done(), or a consumer that walks away leaks the producer.Examples in references/channels.md.
sync.Mutex and sync.RWMutex are ready to use. A
*sync.Mutex field is always wrong.c2 := *c1): the copy carries the
original's lock state. go vet catches most of these; trust it.sync/atomic types for counters and flags rather than a mutex around
an int64.sync.Once for lazy initialization that must happen exactly once.Examples in references/mutex-and-atomics.md.
Context is always the first parameter, never a struct field, and every
blocking operation selects on ctx.Done():
// ✅ Good
select {
case result := <-ch:
return result, nil
case <-ctx.Done():
return nil, ctx.Err()
}
// ❌ Bad — blocks forever if the context is cancelled
result := <-ch
Derive a child context with its own timeout for each external call and
defer cancel() immediately. Full rules in the go-context skill.
// ❌ Bad — mutable global, not safe for concurrent access
var db *sql.DB
// ✅ Good — pass as dependency
type Server struct {
db *sql.DB
}
ALWAYS run tests with race detector during CI:
go test -race ./...
This is non-negotiable. A test suite that passes without -race proves nothing
about concurrent correctness.
context.Background() used where parent context was availableselect without ctx.Done() case in blocking operationtime.Sleep used for synchronization instead of proper signalinginit() or constructor without lifecycle control