Почему появление каналов в C# должно быть для меня плохой новостью.
Потому что каналы это одна из немногих киллер фич golang. Ну так у других тоже есть. По большому счету нет большой разницы между «chan < — 5» и «await chan.WriteAsync(5);»
Однако с вашей стороны кажется странным сначала утверждать, что async/await лучше go/channel/select
В некоторых сценариях прямо сильно лучше. Я же приводил пример. Допустим есть 2 асинхронных метода, например http.get() и db.query(), каждый например в ожидании находится 1 сек. При последовательном исполнении код выполняется 2 сек, я переставил await в другое место и код стал выполнятся уже за 1 сек. А в go вам пришлось сделать кучу операций:
— Инициализировать 2 канала;
— Запустить 2 горутины;
— Сделать запись в каналы;
— Прочитать из каналов;
— Закрыть каналы.
Забыли? Я вам напомню
Последовательное выполнение: var data1 = await GetData1();
var data2 = await GetData2();
var result = Foo(data1, data2);
Параллельное выполнение: var task1 = GetData1();
var task2 = GetData2();
var result = Foo(await task1, await task2);
Однако есть еще один нюанс… select все еще нет, а учитывая то, что каналы — всего лишь библиотечная штука, удобного селекта, видимо, и не появится.
Как я уже сказал, пользователю пофиг есть select или нет, давайте обсудим реальный сценарий, который он решает.
По вашей же ссылке написано, что await возвращает управление вызывающему коду. Не в очередь, как это реализовано в Go, а ровно тому методу, который вызвал асинхронный метод.
Так и есть, но возвращает управление после того как будет получен результат, а до этого будет ожидать в очереди. Я, честно, уже потерял надежду, что вы когда нибудь это поймете, потому что раз за разом вы придумываете невероятную чепуху.
Слабая замена select'у, если честно. Task.WhenAny, цитирую, «создает задачу, которая будет выполнена после выполнения любой из предоставленных задач.» До select'а по удобству все еще, как до Луны пешком.
Приведите пример, где без select не обойтись, только нормальный, а не вывод в консоль. Скорее всего в c# аналогичная задача решается по другому. Вообще пользователю пофиг select или Task.WhenAny. Чего такого select умеет, чего нельзя сделать другими средствами? В общем без примера нет смысла обсуждать, давайте реальный пример.
Гошная модель асинхронности, как я уже неоднократно говорил, заточена на многопоточную среду исполнения. В однопоточной среде она способна только породить излишний геморрой. Поэтому сравнивать имеет смысл асинхронность именно в многопоточной среде, в однопоточной Go и не конкуррент никому.
Я же говорю, Вы не понимаете что такое асинхронность, она у вас почему-то ассоциируется с многопоточностью. Вот есть у нас 2 метода, пусть это будет условный http.get(), допустим нам нужно взять данные с двух разных серверов, допустим каждый вызов длится 1 сек. Вот код можно написать так, что он будет выполнен через 2 сек, а можно и через 1 сек и для этого многопоточность не нужна, потому что для ожидания поток не нужен. Это можно реализовать на go, c#, javascript и вообще на любом языке где есть асинхронные методы…
Вы опять несете ахинею, и делаете выводы на своих фантазиях.
Есть основной поток и пул потоков (и ещё сколько то служебных).
Task.Run() не запускает поток, а планирует выполнение задачи в пуле потоков.
В консольном приложении и в desktop код вполне может работать в основном потоке, более того, работать с интерфейсом можно только из основного потока, вам гошникам конечно это неизвестно. Но серверные приложения обрабатывают запросы в пуле потоков.
Никакой иерархии потоков нет, как я уже сказал, есть пул потоков.
Чтобы подождать выполнение одной задачи, можно использовать Task.WhenAny().
У меня складывается ощущение, что вы не понимаете что такое асинхронность, потому что постоянно говорите про потоки. Асинхронное приложение не обязательно многопоточное (кажется в браузере весь код выполняется в основном потоке, за исключением воркеров).
В общем в очередной раз вы облажались))
Давайте жгите ещё!))
Если с помощью модификатора async указать, что метод является асинхронным, у вас появятся следующие две возможности.
— Асинхронный метод сможет использовать await для обозначения точек приостановки
Вот это вас плющит))
Третий раз говорю, прочитайте ту ссылку и больше не пишите такую чушь. В той статье написано что await можно использовать только в асинхронном методе. main кстати тоже может быть асинхронным.
Я же дал ссылку, зачем придумываете от себя? Там черным по белому написано:
Выражение await в асинхронном методе не блокирует текущий поток на время выполнения ожидаемой задачи. Вместо этого выражение регистрирует остальную часть метода как продолжение и возвращает управление вызывающему объекту асинхронного метода.
await — костыль для возможности дернуть этот метод синхронно.
Нет, await как раз делает код похожим на синхронный. Как раз там где стоит await, метод приостанавливает свою работу и поток передается следующей задаче.
Насколько я понял, в go написать синхронный код невозможно, т.к. функции которые блокируют поток не добавлены, по крайней мере в стандартную библиотеку. Но если вызвать из c/cpp такую функцию, то избавиться от блокировки go не сможет.
почему-то, кажется, что во втором варианте у вас ничего параллельно не запустится.
Не надо гадать, надо проверить.
Представляем, что у вас уже есть два синхронных метода
Если они полностью синхронные (не содержат в себе I/O), то запускать их параллельно в нагруженном сервисе нет никакого смысла. А если они блокируют поток, то вместо них нужно использовать асинхронные аналоги.
Синхронные методы не становятся асинхронными добавлением async/await. Если в методе блокируется поток, то с этим ничего нельзя сделать кроме как переписать его.
Опечалить вы можете кого-нибудь другого. А с учетом того, что я всё это делаю ради эксперимента, то ошибиться вообще не страшно)).
Последовательный код c#: var data1 = await GetData1();
var data2 = await GetData2();
var result = Foo(data1, data2);
Почти параллельный код (если в методе много I/O и мало CPU): var data1 = GetData1();
var data2 = GetData2();
var result = Foo(await data1, await data2);
Параллельный код: var data1 = Task.Run(() => GetData1());
var data2 = Task.Run(() => GetData2());
var result = Foo(await data1, await data2);
Не надо лукавить! А где запись в канал? У этих функций не было такого параметра, это могла быть какая нибудь http.get(), которую нельзя было доработать. В общем понятно, с вами конструктивного обсуждения не получится, фанатизм так и прёт.
<В чем суть проблемы-то?blockquote>
В том что результат надо обработать. Ваш код красив для заманухи, но по факту он бесполезен, потому что в нем нет обработки результатов. Задача: Надо собрать данные по разным источникам (например с двух http сервисов) и вернуть одним ответом пользователю. С await сильно короче получается. Вы приведите полный код, тогда его можно будет обсудить
Потому что каналы это одна из немногих киллер фич golang. Ну так у других тоже есть. По большому счету нет большой разницы между «chan < — 5» и «await chan.WriteAsync(5);»
В некоторых сценариях прямо сильно лучше. Я же приводил пример. Допустим есть 2 асинхронных метода, например http.get() и db.query(), каждый например в ожидании находится 1 сек. При последовательном исполнении код выполняется 2 сек, я переставил await в другое место и код стал выполнятся уже за 1 сек. А в go вам пришлось сделать кучу операций:
— Инициализировать 2 канала;
— Запустить 2 горутины;
— Сделать запись в каналы;
— Прочитать из каналов;
— Закрыть каналы.
Забыли? Я вам напомню
Последовательное выполнение:
var data1 = await GetData1();
var data2 = await GetData2();
var result = Foo(data1, data2);
Параллельное выполнение:
var task1 = GetData1();
var task2 = GetData2();
var result = Foo(await task1, await task2);
Как я уже сказал, пользователю пофиг есть select или нет, давайте обсудим реальный сценарий, который он решает.
Так и есть, но возвращает управление после того как будет получен результат, а до этого будет ожидать в очереди. Я, честно, уже потерял надежду, что вы когда нибудь это поймете, потому что раз за разом вы придумываете невероятную чепуху.
Приведите пример, где без select не обойтись, только нормальный, а не вывод в консоль. Скорее всего в c# аналогичная задача решается по другому. Вообще пользователю пофиг select или Task.WhenAny. Чего такого select умеет, чего нельзя сделать другими средствами? В общем без примера нет смысла обсуждать, давайте реальный пример.
Я же говорю, Вы не понимаете что такое асинхронность, она у вас почему-то ассоциируется с многопоточностью. Вот есть у нас 2 метода, пусть это будет условный http.get(), допустим нам нужно взять данные с двух разных серверов, допустим каждый вызов длится 1 сек. Вот код можно написать так, что он будет выполнен через 2 сек, а можно и через 1 сек и для этого многопоточность не нужна, потому что для ожидания поток не нужен. Это можно реализовать на go, c#, javascript и вообще на любом языке где есть асинхронные методы…
Шах и мат))
Есть основной поток и пул потоков (и ещё сколько то служебных).
Task.Run() не запускает поток, а планирует выполнение задачи в пуле потоков.
В консольном приложении и в desktop код вполне может работать в основном потоке, более того, работать с интерфейсом можно только из основного потока, вам гошникам конечно это неизвестно. Но серверные приложения обрабатывают запросы в пуле потоков.
Никакой иерархии потоков нет, как я уже сказал, есть пул потоков.
Чтобы подождать выполнение одной задачи, можно использовать Task.WhenAny().
У меня складывается ощущение, что вы не понимаете что такое асинхронность, потому что постоянно говорите про потоки. Асинхронное приложение не обязательно многопоточное (кажется в браузере весь код выполняется в основном потоке, за исключением воркеров).
В общем в очередной раз вы облажались))
Давайте жгите ещё!))
Также в этой статье есть ссылки на ключевое слово await docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/await там написано:
Также можно попробовать использовать await в синхронном методе, на что будет выдана ошибка:
Поздравляю, с этого места мы будем считать вас окончательно и бесповоротно… кхм… фантазёром))
На этой веселой ноте я заканчиваю обсуждение ваших фантазий.
Третий раз говорю, прочитайте ту ссылку и больше не пишите такую чушь. В той статье написано что await можно использовать только в асинхронном методе. main кстати тоже может быть асинхронным.
Нет, await как раз делает код похожим на синхронный. Как раз там где стоит await, метод приостанавливает свою работу и поток передается следующей задаче.
Уже даже по русски везде об этом написано и с картинками, почитайте docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/concepts/async/#BKMK_Threads
Как раз таки наоборот.
Не надо гадать, надо проверить.
Если они полностью синхронные (не содержат в себе I/O), то запускать их параллельно в нагруженном сервисе нет никакого смысла. А если они блокируют поток, то вместо них нужно использовать асинхронные аналоги.
Синхронные методы не становятся асинхронными добавлением async/await. Если в методе блокируется поток, то с этим ничего нельзя сделать кроме как переписать его.
Последовательный код c#:
var data1 = await GetData1();
var data2 = await GetData2();
var result = Foo(data1, data2);
Почти параллельный код (если в методе много I/O и мало CPU):
var data1 = GetData1();
var data2 = GetData2();
var result = Foo(await data1, await data2);
Параллельный код:
var data1 = Task.Run(() => GetData1());
var data2 = Task.Run(() => GetData2());
var result = Foo(await data1, await data2);