Skip to content

Commit afc3c02

Browse files
author
www.xueximeng.com
committed
fix:pansearch
1 parent 51c3015 commit afc3c02

2 files changed

Lines changed: 157 additions & 112 deletions

File tree

plugin/pansearch/pansearch.go

Lines changed: 63 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,18 @@ var (
2424

2525
// 从__NEXT_DATA__脚本中提取数据的正则表达式
2626
nextDataRegex = regexp.MustCompile(`<script id="__NEXT_DATA__" type="application/json">(.*?)</script>`)
27-
27+
2828
// 缓存相关变量
29-
searchResultCache = sync.Map{}
29+
searchResultCache = sync.Map{}
3030
lastCacheCleanTime = time.Now()
31-
cacheTTL = 1 * time.Hour
31+
cacheTTL = 1 * time.Hour
3232
)
3333

3434
// 在init函数中注册插件
3535
func init() {
3636
// 使用全局超时时间创建插件实例并注册
3737
plugin.RegisterGlobalPlugin(NewPanSearchPlugin())
38-
38+
3939
// 启动缓存清理goroutine
4040
go startCacheCleaner()
4141
}
@@ -45,7 +45,7 @@ func startCacheCleaner() {
4545
// 每小时清理一次缓存
4646
ticker := time.NewTicker(1 * time.Hour)
4747
defer ticker.Stop()
48-
48+
4949
for range ticker.C {
5050
// 清空所有缓存
5151
searchResultCache = sync.Map{}
@@ -102,17 +102,18 @@ type PanSearchAsyncPlugin struct {
102102
maxResults int
103103
maxConcurrent int
104104
retries int
105-
workerPool *WorkerPool // 添加工作池
106105
}
107106

108107
// WorkerPool 工作池结构
109108
type WorkerPool struct {
110-
tasks chan Task
111-
results chan TaskResult
112-
errors chan error
113-
wg sync.WaitGroup
114-
closed atomic.Bool // 添加原子标志来标记工作池是否已关闭
115-
mu sync.Mutex // 添加互斥锁保护提交操作
109+
tasks chan Task
110+
results chan TaskResult
111+
errors chan error
112+
workerCount int
113+
wg sync.WaitGroup
114+
closed atomic.Bool
115+
mu sync.Mutex
116+
closeOnce sync.Once
116117
}
117118

118119
// Task 工作任务
@@ -129,17 +130,25 @@ type TaskResult struct {
129130
}
130131

131132
// NewWorkerPool 创建新的工作池
132-
func NewWorkerPool(size int) *WorkerPool {
133+
func NewWorkerPool(workerCount, bufferSize int) *WorkerPool {
134+
if workerCount < 1 {
135+
workerCount = 1
136+
}
137+
if bufferSize < workerCount {
138+
bufferSize = workerCount
139+
}
140+
133141
return &WorkerPool{
134-
tasks: make(chan Task, size*3), // 增加任务通道容量
135-
results: make(chan TaskResult, size*3), // 增加结果通道容量
136-
errors: make(chan error, size*3), // 增加错误通道容量
142+
tasks: make(chan Task, bufferSize),
143+
results: make(chan TaskResult, bufferSize),
144+
errors: make(chan error, bufferSize),
145+
workerCount: workerCount,
137146
}
138147
}
139148

140149
// Start 启动工作池
141150
func (wp *WorkerPool) Start(ctx context.Context, handler func(ctx context.Context, task Task) (TaskResult, error)) {
142-
for i := 0; i < cap(wp.tasks); i++ {
151+
for i := 0; i < wp.workerCount; i++ {
143152
wp.wg.Add(1)
144153
go func() {
145154
defer wp.wg.Done()
@@ -154,18 +163,14 @@ func (wp *WorkerPool) Start(ctx context.Context, handler func(ctx context.Contex
154163
if err != nil {
155164
select {
156165
case wp.errors <- err:
157-
// 成功发送错误
158-
default:
159-
// 通道可能已关闭,忽略错误
160-
fmt.Printf("无法发送错误: %v\n", err)
166+
case <-ctx.Done():
167+
return
161168
}
162169
} else {
163170
select {
164171
case wp.results <- result:
165-
// 成功发送结果
166-
default:
167-
// 通道可能已关闭,忽略结果
168-
fmt.Printf("无法发送结果\n")
172+
case <-ctx.Done():
173+
return
169174
}
170175
}
171176

@@ -182,52 +187,26 @@ func (wp *WorkerPool) Submit(task Task) bool {
182187
wp.mu.Lock()
183188
defer wp.mu.Unlock()
184189

185-
// 检查工作池是否已关闭
186190
if wp.closed.Load() {
187191
return false
188192
}
189193

190-
select {
191-
case wp.tasks <- task:
192-
return true
193-
default:
194-
// 如果通道已满,返回失败
195-
return false
196-
}
194+
wp.tasks <- task
195+
return true
197196
}
198197

199198
// Close 关闭工作池
200199
func (wp *WorkerPool) Close() {
201-
wp.mu.Lock()
202-
if !wp.closed.Load() {
200+
wp.closeOnce.Do(func() {
201+
wp.mu.Lock()
203202
wp.closed.Store(true)
204203
close(wp.tasks)
205-
}
206-
wp.mu.Unlock()
204+
wp.mu.Unlock()
207205

208-
wp.wg.Wait()
209-
210-
// 安全关闭结果和错误通道
211-
wp.mu.Lock()
212-
defer wp.mu.Unlock()
213-
214-
select {
215-
case _, ok := <-wp.results:
216-
if ok {
217-
close(wp.results)
218-
}
219-
default:
206+
wp.wg.Wait()
220207
close(wp.results)
221-
}
222-
223-
select {
224-
case _, ok := <-wp.errors:
225-
if ok {
226-
close(wp.errors)
227-
}
228-
default:
229208
close(wp.errors)
230-
}
209+
})
231210
}
232211

233212
// NewPanSearchPlugin 创建新的盘搜异步插件
@@ -241,7 +220,6 @@ func NewPanSearchPlugin() *PanSearchAsyncPlugin {
241220
maxResults: MaxResults,
242221
maxConcurrent: maxConcurrent,
243222
retries: MaxRetries,
244-
workerPool: NewWorkerPool(maxConcurrent), // 初始化工作池
245223
}
246224

247225
// 初始化时预热获取 buildId
@@ -548,13 +526,13 @@ func (p *PanSearchAsyncPlugin) doSearch(client *http.Client, keyword string, ext
548526
remainingResults := min(total-PageSize, p.maxResults-PageSize)
549527
if remainingResults <= 0 {
550528
results := p.convertResults(allResults, keyword)
551-
529+
552530
// 缓存结果
553531
searchResultCache.Store(keyword, cachedResponse{
554532
results: results,
555533
timestamp: time.Now(),
556534
})
557-
535+
558536
return results, nil
559537
}
560538

@@ -564,21 +542,21 @@ func (p *PanSearchAsyncPlugin) doSearch(client *http.Client, keyword string, ext
564542
// 如果只需要获取少量页面,直接返回
565543
if neededPages <= 0 {
566544
results := p.convertResults(allResults, keyword)
567-
545+
568546
// 缓存结果
569547
searchResultCache.Store(keyword, cachedResponse{
570548
results: results,
571549
timestamp: time.Now(),
572550
})
573-
551+
574552
return results, nil
575553
}
576554

577555
// 根据实际页数确定并发数,但不超过最大并发数
578556
actualConcurrent := min(neededPages, p.maxConcurrent)
579557

580-
// 创建适合实际并发数的工作池
581-
p.workerPool = NewWorkerPool(actualConcurrent)
558+
// 工作池是单次请求的局部资源,避免并发请求共享状态
559+
pool := NewWorkerPool(actualConcurrent, neededPages)
582560

583561
// 创建上下文用于管理所有请求
584562
ctx, cancel := context.WithTimeout(context.Background(), p.timeout*2)
@@ -588,7 +566,7 @@ func (p *PanSearchAsyncPlugin) doSearch(client *http.Client, keyword string, ext
588566
needRefreshBuildId := &atomic.Bool{}
589567

590568
// 启动工作池
591-
p.workerPool.Start(ctx, func(ctx context.Context, task Task) (TaskResult, error) {
569+
pool.Start(ctx, func(ctx context.Context, task Task) (TaskResult, error) {
592570
var pageResults []PanSearchItem
593571
var err error
594572

@@ -664,15 +642,8 @@ func (p *PanSearchAsyncPlugin) doSearch(client *http.Client, keyword string, ext
664642
// 提交任务计数器
665643
submittedTasks := 0
666644

667-
// 简化批次处理逻辑,考虑到最多只有99页需要获取(第一页已经获取)
668-
// 使用两个批次:每批次最多50页,避免一次性提交过多任务
669-
batchSize := (neededPages + 1) / 2 // 将总页数分成两批
670-
if batchSize < 1 {
671-
batchSize = neededPages // 如果页数很少,就一次性提交所有任务
672-
}
673-
674645
// 提交所有任务
675-
for i := 0; i < neededPages; i += batchSize {
646+
for i := 0; i < neededPages; i++ {
676647
// 检查上下文是否已取消
677648
select {
678649
case <-ctx.Done():
@@ -682,46 +653,26 @@ func (p *PanSearchAsyncPlugin) doSearch(client *http.Client, keyword string, ext
682653
// 继续执行
683654
}
684655

685-
end := i + batchSize
686-
if end > neededPages {
687-
end = neededPages
688-
}
689-
690-
// 提交一批任务
691-
for j := i; j < end; j++ {
692-
offset := PageSize + j*PageSize
693-
if offset < p.maxResults {
694-
task := Task{
695-
keyword: keyword,
696-
offset: offset,
697-
baseURL: baseURL,
698-
}
699-
700-
// 尝试提交任务,如果失败则跳出循环
701-
if !p.workerPool.Submit(task) {
702-
fmt.Printf("无法提交任务,工作池可能已关闭\n")
703-
goto CollectResults
704-
}
705-
706-
submittedTasks++
656+
offset := PageSize + i*PageSize
657+
if offset < p.maxResults {
658+
task := Task{
659+
keyword: keyword,
660+
offset: offset,
661+
baseURL: baseURL,
707662
}
708-
}
709663

710-
// 只有在有多个批次且不是最后一批时才等待
711-
if batchSize < neededPages && end < neededPages {
712-
select {
713-
case <-time.After(50 * time.Millisecond):
714-
// 继续执行
715-
case <-ctx.Done():
716-
// 上下文已取消,停止提交任务
664+
if !pool.Submit(task) {
665+
fmt.Printf("无法提交任务,工作池可能已关闭\n")
717666
goto CollectResults
718667
}
668+
669+
submittedTasks++
719670
}
720671
}
721672

722673
CollectResults:
723674
// 关闭任务提交通道
724-
go p.workerPool.Close()
675+
go pool.Close()
725676

726677
// 收集结果
727678
resultCount := 0
@@ -731,15 +682,15 @@ CollectResults:
731682
// 使用select非阻塞地收集结果和错误
732683
for resultCount+errorCount < submittedTasks {
733684
select {
734-
case result, ok := <-p.workerPool.results:
685+
case result, ok := <-pool.results:
735686
if !ok {
736687
// 结果通道已关闭
737688
goto ProcessResults
738689
}
739690
allResults = append(allResults, result.results...)
740691
resultCount++
741692

742-
case err, ok := <-p.workerPool.errors:
693+
case err, ok := <-pool.errors:
743694
if !ok {
744695
// 错误通道已关闭
745696
goto ProcessResults
@@ -750,13 +701,13 @@ CollectResults:
750701
case <-ctx.Done():
751702
// 上下文超时,返回已收集的结果
752703
results := p.convertResults(allResults, keyword)
753-
704+
754705
// 缓存结果(即使超时也缓存已获取的结果)
755706
searchResultCache.Store(keyword, cachedResponse{
756707
results: results,
757708
timestamp: time.Now(),
758709
})
759-
710+
760711
return results, fmt.Errorf("搜索超时: %w", ctx.Err())
761712
}
762713
}
@@ -765,20 +716,20 @@ ProcessResults:
765716
// 如果所有请求都失败且没有获得首页以外的结果,则返回错误
766717
if submittedTasks > 0 && errorCount == submittedTasks && len(allResults) == len(firstPageResults) {
767718
results := p.convertResults(allResults, keyword)
768-
719+
769720
// 缓存结果(即使有错误也缓存已获取的结果)
770721
searchResultCache.Store(keyword, cachedResponse{
771722
results: results,
772723
timestamp: time.Now(),
773724
})
774-
725+
775726
return results, fmt.Errorf("所有后续页面请求失败: %v", lastError)
776727
}
777728

778729
// 4. 去重和格式化结果
779730
uniqueResults := p.deduplicateItems(allResults)
780731
results := p.convertResults(uniqueResults, keyword)
781-
732+
782733
// 缓存结果
783734
searchResultCache.Store(keyword, cachedResponse{
784735
results: results,

0 commit comments

Comments
 (0)