Re[27]: Можно ли избавиться от async|await?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 16.12.25 20:30
Оценка:
Здравствуйте, novitk, Вы писали:


S>>Эти зеленые потоки уже обсуждали множество раз. Там единственный плюс, что все выплняется в одном потоке, поэтому не нужна синхронизация.

N>зеленые потоки не выполняются в одном OS потоке и синхронизация нужна.

https://translated.turbopages.org/proxy_u/en-ru.ru.57470c0e-6941bee3-315f29ec-74722d776562/https/stackoverflow.com/questions/74639116/what-is-the-difference-between-green-$$url0$$

Виртуальные потоки — это упрощённая реализация потоков, предоставляемая JDK, а не операционной системой. Они представляют собой разновидность потоков пользовательского режима, которые успешно используются в других многопоточных языках (например, горутины в Go и процессы в Erlang). Потоки пользовательского режима даже назывались «зелёными потоками» в ранних версиях Java, когда потоки операционной системы ещё не были широко распространены. Однако все «зелёные» потоки Java использовали один поток ОС (планирование M:1) и в конечном счёте уступали в производительности платформенным потокам, реализованным как оболочки для потоков ОС (планирование 1:1). Виртуальные потоки используют планирование M:N, при котором большое количество (M) виртуальных потоков планируется к запуску на меньшем количестве (N) потоков ОС.


S>>То же можно сделать и на C# со своим шедулером с одним потоком.

N>Бесшовно нельзя. Именно поэтому есть в C# Thread.Sleep и Таsk.Sleep, a в Го и jvm одна. Именно поэтому надо руками добавлять Task.Yield в числодробилки, а на Gо и jvm нет.

Task.Delay. В асинхронном коде Thread.Sleep не используют. Task.Yield это что бы разбить на части. Кстати в задачах используются и CancellationToken , что бы прекратить задачу.

S>>

S>>В современных версиях Java, таких как Java 8 и выше, зелёные потоки не используются по умолчанию, и управление потоками передаётся операционной системе.

N>Что такое "по умолчанию"?

https://habr.com/ru/companies/oleg-bunin/articles/358520/

Потоки в Java

Про потоки в Java важно знать, что они — нормальные потоки операционной системы. Когда-то в первых JVM были реализованы так называемые green threads — зелёные потоки, когда на самом деле стек java-потока как-то жил своей жизнью, и один поток операционной системы выполнял то один java-поток, то другой. Это всё развивалось до тех пор, пока в операционных системах не появилась нормальная многопоточность. После этого все забыли «зелёные» потоки как страшный сон, потому что с нативными потоками код работает лучше.

и солнце б утром не вставало, когда бы не было меня
Re[28]: Можно ли избавиться от async|await?
От: novitk США  
Дата: 17.12.25 03:03
Оценка:
Здравствуйте, Serginio1, Вы писали:

N>>Бесшовно нельзя. Именно поэтому есть в C# Thread.Sleep и Таsk.Sleep, a в Го и jvm одна. Именно поэтому надо руками добавлять Task.Yield в числодробилки, а на Gо и jvm нет.

S> Task.Delay. В асинхронном коде Thread.Sleep не используют. Task.Yield это что бы разбить на части. Кстати в задачах используются и CancellationToken , что бы прекратить задачу.
Да, похоже у тебя очень сложный диагноз.
Re[23]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 17.12.25 06:20
Оценка:
Здравствуйте, Serginio1, Вы писали:


S>И чем это лучше


S>
S>val1 := Task.Run(func1)
S>val2 := Task.Run(func2)
S>await Task.WhwnAll(val1, val2);
S>println(val1.Result + val2.Result)
S>


Тем, что func1 и func2 обязаны быть async на всю глубину вызовов и не делать блокирующих io операций
лэт ми спик фром май харт
Re[23]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 17.12.25 06:23
Оценка:
Здравствуйте, novitk, Вы писали:

N>Будь они обычные, как в Project Loom, тебе бы RunTask, aka Task.Run, не понадобился. Там семантика результата функций поддерживается в обеих контекстах, а в GoLang только в синхронном.


И какие проблемы с RunTask, который хелпер на несколько строк кода? Это такая же великая проблема языка go, как и отсутствие функции max в стандартной библиотеке (в последних версиях go правда добавили)
лэт ми спик фром май харт
Re[7]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 17.12.25 06:24
Оценка:
Здравствуйте, SkyDance, Вы писали:


SD>Ага.

SD>Собственно, Erlang тем и отличается, что у них process не просто структура данных, а еще и всякие поля для scheduling'а, и структура эта определена в виртуальной машине, а не просто как часть user-space library.

В go тоже, но сути это не меняет
лэт ми спик фром май харт
Re[21]: Можно ли избавиться от async|await?
От: mrTwister Россия  
Дата: 17.12.25 06:30
Оценка: +1
Здравствуйте, ·, Вы писали:

