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
This commit is contained in:
146
internal/worker/pool.go
Normal file
146
internal/worker/pool.go
Normal file
@@ -0,0 +1,146 @@
|
||||
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) }
|
||||
Reference in New Issue
Block a user