Re[4]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 14.12.25 12:05
Оценка:
Здравствуйте, Doom100500, Вы писали:

D>Здравствуйте, mrTwister, Вы писали:


T>>А по факту весь код в го ..... по умолчанию асинхронный.


D>Это как?


D>
D>func foo() {
D>}

D>func bar() {
D>  foo() // Так по-умолчанию
D>  go foo() // Так асинхронно
D>}
D>


Оба этих варианта асинхронны и не блокируют поток операционной системы.
лэт ми спик фром май харт
Re[8]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 14.12.25 12:10
Оценка:
Здравствуйте, novitk, Вы писали:

N>Здравствуйте, mrTwister, Вы писали:


T>>В go ничего переписывать не надо, функция всегда выглядит одинаково.

N>Ты повторяешь одно и тоже. Вместо формализма, что функции в Го не помечены, с которого я собственно и начал, приведи пример реальной функции в go которая бы работала в двух контекстах?

В go есть только асинхронный контекст, нет никаких двух контекстов, любая функция в go всегда работает в асинхронном контексте.
лэт ми спик фром май харт
Re[5]: Можно ли избавиться от async|await?
От: Doom100500 Израиль  
Дата: 14.12.25 14:15
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Оба этих варианта асинхронны и не блокируют поток операционной системы.


Тогда в чём разница между этими вызовами?

func foo() {
    fmt.Println(runtime.NumGoroutine())
    time.Sleep(1000)
    fmt.Println(runtime.NumGoroutine())
}

func main() {
    fmt.Println(runtime.NumGoroutine())
    foo()
    fmt.Println(runtime.NumGoroutine())
}

/// out:
1
1
1
1

func foo(wg *sync.WaitGroup) {
    fmt.Println(runtime.NumGoroutine())
    time.Sleep(1000)
    fmt.Println(runtime.NumGoroutine())
    wg.Done()
}


func main() {
    fmt.Println(runtime.NumGoroutine())
    wg := &sync.WaitGroup{}
    wg.Add(1)
    go foo(wg)
    fmt.Println(runtime.NumGoroutine())
    wg.Wait()
    fmt.Println(runtime.NumGoroutine())
}

/// out:
1
2
2
2
1


Какой поток операционной системы?

https://go.dev/tour/concurrency/1

A goroutine is a lightweight thread managed by the Go runtime.


Программа на любом языке состоит из, как минимум, одного потока, который не блокирует современную многозагачную операционную сицтему.
Спасибо за внимание
Re[5]: Можно ли избавиться от async|await?
От: SkyDance Земля  
Дата: 14.12.25 14:28
Оценка:
Аё>Написать go вместо async и receive вместо await делает код легкочитабельным?

await разве умеет pattern matching? Если да, то — как и предсказано Робертом Вирдингом, "Any sufficiently complicated concurrent program in another language contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Erlang."
Re[6]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 14.12.25 14:54
Оценка:
Здравствуйте, Doom100500, Вы писали:

D>Тогда в чём разница между этими вызовами?


Я не понял, что ты хотел продемонстрировать этими примерами

D>Какой поток операционной системы?


D>https://go.dev/tour/concurrency/1

D>

D>A goroutine is a lightweight thread managed by the Go runtime.


Главное слово выделил, горутина — это внутренняя структура в go, которая не имеет никакого отношения к потокам. Это что-то типа класса Task в C#

D>Программа на любом языке состоит из, как минимум, одного потока, который не блокирует современную многозагачную операционную сицтему.


Разница в том, что если, например в C# я запущу параллельно 1000 функций Thread.Sleep, то я создам и заблокирую 1000 потоков операционной системы, потому что Thread.Sleep синхронная. Если я запущу в go в горутинах 1000 функций time.Sleep, я не создам ни одного дополнительного потока операционной системы, потому что time.Sleep как и все остальные функции в go асинхронная. Аналогом time.Sleep из go является в .net Task.Delay, вот она асинхронная.
лэт ми спик фром май харт
Отредактировано 14.12.2025 14:54 mrTwister . Предыдущая версия .
Re[9]: Можно ли избавиться от async|await?
От: novitk США  
Дата: 14.12.25 16:07
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>В go есть только асинхронный контекст, нет никаких двух контекстов, любая функция в go всегда работает в асинхронном контексте.

