2013-08-13 25 views
59

Mã này chọn tất cả các tệp xml trong cùng một thư mục, như thực thi được gọi và áp dụng không đồng bộ cho mỗi kết quả trong phương thức gọi lại (trong ví dụ bên dưới, chỉ tên của tệp được in ra).Làm thế nào để chờ tất cả các goroutin kết thúc mà không cần sử dụng time.Sleep?

Làm cách nào để tránh sử dụng phương pháp ngủ để giữ phương pháp chính thoát khỏi? Tôi có vấn đề bao quanh đầu của tôi xung quanh các kênh (tôi giả định đó là những gì nó cần, để đồng bộ hóa kết quả) để giúp đỡ bất kỳ được đánh giá cao!

package main 

import (
    "fmt" 
    "io/ioutil" 
    "path" 
    "path/filepath" 
    "os" 
    "runtime" 
    "time" 
) 

func eachFile(extension string, callback func(file string)) { 
    exeDir := filepath.Dir(os.Args[0]) 
    files, _ := ioutil.ReadDir(exeDir) 
    for _, f := range files { 
      fileName := f.Name() 
      if extension == path.Ext(fileName) { 
       go callback(fileName) 
      } 
    } 
} 


func main() { 
    maxProcs := runtime.NumCPU() 
    runtime.GOMAXPROCS(maxProcs) 

    eachFile(".xml", func(fileName string) { 
       // Custom logic goes in here 
       fmt.Println(fileName) 
      }) 

    // This is what i want to get rid of 
    time.Sleep(100 * time.Millisecond) 
} 

Trả lời

96

Bạn có thể sử dụng sync.WaitGroup. Trích dẫn ví dụ được liên kết:

package main 

import (
     "net/http" 
     "sync" 
) 

func main() { 
     var wg sync.WaitGroup 
     var urls = []string{ 
       "http://www.golang.org/", 
       "http://www.google.com/", 
       "http://www.somestupidname.com/", 
     } 
     for _, url := range urls { 
       // Increment the WaitGroup counter. 
       wg.Add(1) 
       // Launch a goroutine to fetch the URL. 
       go func(url string) { 
         // Decrement the counter when the goroutine completes. 
         defer wg.Done() 
         // Fetch the URL. 
         http.Get(url) 
       }(url) 
     } 
     // Wait for all HTTP fetches to complete. 
     wg.Wait() 
} 
+6

Bất kỳ lý do nào bạn phải làm wg.Thêm (1) bên ngoài thường trình đi? Chúng ta có thể làm điều đó ngay trước khi hoãn wg.Done()? – sat

+9

sat, yes, có một lý do, nó được mô tả trong sync.WaitGroup.Add tài liệu: '' 'Lưu ý rằng các cuộc gọi với đồng bằng tích cực phải xảy ra trước khi cuộc gọi Chờ, hoặc người nào khác Chờ đợi có thể chờ quá nhỏ một nhóm. Thông thường, điều này có nghĩa là các lệnh gọi Add sẽ thực hiện trước khi câu lệnh tạo ra goroutine hoặc sự kiện khác được chờ đợi. Xem ví dụ WaitGroup.''' – rslnx

+3

Việc thích ứng mã này làm cho tôi một phiên gỡ rối dài vì goroutine của tôi là một hàm được đặt tên và truyền vào WaitGroup như một giá trị sẽ sao chép nó và làm cho wg.Done() không hiệu quả. Trong khi điều này có thể được cố định bằng cách truyền con trỏ & wg, cách tốt hơn để ngăn chặn các lỗi như vậy là khai báo biến WaitGroup như một con trỏ ở vị trí đầu tiên: 'wg: = new (sync.WaitGroup)' thay vì 'var wg sync .WaitGroup'. –

37

WaitGroups chắc chắn là cách kinh điển để thực hiện việc này. Tuy nhiên, vì lợi ích của sự hoàn chỉnh, đây là giải pháp thường được sử dụng trước khi WaitGroups được giới thiệu. Ý tưởng cơ bản là sử dụng một kênh để nói "Tôi đã hoàn thành" và đợi goroutine chính cho đến khi mỗi thói quen sinh sản đã báo cáo sự hoàn thành của nó.

func main() { 
    c := make(chan struct{}) // We don't need any data to be passed, so use an empty struct 
    for i := 0; i < 100; i++ { 
     go func() { 
      doSomething() 
      c <- struct{}{} // signal that the routine has completed 
     }() 
    } 

    // Since we spawned 100 routines, receive 100 messages. 
    for i := 0; i < 100; i++ { 
     <- c 
    } 
} 
+4

Rất vui được xem giải pháp với các kênh đơn giản. Một tiền thưởng thêm: nếu 'doSomething()' trả về một số kết quả, bạn có thể đặt nó trên kênh và bạn có thể thu thập và xử lý kết quả trong vòng lặp thứ hai (ngay khi chúng sẵn sàng) – andras

+0

Ah yeah, điểm tốt . – joshlf

+2

Nó chỉ hoạt động nếu bạn đã biết số lượng gorutines bạn muốn bắt đầu. Nếu bạn đang viết một số loại trình thu thập thông tin html và bắt đầu gorutines theo cách đệ quy cho mọi liên kết trên trang? – shinydev

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