T>>Делается тривиальный хелпер на три строчки и код будет выглядеть точно так же

·>Ну т.е. создать новую функцию и передать всё через одно место (chan). И ещё каким-то хитровывернутым синтаксисом...

А в чем проблема создать повторно используемую функцию на 3 строчки кода? Пошли придирки ради придирок.
Какая тебе разница, что внутри chan, и чем он плох по-твоему? Ну замени chan на condition, сути это не поменяет, просто работать будет медленнее (chan в go очень сильно оптимизированы на уровне рантайма, например если какая-то функция читает канал, то писатель в канал запишет значение сразу в стек читателя, исключая тем самым лишнее копирование данных). Синтаксис стандартный в go.
лэт ми спик фром май харт
Re[3]: Можно ли избавиться от async|await?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 17.12.25 07:48
Оценка: +1
Здравствуйте, Shmj, Вы писали:

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


S>>>Получается если не нужно ждать результата функции — пишем наоборот — nowait. Если ждать результат — ничего не пишем, по умолчанию.

G>>Так работает Go

S>Проверял или просто веришь?

Не проверял, но по косвенным признакам это так. Подробности ниже.


S>Вот C#


S>
S>async Task<int> SumAsync(int a, int b) {
S>    return a + b;
S>}

S>var x = await SumAsync(2, 3);
S>


Если что в этом коде func гарантированно выполнится в том же потоке, вернется промис aka Task, и await в вызывающем коде сразу же получит ризультат. Никакого асинхронного выполнения не будет.

S>Эквивалент в Go


S>
S>func sumAsync(a, b int) <-chan int {
S>    ch := make(chan int, 1)

S>    go func() {
S>        ch <- a + b
S>        close(ch)
S>    }()

S>    return ch
S>}

S>x := <-sumAsync(2, 3)
S>


В этом коде ты явно создаешь новый поток, в котором выполняется функция сложения, которая в канал пересылает результат. Что дает асинхронное выполнение функции, но потом ты в вызывающем коде синхронно ожидаешь реультата асинхронной функции.

Эквивалент на C# будет гораздо сложнее, там и Task.Run, и System.Threading.Channels.

Эквивалент в Go твоего примера на C# будет такой:

func sum(a, b int) int {
    return a+b;
}

x:=sum(2,3)


Функция также выполнится синхронно, также вызывающий код получит результат.


Самое интересное происходит когда внутри функции у тебя есть IO или другая операция, которая может выполниться в неблокирующем режиме
func read() ? {
   data, err := os.ReadFile("image.png")
   ...
}

x:=read()


На c# эквивалент будет такой
async Task<?> read() {
   var data = await System.IO.File.ReadAllBytesAsync("image.png")
   ...
}

x = await read();



Почему работает ровно то, что ты хотел получить — когда нужно ждать результата, то не пишем ничего. А если нужно не ждать, то вызываем функцию через оператор go.

Вызываются ли IO функции асинхронно я не проверял.
Но если запустить 1000 горутин и во всех них вызвать IO функции, то они будут выполняться параллельно, хотя потоков будет гораздо меньше. Это поведение я неоднократно наблюдал.
Re[4]: Можно ли избавиться от async|await?
От: Shmj Ниоткуда  
Дата: 17.12.25 11:18
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Эквивалент в Go твоего примера на C# будет такой:


func sum(a, b int) int {
    return a+b;
}

x:=sum(2,3)


Не будет и близко. В C# я могу получить Task (в JS — Promise, в Dart — Future и т.д). Это позволяет мне писать легко и просто вот такое:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    private static int _globalCounter = 0;

    static async Task Main()
    {
        const int n = 10;
        var tasks = new List<Task<int>>(n);

        for (int i = 0; i < n; i++)
        {
            tasks.Add(Task.Run(async () =>
            {
                await Task.Delay(1000);

                int current = Interlocked.Increment(ref _globalCounter);

                if (current % 2 == 0)
                    throw new InvalidOperationException($"Ошибка: счетчик={current}, нельзя вернуть чётное значение.");

                return current;
            }));
        }

        // Ждём все задачи и "гасим" исключение на уровне await через continuation
        await Task.WhenAll(tasks).ContinueWith(t =>
        {
            // можно оставить пусто
            // если нужно — тут можно залогировать:
            // if (t.Exception != null) Console.WriteLine(t.Exception);

        }, TaskContinuationOptions.ExecuteSynchronously);

        var successful = tasks
            .Where(t => t.Status == TaskStatus.RanToCompletion)
            .Select(t => t.Result)
            .ToList();

        var errors = tasks
            .Where(t => t.IsFaulted)
            .SelectMany(t => t.Exception!.Flatten().InnerExceptions)
            .Select(ex => ex.Message)
            .ToList();

        Console.WriteLine("Успешные результаты: " + (successful.Count == 0 ? "(нет)" : string.Join(", ", successful)));
        Console.WriteLine("Сумма успешных результатов: " + successful.Sum());

        Console.WriteLine($"Успешно: {successful.Count}, с ошибкой: {errors.Count}");

        Console.WriteLine("Тексты ошибок:");
        if (errors.Count == 0)
        {
            Console.WriteLine("(нет)");
        }
        else
        {
            foreach (var e in errors)
                Console.WriteLine(" - " + e);
        }

        Console.WriteLine("Финальный глобальный счетчик: " + _globalCounter);
    }
}


