2013-04-29 22 views
6

Tôi đang học Go ngay bây giờ bằng cách sử dụng và một trong những dự án đầu tiên của tôi là một tập lệnh ping đơn giản. Về cơ bản tôi muốn ping một loạt các url, và phản ứng của mỗi người đợi XXX số giây sau đó ping lại. Đây là mã tóm tắt:Việc khởi chạy goroutines bên trong goroutines có thể chấp nhận được không?

func main() { 
    // read our text file of urls 
    f, err := ioutil.ReadFile(urlFile) 
    if err != nil { 
     log.Print(err) 
    } 

    urlStrings := []string{} 
    urlStrings = strings.Split(string(f), "\n") 

    for _, v := range urlStrings { 
     go ping(v) 
    } 

    // output logs to the terminal 
    // channel is global 
    for i := range c { 
     fmt.Println(i) 
    } 
} 

func ping(url string) { 
    // for our lag timer 
    start := time.Now() 

    // make our request 
    _, err := http.Get(url) 

    if err != nil { 
     msg := url + " Error:" + err.Error() 

     fmt.Println(msg) 

     c <- msg 
     reportError(msg) 
    } else { 
     lag := time.Since(start) 
     var msg string 

     // running slow 
     if lag > lagThreshold*time.Second { 
      msg = url + " lag: " + lag.String() 
      reportError(msg) 
     } 

     msg = url + ", lag: " + lag.String() 
     c <- msg 
    } 

    time.Sleep(pingInterval * time.Second) 
    go ping(url) // is this acceptable? 
} 

Theo yêu cầu Nhận của tôi trước đây tôi đã kêu gọi hoãn res.Body.Close() nhưng điều đó đã được panicing sau khi ứng dụng chạy cho một lúc. Tôi giả định rằng trì hoãn không thể gọi lệnh Close() trên phản hồi cho đến khi goroutine đã được thu thập rác và quá trình res không còn tồn tại nữa. Điều đó khiến tôi suy nghĩ nếu bằng cách gọi một goroutine bên trong goroutine là thực hành tốt nhất hoặc nếu tôi làm cho hàm không bao giờ thoát, và sau đó trì hoãn sẽ chỉ được gọi khi goroutine được thu gom rác.

+0

Không có bất kỳ vấn đề sinh sản goroutines từ các goroutines khác, nhưng có lý do nào không chỉ sử dụng một vòng lặp trong trường hợp này? –

+0

@JamesHenstridge I 'không làm điều này trong một vòng lặp thủ tục vì vậy tôi không phải chờ đợi cho mỗi yêu cầu để trở về trước khi tôi gọi tiếp theo. Tôi đang cố gắng sử dụng đồng thời để mỗi chu kỳ ping độc lập dựa trên thời gian trễ của chính nó. – ARolek

+0

Tôi đã đề cập đến phần mà 'ping()' goroutine sinh ra một goroutine khác ngay trước khi thoát. Nếu bạn đặt một vòng lặp bên trong 'ping()', bạn sẽ nhận được cùng một hiệu ứng. –

Trả lời

11

Điều đó là tốt. Nó hoàn toàn chấp nhận được để gọi một goroutine từ một goroutine khác. Các goroutine gọi sẽ vẫn thoát ra và goroutine mới sẽ đi trên đó là cách vui vẻ.

7

Mở rộng một goroutine mới từ bên trong goroutine là hoàn toàn bình thường.

Nhưng tôi nghi ngờ đây là giải pháp đơn giản và sạch nhất cho vấn đề của bạn. Tôi đoán rằng phiên bản đầu tiên của bạn đã làm điều rõ ràng và ping mỗi URL trong một vòng lặp vô tận. Và điều này cắn trì hoãn: Các cuộc gọi trì hoãn được thực thi khi hàm trả về. (Điều này không có gì để làm wit một con ong goroutine "rác thu thập được, thực sự goroutines chỉ kết thúc, không được thu thập). Trong một vòng lặp vô tận bạn không bao giờ trở lại, bạn chỉ tích lũy các cuộc gọi trì hoãn mà không bao giờ được thực hiện. res.Body và bạn chạy ra khỏi bộ nhớ/bất cứ điều gì và nhìn thấy một hoảng loạn.

Làm defer res.Body.Close là một thành ngữ tốt đẹp, nhưng không phải bên trong một vòng lặp vô tận.

tôi sẽ cố gắng phiên bản đầu tiên của bạn và trực tiếp thực hiện res.Body .Đóng vào đường dẫn lỗi nil

+0

nếu tôi không gọi res.Body.Close() sẽ sử dụng bộ nhớ hợp chất là tốt, hoặc sẽ res được loại bỏ? – ARolek

+0

Bạn ** phải ** gọi res.Body.Close. Nó được ghi lại vì một lý do nào đó. (Mã của bạn sẽ bị rò rỉ nếu không.) – Volker

+0

nếu tôi không dùng nó để làm biến đổi như tôi đang làm ở trên thì sao? _, err: = http.Get (url) sẽ bị rò rỉ? – ARolek