Если бы это было так то слово go было бы не нужно. Точно так же можно сказать, что в C# нет никаких async функций, все синхронны просто возвращают разное, и это будет правдой, но словоблудием. То что компилятор Go не жалуется, а должен бы, на "go prime(10000)" не означает, что функция написанная с return удобоварима асинхронно. Это обычная дыра, которых в GoLang гора, оставленная во имя "простоты".
Отредактировано 14.12.2025 16:23 novitk . Предыдущая версия . Еще …
Отредактировано 14.12.2025 16:08 novitk . Предыдущая версия .
Re[6]: Можно ли избавиться от async|await?
От: novitk США  
Дата: 14.12.25 16:36
Оценка: +2
Здравствуйте, SkyDance, Вы писали:

Аё>>Написать go вместо async и receive вместо await делает код легкочитабельным?

SD>await разве умеет pattern matching? Если да, то — как и предсказано Робертом Вирдингом, "Any sufficiently complicated concurrent program in another language contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Erlang."

Я понимаю, что Erlang даже большая религия чем GoLang, но чердак надо держать в порядке.
Какое нафиг отношение pattern matching имеет к асинхронности? В языках, которые поддерживают обе концепции (C#/F#/Scala/Haskell), все конечно бесшовно комбинируeтся:
string message = (await CountRecordsAsync()) switch
{
    0 => "No records found.",
    > 10 => "Too many records to display.",
    _ => "Insanely many records."
};
Отредактировано 14.12.2025 16:59 novitk . Предыдущая версия . Еще …
Отредактировано 14.12.2025 16:40 novitk . Предыдущая версия .
Отредактировано 14.12.2025 16:38 novitk . Предыдущая версия .
Re[4]: Можно ли избавиться от async|await?
От: novitk США  
Дата: 14.12.25 16:58
Оценка:
Здравствуйте, SkyDance, Вы писали:

N>>В Erlang разве не обычные синхронные функции, обертывание которых в процессы требует даже большей церемонии чем async/await в C#/JS/Python?

SD>Не знаю, что подразумевается под "церемониями", но там все реально очень просто, в том числе и запуск отдельного процесса.
Допустим у тебя есть функция prime/1(возвращает Ns простое число). Работает слишком долго и блокируют. В случае C# берем код как есть, ставим async, переименовываем в GetPrimeAsync. Если есть желание, но в современном мире multicore уже не обязательно, разбрасываем "await Task.Yield()".
В Эрланге надo полностью разбить на процессы.
Отредактировано 14.12.2025 17:02 novitk . Предыдущая версия .
Re[10]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 14.12.25 17:25
Оценка:
Здравствуйте, novitk, Вы писали:

N>Если бы это было так то слово go было бы не нужно.


Слово go — это возможность вызвать асинхронную функцию без await'а. От этого вызываемая функция не начинает и не перестает быть асинхронной.
Пример из C#:
static async void MyDelay() {
    await Task.Delay(....)
}


Эта функция асинхронна, она не блокирует тред. Вот ее полный аналог из go:
func MyDelay() {
    time.Sleep(...)
}


Это такая же асинхронная функция и она ничем не отличается от асинхронной функции из C#

Слово go — это по просто отсутствие await. Аналогами будут:

C#:
static async void MyDelay() {
    Task.Delay(....)
}


Go:
func MyDelay() {
    go time.Sleep(...)
}


N>Точно так же можно сказать, что в C# нет никаких async функций, все синхронны просто возвращают разное, и это будет правдой, но словоблудием. То что компилятор Go не жалуется, а должен бы, на "go prime(10000)" не означает, что функция написанная с return удобоварима асинхронно. Это обычная дыра, которых в GoLang гора, оставленная во имя "простоты".

Не понял, на что должен жаловаться компилятор, и почему функция неудобоварима асинхронно?
лэт ми спик фром май харт
Отредактировано 14.12.2025 17:27 mrTwister . Предыдущая версия .
Re[7]: Можно ли избавиться от async|await?
От: SkyDance Земля  
Дата: 14.12.25 17:40
Оценка:
N>Какое нафиг отношение pattern matching имеет к асинхронности?

Прямое:
get_result() ->
  spawn(parall1),
  spawn(parall2),
  spawn(parall3),
  receive
    {parall1, Result} -> Result;
    {parall2, Result2} -> Result2;
    {parall3, Result3} -> Result3;
  end.


Запускаешь 3 функции в параллель, которая первой ответила — тот результат и возвращаем.

N>string message = (await CountRecordsAsync()) switch


Тут ничего асинхронного по сути нет. Как мне запустить много асинхронных функций, и "решать вопросы по мере поступления"? Да, там есть обертки, которые позволяют это делать врукопашную, но оно все очень сложно читается.
Re[10]: Можно ли избавиться от async|await?
От: SkyDance Земля  
Дата: 14.12.25 18:00
Оценка:
N>Если бы это было так то слово go было бы не нужно. Точно так же можно сказать, что в C# нет никаких async функций, все синхронны просто возвращают разное, и это будет правдой, но словоблудием.

Это как раз и будет реальность, данная нам в call stack'ах. Именно поэтому работать с асинхронщиной в изначально не предназначенных для concurrency языках столь неудобно.
Re[5]: Можно ли избавиться от async|await?
От: SkyDance Земля  
Дата: 14.12.25 18:03
Оценка: +1
N>Допустим у тебя есть функция prime/1(возвращает Ns простое число). Работает слишком долго и блокируют. В случае C# берем код как есть, ставим async, переименовываем в GetPrimeAsync. Если есть желание, но в современном мире multicore уже не обязательно, разбрасываем "await Task.Yield()".

И в чем смысл такого мероприятия? Просто "поставить async" не выйдет — нужно где-то "await". Иными словами, всю программу переписать.

N>В Эрланге надo полностью разбить на процессы.


Для такой простой мелочи разбивать ничего не надо, есть готовая функция в OTP. Но можно написать и вручную, причем это будет выглядеть очень просто, красиво и элегантно. Оригинальная функция ровно так же не будет меняться. Только в месте вызова вместо "call_fun" будет "spawn(fun call_fun)". Все, писанины куда меньше, чем в C#.
Re[8]: Можно ли избавиться от async|await?
От: novitk США  
Дата: 14.12.25 18:04
Оценка:
Здравствуйте, SkyDance, Вы писали:

N>>Какое нафиг отношение pattern matching имеет к асинхронности?


SD>Прямое:

SD>
SD>get_result() ->
SD>  spawn(parall1),
SD>  spawn(parall2),
SD>  spawn(parall3),
SD>  receive
SD>    {parall1, Result} -> Result;
SD>    {parall2, Result2} -> Result2;
SD>    {parall3, Result3} -> Result3;
SD>  end.
SD>


SD>Запускаешь 3 функции в параллель, которая первой ответила — тот результат и возвращаем.


public static async Task<T> GetResultAsync()
{
    var task1 = parall1();
    var task2 = parall2();
    var task3 = parall3();

    return Task.WhenAny(task1, task2, task3) switch
    {
        task1 => await task1;
        task2 => await task2;
        task2 => await task3;
    };       
};

PM в C# тут конечно не нужен:
    return await Task.WhenAny(task1, task2, task3);

, но я написал для тебя по эрланговски, длинно.
Re[6]: Можно ли избавиться от async|await?
От: novitk США  
Дата: 14.12.25 18:13
Оценка:
Здравствуйте, SkyDance, Вы писали:

N>>Допустим у тебя есть функция prime/1(возвращает Ns простое число). Работает слишком долго и блокируют. В случае C# берем код как есть, ставим async, переименовываем в GetPrimeAsync. Если есть желание, но в современном мире multicore уже не обязательно, разбрасываем "await Task.Yield()".


SD>Просто "поставить async" не выйдет — нужно где-то "await". Иными словами, всю программу переписать.

Конечно ожидается что точка вызова уже async. Собственно есть встроенная обертка Task.Run и переписывать не надо вообще. Но тут я не в курсе, что то подобное возможно есть и в Erlang.

N>>В Эрланге надo полностью разбить на процессы.

SD>Для такой простой мелочи разбивать ничего не надо, есть готовая функция в OTP.
Блин, ну это же пример.

SD>Но можно написать и вручную, причем это будет выглядеть очень просто, красиво и элегантно. Оригинальная функция ровно так же не будет меняться. Только в месте вызова вместо "call_fun" будет "spawn(fun call_fun)". Все, писанины куда меньше, чем в C#.

"красиво и элегантно" это религия, а к "писанины куда меньше" в соседний топик. Там пока у C# короче.
Re[11]: Можно ли избавиться от async|await?
От: novitk США  
Дата: 14.12.25 18:21
Оценка:
Здравствуйте, SkyDance, Вы писали:

N>>Если бы это было так то слово go было бы не нужно. Точно так же можно сказать, что в C# нет никаких async функций, все синхронны просто возвращают разное, и это будет правдой, но словоблудием.


SD>Это как раз и будет реальность, данная нам в call stack'ах. Именно поэтому работать с асинхронщиной в изначально не предназначенных для concurrency языках столь неудобно.


Мух отделяем от котлет и не создаем шум. Call stack не самоцель. Люди изобретают специализированные инструменты. Для async — Task Window, для graph compute — TensorBoard и т.д.
Отредактировано 14.12.2025 18:27 novitk . Предыдущая версия . Еще …
Отредактировано 14.12.2025 18:27 novitk . Предыдущая версия .
Re[11]: Можно ли избавиться от async|await?
От: novitk США  
Дата: 14.12.25 18:26
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Не понял, на что должен жаловаться компилятор, и почему функция неудобоварима асинхронно?


Результат не получить, если вызвана через go, то есть конструкция бессмысленная.
P.S. Не стоит писать кучу текста с кодом, я неплохо понимаю как работает Go.
Re[8]: Можно ли избавиться от async|await?
От: hi_octane Беларусь  
Дата: 14.12.25 18:27
Оценка:
SD>Запускаешь 3 функции в параллель, которая первой ответила — тот результат и возвращаем.

На C# для такой задачи ПМ только усложнять задачу. Вот полная консольная программа. Выведет: Finished in 100 ms.

static async Task<string> Para1(int delay)
{
    await Task.Delay(delay);
    return $"Finished in {delay} ms";
}

//в этой одной строке - 3 запустятся в параллель, результатом будет та, которая первой ответила
var t = await Task.WhenAny(Para1(2000), Para1(100), Para1(500));
Console.WriteLine(t.Result); //вместо t.Result можно использовать await t
Re[12]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 14.12.25 18:36
Оценка:
Здравствуйте, novitk, Вы писали:

N>Результат не получить, если вызвана через go, то есть конструкция бессмысленная.

N>P.S. Не стоит писать кучу текста с кодом, я неплохо понимаю как работает Go.

Может результат и не нужен, в C# же тоже никто await писать не заставляет. Если нужен результат, то зачем слово "go"? Если результат нужен когда-то потом, то исходную функцию не надо менять:
result := make(chan int)
go func(){result <- prime(10000)}()
// Куча кода
return <-result
лэт ми спик фром май харт
Re[7]: Можно ли избавиться от async|await?
От: SkyDance Земля  
Дата: 14.12.25 18:40
Оценка:
N>Конечно ожидается что точка вызова уже async. Собственно есть встроенная обертка Task.Run

Я знаю, что есть в C#, и знаю, как сложно дебажить все эти "встроенные обертки". Именно об этом я и пишу — нет стройности и легкости. А так-то, конечно, все языки более-менее эквивалентны по возможностям.

N>"красиво и элегантно" это религия, а к "писанины куда меньше" в соседний топик. Там пока у C# короче.


В "соседнем топике" я написал через "длинный вариант", чтобы было понятно, как именно оно работает. Причем call stack'и там будут очень понятные в случае с Erlang, и — ууух, поди разберись! — в случае с C#.

Что, конечно, не умаляет достоинств команды .NET и конкретно C#. Правильной дорогой идут, добавляя лучшее из других языков, и делая очень работоспособные высокоуровневые обертки. Именно эти обертки, от Task.Run до WhenAny, и есть ответ на вопрос из сабжа. Беда с ними лишь в том, что иногда это таки нужно дебажить...
Re[7]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 14.12.25 18:42
Оценка:
Здравствуйте, novitk, Вы писали:

N>Конечно ожидается что точка вызова уже async. Собственно есть встроенная обертка Task.Run и переписывать не надо вообще. Но тут я не в курсе, что то подобное возможно есть и в Erlang.


О да, есть Task.Run и ничего не надо переписывать. Ага, щаз! Потом продакшен внезапно перестает отвечать на любые запросы из-за thread pool depletion, так как скопилась очередь из Task.Run, которые выжрали все потоки из системного пула потоков и сервер встал колом
лэт ми спик фром май харт
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.