Как ждать, пока все goroutines закончат, не используя время.Спать?



этот код выбирает все xml-файлы в той же папке, что и вызываемый исполняемый файл, и асинхронно применяет обработку к каждому результату в методе обратного вызова (в приведенном ниже примере выводится только имя файла).



Как мне избежать использования метода сна, чтобы основной метод не выходил? У меня есть проблемы с обертыванием головы вокруг каналов (я предполагаю, что это то, что нужно, чтобы синхронизировать результаты), поэтому любая помощь приветствуется!



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)
}
588   3  

3 ответов:

можно использовать синхронизации.WaitGroup. Цитируя связанный пример:

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

группы ожидания, безусловно, канонический способ сделать это. Просто для полноты картины, однако, вот решение, которое обычно использовалось до того, как были введены WaitGroups. Основная идея состоит в том, чтобы использовать канал, чтобы сказать: "я закончил", и заставить главный goroutine ждать, пока каждая порожденная процедура не сообщит о своем завершении.

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

синхронизации.WaitGroup могу помочь вам здесь.

package main

import (
    "fmt"
    "sync"
    "time"
)


func wait(seconds int, wg * sync.WaitGroup) {
    defer wg.Done()

    time.Sleep(time.Duration(seconds) * time.Second)
    fmt.Println("Slept ", seconds, " seconds ..")
}


func main() {
    var wg sync.WaitGroup

    for i := 0; i <= 5; i++ {
        wg.Add(1)   
        go wait(i, &wg)
    }
    wg.Wait()
}

Comments

    Ничего не найдено.