Похоже нет никакой краткости. «go foo()» — выглядит кратко, но по факту этот код бесполезен. Например если нам надо отправить параллельно 2 Http-запроса, то код становится сильно больше.
У меня какое-то двоякое чувство, на простых примерах всё красиво, асинхронный код выглядит как синхронный, даже async/await не нужны. Но чуть в сторону и лапша какая-то получается…
Ок, только всё началось с того, где были описаны минусы корутин:
Из очевидных минусов: если внутри корутины до yield'а есть что-то очень трудоемкое, либо что-то, что ставит поток раком, либо какое-то долгое ожидание — нагнется целиком системный поток.
Давайте код, который ставит раком поток, очень хочется убедиться что там не говнокод.
Да я go установил впервые только несколько дней назад, потому что стало интересно посмотреть что там за такие горутины. А Вы мне такие вопросы задаете))
Ваш пример был ошибочным, трэд там в состоянии Running и то что сказал qrKot подтвердилось вашим же примером.
Ну да, тред работает, только остальные горутины остались в пролете. Бесконечный цикл скорее всего исключение, но вот долгое выполнение вполне реально может случиться. Пользователю то пофиг, тред твой тормознулся или занят непонятной херней, ему главное чтобы сайт не тормозил, а вместо этого получит 503.
Из очевидных минусов: если внутри корутины до yield'а есть что-то очень трудоемкое, либо что-то, что ставит поток раком, либо какое-то долгое ожидание — нагнется целиком системный поток.
вот в go я запустил как раз трудоемкое. Что не так то? От своих слов отказываетесь?
А насчет долгих ожиданий, так уже давно везде реализовано асинхронное апи для I/O, все прекрасно знают об этом.
Вы уже уходите от темы, то есть вы согласны что «никакая горутина не может поставить колом целиком поток»?
Да я откуда знаю, может есть еще и другие способы. Тем не менее, это работает не так как написал qrKot. Это не плохо и не хорошо, это примерно также как и у других.
Вот в Go, за счет того, что заблокированая горутина паркуется и не блокирует трэд, второй запрос у вас обработается быстрее, так как во время I/O первой горутины, будет выполняться вторая.
Вы так говорите, как будто это уникальная фича go, да у всех асинхронных серверов так. Понятно что в старых языках типа Java остались синхронные апи для I/O, ну сам себе буратино что используешь их в асинхронном методе. Ну кстати не всегда и требуется переписывать на асинхрон, я как-то переписал консольную утилиту и она стала медленнее работать, накладных расходов потому что стало больше чем полезного кода.
в той же Java на ожидание ответа системного вызова блокируется весь поток
И у этого вызова нет асинхронного аналога? И он реально долгий?
Ну частое переключение, как мне кажется, тоже имеет свои минусы, например это избыточные накладные расходы (сохранить стек от одной горутины, восстановить от другой). В глобальном плане это вообще пофигу, например когда сервис обслуживает тысячи запросов. Например одно ядро должно обслужить 2 запроса, каждый из которых требует 100 мс процессора, то нам все равно, оба запроса выполнятся параллельно и оба ответа вернутся через 200 мс, или последовательно и тогда первый ответ вернется через 100 мс, а второй через 200 мс. Пример конечно упрощенный, но думаю суть понятна.
Чтобы ограничить выполнение одним потоком. Чтобы проще было проверить. Не нравится этот код, вот вам другой:
func main() {
for i := 0; i < 100500; i++ {
go test(0)
}
time.Sleep(1)
go fmt.Println("main 1")
fmt.Println("main 2")
}
func test(t int) {
fmt.Println("start")
for true {
t = t + 1
}
fmt.Println("stop")
}
У меня выводит 8 раз «start» и больше нифига. В итоге непонятно чем горутины лучше котлиновских корутин, дотнентых тасков и т.д. По большому счету нам всегда надо знать, нужно ожидать завершения метода или не нужно. В go если нужно ждать, то пишем просто «foo()», а если не нужно, то «go foo()», а в c# наоборот «await foo();» и «foo();». Я кстати не разработчик go, и не разработчик c#, так что пишите критику и одни и другие))
Следующий код у меня не выводит «main». Вывод: горутина может повесить всю программу. А иначе зачем тогда нужен метод runtime.Gosched()? Ксати, если его вызов вставить в цикл, то «main» будет выводиться.
func main() {
t := 0
runtime.GOMAXPROCS(1)
go test(t)
time.Sleep(1)
fmt.Println("main")
}
func test(t int) {
fmt.Println("start")
for true {
t = t + 1
}
fmt.Println("stop")
}
При этом для кеширующих вещей, маршрутизации, сетевых кешей, лоад-балансировщиков ну или просто «показать API наружу» мне в голову не придет использовать C# — Go тут просто удобней.
Я думаю в этих случаях большая часть людей воспользуется готовым решением, а остальные будут использовать cpp или rust.
Ну это зря вы меня обвиняете в хейтинге. Как говорится «всё познается в сравнении», я просто знаю немного c#.
Task — это класс из стандартной библиотеки.
Короткая запись конечно лучше длинной.
Если каналы такие удобные, то надо просто их заюзать в своем языке, почему бы не воспользоваться лучшими практиками из другого языка? Мне кажется так часто поступают.
Я думаю, в современном мире, редко пишут на одном языке. Я иногда пишу и на c#, приходилось и на java и kotlin. Думаю и GO мне пригодится, какую-нибудь утилиту для линукс написать, хорошо что получается единственный файл со всеми зависимости.
Прошу пояснить для незнающих:
1. использование go перед любой функцией принципиально чем-то отличается от например c# Task.Run(()=>Foo()), кроме более короткого способа записи?
2. Каналы можно реализовать на другом языке (на том же c#) или это фича именно GO?
Разработчиков, админов и т.д. сколько в стране? И почти каждому хочется за недорого иметь свой серверочек в облаке для небольших но разноплановых задач. Ну так и продавайте, хоть даже с oversell, все будут только рады.
Похоже нет никакой краткости. «go foo()» — выглядит кратко, но по факту этот код бесполезен. Например если нам надо отправить параллельно 2 Http-запроса, то код становится сильно больше.
У меня какое-то двоякое чувство, на простых примерах всё красиво, асинхронный код выглядит как синхронный, даже async/await не нужны. Но чуть в сторону и лапша какая-то получается…
Спасибо за ответы!
Давайте код, который ставит раком поток, очень хочется убедиться что там не говнокод.
Да я go установил впервые только несколько дней назад, потому что стало интересно посмотреть что там за такие горутины. А Вы мне такие вопросы задаете))
Ну да, тред работает, только остальные горутины остались в пролете. Бесконечный цикл скорее всего исключение, но вот долгое выполнение вполне реально может случиться. Пользователю то пофиг, тред твой тормознулся или занят непонятной херней, ему главное чтобы сайт не тормозил, а вместо этого получит 503.
вот в go я запустил как раз трудоемкое. Что не так то? От своих слов отказываетесь?
А насчет долгих ожиданий, так уже давно везде реализовано асинхронное апи для I/O, все прекрасно знают об этом.
Да я откуда знаю, может есть еще и другие способы. Тем не менее, это работает не так как написал qrKot. Это не плохо и не хорошо, это примерно также как и у других.
Вы так говорите, как будто это уникальная фича go, да у всех асинхронных серверов так. Понятно что в старых языках типа Java остались синхронные апи для I/O, ну сам себе буратино что используешь их в асинхронном методе. Ну кстати не всегда и требуется переписывать на асинхрон, я как-то переписал консольную утилиту и она стала медленнее работать, накладных расходов потому что стало больше чем полезного кода.
И у этого вызова нет асинхронного аналога? И он реально долгий?
Ну частое переключение, как мне кажется, тоже имеет свои минусы, например это избыточные накладные расходы (сохранить стек от одной горутины, восстановить от другой). В глобальном плане это вообще пофигу, например когда сервис обслуживает тысячи запросов. Например одно ядро должно обслужить 2 запроса, каждый из которых требует 100 мс процессора, то нам все равно, оба запроса выполнятся параллельно и оба ответа вернутся через 200 мс, или последовательно и тогда первый ответ вернется через 100 мс, а второй через 200 мс. Пример конечно упрощенный, но думаю суть понятна.
Захотелось проверить, но чуда не произошло
У меня выводит 8 раз «start» и больше нифига. В итоге непонятно чем горутины лучше котлиновских корутин, дотнентых тасков и т.д. По большому счету нам всегда надо знать, нужно ожидать завершения метода или не нужно. В go если нужно ждать, то пишем просто «foo()», а если не нужно, то «go foo()», а в c# наоборот «await foo();» и «foo();». Я кстати не разработчик go, и не разработчик c#, так что пишите критику и одни и другие))
Я думаю в этих случаях большая часть людей воспользуется готовым решением, а остальные будут использовать cpp или rust.
Task — это класс из стандартной библиотеки.
Короткая запись конечно лучше длинной.
Если каналы такие удобные, то надо просто их заюзать в своем языке, почему бы не воспользоваться лучшими практиками из другого языка? Мне кажется так часто поступают.
Я думаю, в современном мире, редко пишут на одном языке. Я иногда пишу и на c#, приходилось и на java и kotlin. Думаю и GO мне пригодится, какую-нибудь утилиту для линукс написать, хорошо что получается единственный файл со всеми зависимости.
1. использование go перед любой функцией принципиально чем-то отличается от например c# Task.Run(()=>Foo()), кроме более короткого способа записи?
2. Каналы можно реализовать на другом языке (на том же c#) или это фича именно GO?
POST https://example.com/comments HTTP/1.1
content-type: application/json
{
"name": "sample",
"time": "Wed, 21 Oct 2015 18:27:50 GMT"
}
Пользуюсь стандартами разработки с 13 года. Не верите? Смотрите сами https://web.archive.org/web/20130417015349/https://its.1c.ru/#dev