如何在Golang中实现Goroutine的等待机制来检索池中的页面而不返回nil?

问题描述 投票:0回答:1

如何在已填充的拉取上下文中实现等待 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。然而,当前的实现并没有按预期处理这种情况,可能导致零回报。

go web-scraping channel goroutine
1个回答
0
投票

也许您可以利用令牌通道和轮询,如下所示,

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
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.