7

我编写了一些代码,每 30 分钟同时轮询一次 URL:

func (obj * MyObj) Poll() {
    for ;; {
        for _, url := range obj.UrlList {
            //Download the current contents of the URL and do something with it
        }
        time.Sleep(30 * time.Minute)
}

//Start the routine in another function
go obj.Poll()

然后我将如何添加到代码中其他地方的 obj.UrlList 并确保下次轮询 URL 时 Poll goroutine 中的 UrlList 也已更新,因此也会轮询新 URL?

我知道在 Go 中内存是通过通信而不是相反的方式共享的,并且我已经研究了通道,但是我不确定如何在此示例中实现它们。

4

3 回答 3

14

这是一个未经测试但安全的模型,用于定期获取一些 URL,并能够安全地将新 URL 动态添加到 URL 列表中。如果您还想删除 URL,读者应该很清楚需要什么。

type harvester struct {
    ticker *time.Ticker // periodic ticker
    add    chan string  // new URL channel
    urls   []string     // current URLs
}

func newHarvester() *harvester {
    rv := &harvester{
        ticker: time.NewTicker(time.Minute * 30),
        add:    make(chan string),
    }
    go rv.run()
    return rv
}

func (h *harvester) run() {
    for {
        select {
        case <-h.ticker.C:
            // When the ticker fires, it's time to harvest
            for _, u := range h.urls {
                harvest(u)
            }
        case u := <-h.add:
            // At any time (other than when we're harvesting),
            // we can process a request to add a new URL
            h.urls = append(h.urls, u)
        }
    }
}

func (h *harvester) AddURL(u string) {
    // Adding a new URL is as simple as tossing it onto a channel.
    h.add <- u
}
于 2013-06-04T07:58:20.317 回答
6

如果您需要定期轮询,则不应使用time.Sleepatime.Ticker而不是(或相对的 like time.After)。原因是睡眠只是一个睡眠,并没有考虑由于您在循环中所做的实际工作而导致的漂移。相反,Ticker 有一个单独的 goroutine 和一个通道,它们一起能够向您发送常规事件,从而导致一些有用的事情发生。

这是一个与您的示例相似的示例。我放了一个随机抖动来说明使用 Ticker 的好处。

package main

import (
    "fmt"
    "time"
    "math/rand"
)

func Poll() {
    r := rand.New(rand.NewSource(99))
    c := time.Tick(10 * time.Second)
    for _ = range c {
        //Download the current contents of the URL and do something with it
        fmt.Printf("Grab at %s\n", time.Now())
        // add a bit of jitter
        jitter := time.Duration(r.Int31n(5000)) * time.Millisecond 
        time.Sleep(jitter)
    }
}

func main() {
    //go obj.Poll()
    Poll()
}

当我运行它时,我发现它保持严格的 10 秒周期,尽管有抖动。

于 2013-06-04T20:43:20.157 回答
1
// Type with queue through a channel.
type MyType struct {
    queue chan []*net.URL
}

func (t *MyType) poll() {
    for urls := range t.queue {
        ...
        time.Sleep(30 * time.Minute)
    }
}

// Create instance with buffered queue.
t := MyType{make(chan []*net.URL, 25)}

go t.Poll()
于 2013-06-03T18:37:27.583 回答