我编写了一些代码,每30分钟会同时轮询一次网址:
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中通过通信共享内存而不是相反,我调查了通道但是我不确定如何在这个例子中实现它们。
答案 0 :(得分:12)
这是一个未经测试但安全的模型,用于定期提取某些网址,并能够安全地将新网址动态添加到网址列表中。对于读者来说,如果你想删除一个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
}
答案 1 :(得分:5)
如果您需要定期轮询,不应使用time.Sleep
,而是使用time.Ticker
(或相对像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秒周期。
答案 2 :(得分: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()