Files
Geliebte 1ea8c9da9c feat: 初始化 Wails + React + Go 桌面应用模板
- Wails v2.16.0 + React 19 + TypeScript + Vite 7
- 插件系统(build tag 控制编译,plugin.json 运行时配置)
- 支付插件(授权、账号、订单、退款、账单)
- 高并发基础设施(任务池、批量处理器、限流器、环形缓冲、管道)
- Windows 系统托盘(Win32 API)
- CodeGraph 索引 + .memory 记忆包
- 默认图标 assets/icon.png
2026-09-17 19:31:17 +08:00

147 lines
2.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package worker
import (
"context"
"sync"
"sync/atomic"
)
// Job 任务接口,所有后台任务需实现此接口
type Job interface {
Execute(ctx context.Context) error
JobID() string
}
// TaskResult 任务执行结果
type TaskResult struct {
JobID string
Output any
Error error
}
// Pool 任务并发池,管理固定数量工作协程
type Pool struct {
jobs chan Job
results chan TaskResult
wg sync.WaitGroup
stopOnce sync.Once
ctx context.Context
cancel context.CancelFunc
running atomic.Int64
total atomic.Int64
failed atomic.Int64
}
// Options 池配置
type Options struct {
Workers int // 工作协程数,默认 4
BufSize int // 队列缓冲,默认 1000
}
// NewPool 创建任务池
func NewPool(opts ...Options) *Pool {
o := Options{Workers: 4, BufSize: 1000}
if len(opts) > 0 {
o = opts[0]
}
if o.Workers <= 0 {
o.Workers = 4
}
if o.BufSize <= 0 {
o.BufSize = 1000
}
ctx, cancel := context.WithCancel(context.Background())
p := &Pool{
jobs: make(chan Job, o.BufSize),
results: make(chan TaskResult, o.BufSize),
ctx: ctx,
cancel: cancel,
}
p.startWorkers()
return p
}
func (p *Pool) startWorkers() {
for i := 0; i < 4; i++ {
p.wg.Add(1)
go p.worker()
}
}
func (p *Pool) worker() {
defer p.wg.Done()
for {
select {
case <-p.ctx.Done():
return
case job, ok := <-p.jobs:
if !ok {
return
}
p.running.Add(1)
p.total.Add(1)
err := job.Execute(p.ctx)
result := TaskResult{JobID: job.JobID(), Error: err}
if err != nil {
p.failed.Add(1)
}
p.running.Add(-1)
select {
case p.results <- result:
case <-p.ctx.Done():
return
}
}
}
}
// Submit 提交任务到队列(非阻塞,队列满时返回 false)
func (p *Pool) Submit(job Job) bool {
select {
case p.jobs <- job:
return true
default:
return false
}
}
// SubmitAndWait 提交任务并等待结果
func (p *Pool) SubmitAndWait(ctx context.Context, job Job) (*TaskResult, error) {
if !p.Submit(job) {
return nil, ErrQueueFull
}
select {
case r := <-p.results:
return &r, r.Error
case <-ctx.Done():
return nil, ctx.Err()
}
}
// Results 返回结果通道,供外部 range 消费
func (p *Pool) Results() <-chan TaskResult {
return p.results
}
// Stats 当前池状态
func (p *Pool) Stats() (running, total, failed int64) {
return p.running.Load(), p.total.Load(), p.failed.Load()
}
// Stop 优雅停止池
func (p *Pool) Stop() {
p.stopOnce.Do(func() {
p.cancel()
close(p.jobs)
p.wg.Wait()
close(p.results)
})
}
var ErrQueueFull = SyncError("任务队列已满,请降低提交频率或增大 BufSize")
// SyncError 用于类型断言
type SyncError string
func (e SyncError) Error() string { return string(e) }