Тут: https://dotnetfiddle.net/e49LaQ

А ты сможешь так на Go

Ну-ну. Сдюжь.
=сначала спроси у GPT=
Отредактировано 17.12.2025 11:21 Shmj . Предыдущая версия .
Re[24]: Можно ли избавиться от async|await?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 17.12.25 12:19
Оценка:
Здравствуйте, mrTwister, Вы писали:

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



S>>И чем это лучше


S>>
S>>val1 := Task.Run(func1)
S>>val2 := Task.Run(func2)
S>>await Task.WhwnAll(val1, val2);
S>>println(val1.Result + val2.Result)
S>>


T>Тем, что func1 и func2 обязаны быть async на всю глубину вызовов и не делать блокирующих io операций

В его примере func1 и func2 это обычные методы. И я привел

Что касается asнnc методов то на C# используются асинхронные функции. Зачем использовать синхронные в асинхронном методе?
и солнце б утром не вставало, когда бы не было меня
Re[8]: Можно ли избавиться от async|await?
От: SkyDance Земля  
Дата: 17.12.25 18:03
Оценка:
T>В go тоже, но сути это не меняет

Так горутины с самого начала были прямой копией "процессов". Разница заключалась только в подходе к GC, в случае с Erlang одним из требований было как раз полное отсутствие stop-the-world фазы у сборщика. Поэтому GC в эрланге осуществляется для каждого процесса отдельно (как если бы каждая горутина имела свою heap, а не только стек). Что потянуло за собой shared-nothing модель (разумеется, с оговорками, — например, binaries размером больше 64 (или как-то так, я уже точно не помню) уже являются ref-counted), ну а дальше оказалось, что immutable variables даже более элегантно смотрятся в языке.
Re[25]: Можно ли избавиться от async|await?
От: · Великобритания  
Дата: 17.12.25 23:17
Оценка:
Здравствуйте, Serginio1, Вы писали:

T>>Тем, что func1 и func2 обязаны быть async на всю глубину вызовов и не делать блокирующих io операций

S>В его примере func1 и func2 это обычные методы. И я привел

S>Что касается asнnc методов то на C# используются асинхронные функции. Зачем использовать синхронные в асинхронном методе?


Перечитай что тут писали. Твой ответ просто невпопад.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[26]: Можно ли избавиться от async|await?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.12.25 07:39
Оценка:
Здравствуйте, ·, Вы писали:

T>>>Тем, что func1 и func2 обязаны быть async на всю глубину вызовов и не делать блокирующих io операций

S>>В его примере func1 и func2 это обычные методы. И я привел

S>>Что касается asнnc методов то на C# используются асинхронные функции. Зачем использовать синхронные в асинхронном методе?


·>Перечитай что тут писали. Твой ответ просто невпопад.


Читал. Основное "преимущество" типа заключается в том, что не нужно блокировать общие ресурсы ибо зеленый поток реально работает в одном нативном потоке.
Ну и единственно, что явовский компилятор может их синхронного IO сделать его асинхронным.
Но суть в том, что при использовании пула нативных потоков производительность системы даже с блокировками значительно выше зеленых потоков.
Поэтому Java и отказывается от зеленых потоков в пользу нативных.
и солнце б утром не вставало, когда бы не было меня
Отредактировано 18.12.2025 7:42 Serginio1 . Предыдущая версия .
Re[27]: Можно ли избавиться от async|await?
От: · Великобритания  
Дата: 18.12.25 08:07
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Поэтому Java и отказывается от зеленых потоков в пользу нативных.

Перечитай ещё раз. В java нет зелёных потоков четверть века.
Речь шла о виртуальных потоках и project loom.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[28]: Можно ли избавиться от async|await?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.12.25 08:36
Оценка:
Здравствуйте, ·, Вы писали:



S>>Поэтому Java и отказывается от зеленых потоков в пользу нативных.

·>Перечитай ещё раз. В java нет зелёных потоков четверть века.
·>Речь шла о виртуальных потоках и project loom.

Угу яве то чуть больше четверть века.

