如何在已填充的拉取上下文中实现等待 goroutine 接收页面?因为如果没有错误,Page 永远不应该返回 nil。
type Browse struct {
b *rod.Browser
ctx context.Context
pool []*Page
launch *Launch
maxSize int
mu sync.Mutex
}
func (b *Browse) Page(proxy string, url string) (*Page, error) {
b.mu.Lock()
defer b.mu.Unlock()
for i := range b.pool {
if !b.pool[i].IsActive() {
err := b.pool[i].SetUp(proxy)
if err != nil {
return nil, err
}
return b.pool[i], nil
}
}
if len(b.pool) < b.maxSize {
p := stealth.MustPage(b.b)
page, err := NewPage(p, proxy, url)
if err != nil {
return nil, err
}
b.pool = append(b.pool, page)
return page, nil
}
// TODO: not return nil
return nil, nil
}
func (b *Browse) PutPage(page *Page) {
err := page.CleanUp()
if err != nil {
fmt.Println("Error cleaning up page", err)
}
}
使用:
page, err := v.browse.Page(s.proxy, s.url)
if err != nil {
fmt.Println("Error getting page", err)
return
}
defer v.browse.PutPage(page)
我尝试实现一种从 Go 池中检索资源的机制。我希望 goroutine 在返回 nil 之前等待池已满,以确保除非出现错误,否则永远不会返回 nil。然而,当前的实现并没有按预期处理这种情况,可能导致零回报。
也许您可以利用令牌通道和轮询,如下所示,
package main
import (
"context"
"sync"
"time"
)
type Page struct {
}
func NewPage() (*Page, error) {
return &Page{}, nil
}
func (p *Page) IsInactive() bool {
return false
}
type Browse struct {
ctx context.Context
working sync.Map
tokens chan int
maxSize int
}
func NewBrowse(maxSize int) *Browse {
b := &Browse{
// ...
ctx: context.Background(),
tokens: make(chan int, maxSize),
}
for i := 0; i < maxSize; i++ {
b.tokens <- i
}
return b
}
func (b *Browse) checkInactivePage() *Page {
p := new(Page)
b.working.Range(func(key, value interface{}) bool {
if w, ok := value.(*Page); ok {
if w.IsInactive() {
p = w
return false
}
}
return true
})
return p
}
func (b *Browse) Page(ctx context.Context, proxy string, url string) (*Page, error) {
inactive := b.checkInactivePage()
if inactive != nil {
// Do something with inactive page and return
return inactive, nil
}
for {
select {
case t := <-b.tokens:
// p := stealth.MustPage(b.b)
page, err := NewPage()
if err != nil {
return nil, err
}
b.working.Store(t, struct{}{})
return page, nil
case <-ctx.Done():
return nil, ctx.Err()
default:
time.Sleep(1 * time.Second)
inactive := b.checkInactivePage()
if inactive != nil {
// Do something with inactive page and return
return inactive, nil
}
}
}
}