Привет всем, меня зовут Мин.
В период самостоятельного изучения Golang я написал подробные учебные заметки и разместил их в своем личном общедоступном аккаунте WeChat «Время программирования на Go».Что касается языка Go, я тоже новичок, поэтому то, что я написал, должно больше подходить для новых студентов, если вы только изучаете язык Go, вам стоит обратить на него внимание, учиться и расти вместе.
Мой онлайн-блог:golang.iswbm.comМой Github: github.com/iswbm/GolangCodingTime
Из первых двух статей мы узнали协程
а также信道
В ней много примеров.В то время, чтобы обеспечить выход основной горутины после выполнения всех горутин, я использовал простой метод time.Sleep.
Так как написанные демки относительно просты, засыпаем на 1 секунду, мы субъективно думаем, что этого достаточно.
Однако в реальной разработке разработчики не могут предсказать, сколько времени потребуется для завершения выполнения всех горутин: если сна слишком много, основная программа будет заблокирована, а если сна слишком мало, задачи некоторых подпрограмм будут блокированы. сопрограммы не могут быть завершены.
Поэтому использование time.Sleep крайне не рекомендуется.Сегодня я в основном расскажу, как изящно справиться с этой ситуацией.
1. Используйте каналы, чтобы отметить завершение
«Не общайтесь, делясь памятью, делитесь памятью, общаясь»
Изучив канал, мы знаем, что канал может реализовать связь между несколькими сопрограммами, тогда нам нужно только определить канал, после выполнения задачи написать true в канал, а затем получить true в основной сопрограмме, как мы думаем Дочерняя сопрограмма завершила выполнение.
import "fmt"
func main() {
done := make(chan bool)
go func() {
for i := 0; i < 5; i++ {
fmt.Println(i)
}
done <- true
}()
<-done
}
Вывод выглядит следующим образом
0
1
2
3
4
2. Используйте группу ожидания
Вышеупомянутый способ использования каналов не вызовет никаких проблем при наличии одной сопрограммы или небольшого количества сопрограмм, но при большом количестве сопрограмм код будет очень сложным, если интересно, можете попробовать сами .
Так есть ли более элегантный способ?
Да, речь идет о типе WaitGroup, предоставляемом пакетом синхронизации.
WaitGroup, который вы можете использовать до тех пор, пока вы создаете его экземпляр
var 实例名 sync.WaitGroup
После создания экземпляра доступны несколько его методов:
- Добавить: начальное значение равно 0, значение, которое вы передаете, будет добавлено к счетчику, а количество ваших подпрограмм напрямую передается сюда.
- Готово: когда подпрограмма завершена, этот метод может быть вызван, и счетчик будет уменьшен на 1. Обычно для его вызова можно использовать defer.
- Подождите: заблокируйте текущую сопрограмму, пока счетчик в экземпляре не вернется к нулю.
Например:
import (
"fmt"
"sync"
)
func worker(x int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 5; i++ {
fmt.Printf("worker %d: %d\n", x, i)
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
go worker(1, &wg)
go worker(2, &wg)
wg.Wait()
}
Вывод выглядит следующим образом
worker 2: 0
worker 2: 1
worker 2: 2
worker 2: 3
worker 2: 4
worker 1: 0
worker 1: 1
worker 1: 2
worker 1: 3
worker 1: 4
Выше показано, как мы реализуем метод взаимодействия сопрограммы одного мастера и нескольких детей на языке Go.Рекомендуется использовать sync.WaitGroup. .