Комментарии 12
Идеоматичный мьютекс делается так:
mu.lock
defer mu.unlock
<тут операции под мьютексом, он разблокируется при выходе из зоны видимости благодаря defer>
А есть в GO классические коррутины? И есть ли там конкурентность вообще?
А есть в GO классические коррутины?
Смотря что вкладывать в понятие космических корутин.
И есть ли там конкурентность вообще?
Есть. И автор статьи на протяжении всей статьи её описывает.
Насколько я понял смысл статьи, то описывается мнонопотосность. Ну или то, что в Питоне ближе к мнонопотосности.
Ассинхронность, конкурентность в Питоне - это про цикл событий и "тики" этих событий. Когда все выполняется в одном потоке.
Что же до корутин, возможность функции передать управление и запомнить свое состояние. Есть ли это в го
"мертвые замки" - это, безусловно, шедевр :)
не очень понял фразу "Горутина состоит из 70 в коде" - 70 чего? полей? байт? чего-то еще?
Перед отправкой в канал проверяйте, не закрыт ли он уже
Интересно, как?
Перед/совместно с чтением понимаю, но как проверить перед записью, не читая?
Можно перехватывать панику при записи в закрытый канал. Но это плохая практика.
func main() {
func() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered. Error:\n", r)
}
}()
ch := make(chan struct{}, 1)
close(ch)
ch <- struct{}{}
}()
fmt.Println("done")
}
Да никак конечно, ерунда написана. Люди любят потереть за горутины и каналы (особенно на собесах), но на практике их по назначению (передача значений, а не сигнализации) почти никто не использует. Идея по сути простая: та горутина, которая пишет в канал, отрабатывает полностью (записывает всё, что у неё было) и закрывает канал. Всё, никаких проверок. Если есть fan-out (горутина, которая порождает горутины, записывающие в канал), то это она следит за тем, чтобы все порождённые горутины успели записать или, ещё лучше, переиспользуем этот канал всё время жизни программы и не закрываем его никогда. От утечки одного канала (в отличии от паники посреди работы) ничего страшного не будет.
func operation(ch chan<- string) {
// Имитация длительной операции
time.Sleep(2 * time.Second)
ch <- "результат операции"
}
func main() {
ch := make(chan string)
go operation(ch)
select {
case res := <-ch:
fmt.Println(res)
case <-time.After(1 * time.Second):
fmt.Println("Тайм-аут операции")
}
}
Автор, в данном примере есть потенциальная утечка горутины. Понятно, что в данном случае у вас выход из программы сразу происходит, но для людей, читающих ваш пример, может создастся впечатление, что так нужно делать всегда, независимо от контекста.
Я бы добавил небольшую пометку о том, что тут будет "повисшая" горутина: и она будет висесть, пока из канала не прочитают.
Либо, можно было бы этот пример реализовать через буферизованный канал с величиной буфера '1', тогда рутина не повиснет на 4ой строчке.
Многопоточность и параллелизм в Go: Goroutines и каналы