Виртуальные потоки в Java: эволюция, практика, подводные камни

Плюсы
Простое API: go f() — и готово.

Масштабируемость по умолчанию.

Автоматическая работа с блокировками I/O.

Минусы
Нет контроля над временем жизни — нет structured concurrency.

Потенциальные утечки: забыли завершить — висят.

Возможны блокировки, если не соблюдать правила, например, mutex.


Итд. Там расписаны и плюсы и минусы. Нет серебряной пули.
и солнце б утром не вставало, когда бы не было меня
Re[29]: Можно ли избавиться от async|await?
От: · Великобритания  
Дата: 18.12.25 10:35
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>·>Речь шла о виртуальных потоках и project loom.

S> Угу яве то чуть больше четверть века.
Очередной ответ невпопад.

S>Виртуальные потоки в Java: эволюция, практика, подводные камни

S>

S>go f() — и готово.

Очередная демонстрация неспособности читать. Эта цитата о GoLang.

S>Итд. Там расписаны и плюсы и минусы. Нет серебряной пули.

Что у тебя за диагноз?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[30]: Можно ли избавиться от async|await?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.12.25 11:21
Оценка:
Здравствуйте, ·, Вы писали:

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


S>>·>Речь шла о виртуальных потоках и project loom.

S>> Угу яве то чуть больше четверть века.
·>Очередной ответ невпопад.

S>>Виртуальные потоки в Java: эволюция, практика, подводные камни

S>>

S>>go f() — и готово.

·>Очередная демонстрация неспособности читать. Эта цитата о GoLang.

Согласен

import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        println("Привет из корутины!")
    }
    println("Привет из main")
    delay(1000L)
}


Плюсы
Очень экономичны по ресурсам.

Structured concurrency, runBlocking, coroutineScope.

Совместимы с существующим синхронным кодом.

Минусы
Сложная внутренняя реализация — CPS, state‑machine.

Нужно уметь работать с context«ами, scope, Job, Dispatcher.

Возможны утечки при неправильном использовании.



Что обещали и что получилось
Ожидания: миллионы легких потоков, «магическое» устранение простоев на I/O, совместимость со старым кодом, простота reasoning, минимум усилий со стороны разработчика.

Реальность в целом подтвердилась — если не задевать проблемные места. Там, где нет synchronized, нет повсюду ThreadLocal и не нужно дебажить потоки, все работает, как задумано. Но в продакшене быстро проявились нюансы.

и солнце б утром не вставало, когда бы не было меня
Отредактировано 18.12.2025 11:24 Serginio1 . Предыдущая версия .
Re: Можно ли избавиться от async|await?
От: Skorodum Россия  
Дата: 18.12.25 11:52
Оценка:
Здравствуйте, Shmj, Вы писали:

Новость в тему из мира С++/Qt Qt TaskTree
Картинка довольно наглядно демонстрирует:
qt tasktree qt c++
Re[31]: Можно ли избавиться от async|await?
От: · Великобритания  
Дата: 18.12.25 12:07
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>·>Очередная демонстрация неспособности читать. Эта цитата о GoLang.

S> Согласен
Опять демонстрируешь неспособность читать. Утомил. Выделяю жирным:
S>import kotlinx.coroutines.*

S>

S>Что обещали и что получилось

Т.е. смысл статьи ты вообще не понял.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[32]: Можно ли избавиться от async|await?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.12.25 12:35
Оценка:
Здравствуйте, ·, Вы писали:

S>>·>Очередная демонстрация неспособности читать. Эта цитата о GoLang.

S>> Согласен
·>Опять демонстрируешь неспособность читать. Утомил. Выделяю жирным:
S>>import kotlinx.coroutines.*

S>>

S>>Что обещали и что получилось

·>Т.е. смысл статьи ты вообще не понял.

Смысл я давно понял и единственный плюс виртуальных поток это сделать из синхронного кода асинхронный.

Выводы по Java 21
Работает «из коробки». Виртуальные потоки действительно легкие: можно запускать десятки тысяч.

Совместимость со старым кодом — в целом «да».

Узкое место — synchronized. Множество библиотек, заточенных под старую модель, оказались не готовы.

Дебажить сложно. Проблема проявляется под нагрузкой, а еще когда инструменты для анализа не совсем готовы.

и солнце б утром не вставало, когда бы не было меня
Отредактировано 18.12.2025 13:51 Serginio1 . Предыдущая версия .
Re[33]: Можно ли избавиться от async|await?
От: · Великобритания  
Дата: 18.12.25 15:33
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Смысл я давно понял и единственный плюс виртуальных поток это сделать из синхронного кода асинхронный.

Ты совершенно неверно понял.

S>

S>Выводы по Java 21

Опять неспособность читать. Там ещё следующая глава в статье. Хинт: текущая версия это Java 25.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.