Этот код выбирает все файлы 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)
}
go
synchronization
goroutine
Данте
источник
источник
Note that calls with positive delta must happen before the call to Wait, or else Wait may wait for too small a group. Typically this means the calls to Add should execute before the statement creating the goroutine or other event to be waited for. See the WaitGroup example.
wg := new(sync.WaitGroup)
вместоvar wg sync.WaitGroup
.wg.Add(len(urls))
чуть выше линииfor _, url := range urls
, я считаю, что лучше, если вы используете Добавить только один раз.go vet
обнаруживает этот случай и предупреждает с помощью« func передает блокировку по значению. : sync.WaitGroup содержит sync.noCopy ".WaitGroups - определенно канонический способ сделать это. Однако для полноты картины вот решение, которое обычно использовалось до появления WaitGroups. Основная идея состоит в том, чтобы использовать канал, чтобы сказать «Я готов», и заставить основную горутину ждать, пока каждая порожденная процедура не сообщит о своем завершении.
источник
doSomething()
возвращается какой-то результат, вы можете поместить его на канал, и вы можете собирать и обрабатывать результаты во втором цикле for (как только они будут готовы)wg.Add(1)
и, таким образом, он будет отслеживать их. С каналами было бы несколько сложнее.c
, отличаются от основной горутины, которая читает изc
. Таким образом, основная горутина всегда доступна для чтения значения из канала, что произойдет, когда одна из горутин будет доступна для записи значения в канал. Вы правы, если бы этот код не порождал горутины, а вместо этого запускал бы все в одной горутине, он бы заблокировался.sync.WaitGroup может вам здесь помочь.
источник
Хотя
sync.waitGroup
(wg) - это канонический путь вперед, он требует, чтобы вы выполнили хотя бы некоторые из вашихwg.Add
вызовов перед вами,wg.Wait
чтобы все завершились. Это может оказаться невозможным для простых вещей, таких как поисковый робот, где вы заранее не знаете количество рекурсивных вызовов и требуется время, чтобы получить данные, которые управляютwg.Add
вызовами. В конце концов, вам нужно загрузить и проанализировать первую страницу, прежде чем вы узнаете размер первого пакета дочерних страниц.Я написал решение, используя каналы, избегая
waitGroup
в своем решении упражнения Tour of Go - поискового робота . Каждый раз, когда запускается одна или несколько программ, вы отправляете номер вchildren
канал. Каждый раз, когда процедура го приближается к завершению, вы отправляете1
наdone
канал. Когда сумма детей сравняется с суммой готовых, все готово.Единственное, что меня беспокоит, - это жестко заданный размер
results
канала, но это (текущее) ограничение Go.Полный исходный код решения
источник
Вот решение, в котором используется WaitGroup.
Сначала определите 2 служебных метода:
Затем замените вызов
callback
:С вызовом вашей служебной функции:
Последний шаг: добавьте эту строку в конец вашего
main
, а не вашегоsleep
. Это гарантирует, что основной поток ожидает завершения всех подпрограмм, прежде чем программа сможет остановиться.источник