2013-06-03 29 views
5

Tôi đã viết một số mã mà sẽ URL đồng thời thăm dò mỗi 30 phút:nhiệm vụ bầu cử theo lịch trình tại Gò

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() 

Làm thế nào tôi có thể sau đó thêm vào obj.UrlList nơi khác trong mã và đảm bảo rằng thời gian tới các URL được thăm dò rằng UrlList trong goroutine thăm dò ý kiến ​​cũng được cập nhật và như vậy cũng sẽ thăm dò ý kiến ​​của URL mới?

Tôi hiểu rằng bộ nhớ được chia sẻ thông qua giao tiếp thay vì ngược lại trong Go và tôi đã điều tra các kênh tuy nhiên tôi không chắc chắn cách triển khai chúng trong ví dụ này.

+0

Bạn có thể tìm thấy [this talk] (http://blog.golang.org/2013/05/advanced-go-concurrency-patterns.html) thú vị. – nemo

Trả lời

8

Đây là mô hình chưa được kiểm tra, an toàn để tìm nạp định kỳ một số URL với khả năng tự động thêm URL mới vào danh sách URL một cách an toàn. Nó sẽ được rõ ràng cho người đọc những gì sẽ được yêu cầu nếu bạn muốn loại bỏ một URL là tốt.

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 
} 
+0

Điều này làm việc hoàn toàn rực rỡ mặc dù bạn cần phải thay đổi h.ticker.C để <-h.ticker.C nếu không bạn sẽ nhận được một lỗi 'giá trị không được sử dụng'. –

+0

Tuyệt vời, tôi rất vui vì điều này đã làm việc và rõ ràng là bạn có thể làm việc xung quanh lỗi (mà tôi vừa sửa cho mỗi đặc tả của bạn). – Dustin

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() 
+0

Có lẽ Cuộc thăm dò ý kiến ​​sẽ vẫn bị sa thải ngay cả khi t.queue không được cập nhật trong khoảng thời gian ba mươi phút? –

+2

Thực tế, time.Sleep() là không cần thiết. Phạm vi trên một kênh sẽ chặn cho đến khi các giá trị có sẵn hoặc sẽ thoát khi kênh đã đóng. Tôi đã sử dụng một chan đơn giản * net.URL, mặc dù, thay vì một lát, nếu không bạn sẽ cần một vòng lặp bên trong (để trải rộng trên slice nhận được từ kênh). – mna

+0

Vâng, đó là một bản hack nhanh. ;) Nó ngủ trong 30 phút giữa mỗi cuộc thăm dò và chặn với hàng đợi trống. Một giải pháp thực sự sẽ sử dụng lựa chọn nội bộ và mặc định trong nó nếu hàng đợi trống. Việc ngủ nên được thực hiện trong nhánh đó, để kênh nhận được hoạt động miễn là dữ liệu có sẵn và nếu không toàn bộ vòng lặp sẽ mất một giấc ngủ ngắn. – Mue

2

Nếu bạn cần phải thăm dò ý kiến ​​trong khoảng thời gian định kỳ thường xuyên, bạn không sử dụng time.Sleep nhưng một time.Ticker thay vì (hoặc người thân như time.After) nên. Lý do là một giấc ngủ chỉ là một giấc ngủ và không có tài khoản trôi dạt do công việc thực sự bạn đã làm trong vòng lặp của bạn. Ngược lại, một Ticker có một goroutine riêng biệt và một kênh, mà cùng nhau có thể gửi cho bạn sự kiện thường xuyên và do đó gây ra một cái gì đó hữu ích để xảy ra.

Đây là ví dụ tương tự như của bạn. Tôi đặt trong một jitter ngẫu nhiên để minh họa lợi ích của việc sử dụng một 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() 
} 

Khi tôi chạy điều này, tôi thấy rằng nó được giữ trong chu kỳ 10 giây nghiêm ngặt mặc dù jitter.

Các vấn đề liên quan