Re[6]: [Этюд] - синхронный vs асинхронный
От: Shmj Ниоткуда  
Дата: 30.09.21 10:31
Оценка:
Здравствуйте, paradok, Вы писали:

S>>Там и так все понятно, разница на порядки. Ну могу дописать ожидание завершения всех задач, но это ничего не изменит.

P>да, сделай ! там еще можно будет посмотреть зависимость от задержки, при 10 сек вообще кранты наступают системе.

Добавил в стартовом сообщении.
Re: [Этюд] - синхронный vs асинхронный
От: Teolog  
Дата: 30.09.21 10:50
Оценка:
S>Вопрос: как сделать, чтобы асинхронный метод отрабатывал так же быстро?
Подозреваю что суть проблемы в присутсвие синхронного ожидания Thread.Sleep(1000) после await.
Если я правильно понял ситуацию, то после await Task.Delay(1); оно уже выполняеться не на свеже-запущенном longRunning потоке
а на первом попавшемся из пула. Запущенный уже к этому моменту благополучно помер.
Соотвественно код выполняеться за время 1 *1000 / (размер пулла потоков)
Решение — обернуть синхронное ожидание в await Task.Factory.StartNew(longRunning), а из первоначального запуска задач этот параметр убрать.
Тогда, все что можно сделать на пуле-будет сделано на пуле, остальное на 1000 фоновых потоков.
Лучше оно от этого, по-сравнению с синхронным вариантом работать не будет, но будет хотя-бы так же криво. а не сильно хуже.
Ну еще можно побаловться с контекстом синхронизации, что замаскирет проблему и код станет таким же кривым и бажным как UI Windows
Чтобы работало нормально- надо лезть в библиотеку и переделывать ту синхронную функцию которую у вас символизирует Thread.Sleep(1000)
Re[7]: [Этюд] - синхронный vs асинхронный
От: Ночной Смотрящий Россия  
Дата: 30.09.21 11:00
Оценка: :)
Здравствуйте, Shmj, Вы писали:

S>Добавил в стартовом сообщении.


Вынудил запустить. Переписал чтобы копипастой не заниматьсся:
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace SyncAsync
{
    static class Program
    {
        static async Task AsyncMethod(int i)
        {
            await Task.Delay(1); // Много разных асинхронных вызовов...
            await Task.Delay(1);

            // Это убрать нельзя - эмуляция вызова асинхронного метода, который мы изменить не можем.
            Thread.Sleep(1000);

            Console.WriteLine(i);
        }

        static void SyncMethod(int i)
        {
            Task.Delay(1).Wait(); // Много разных асинхронных вызовов обессинхрониваем - не комильфо...
            Task.Delay(1).Wait();

            // Это убрать нельзя - эмуляция вызова асинхронного метода, который мы изменить не можем.
            Thread.Sleep(1000);

            Console.WriteLine(i);
        }


        private static async Task RunAsync(string name, Func<int, Task> action)
        {
            var sw = new Stopwatch();

            Console.WriteLine($"Start {name}");

            sw.Start();

            var tasks = Enumerable
                .Range(0, 1000)
                .Select(AsyncMethod);

            await Task.WhenAll(tasks);

            sw.Stop();

            Console.WriteLine($"Done. ElapsedMilliseconds={sw.ElapsedMilliseconds}");
        }

        static async Task Main()
        {
            await RunAsync("Sync", i => Task.Factory.StartNew(() => SyncMethod(i), TaskCreationOptions.LongRunning));
            await RunAsync("Async", async i => await AsyncMethod(i));
        }
    }
}

Первый варинт 38 сек, второй — 22 секунды. Что вполне логично, учитывая что размер пула воркер-потоков все таки поменьше 1000 единиц, в отличие от твоей 1 секунды на все потоки, каждый из которых блокируется на секунду.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[2]: [Этюд] - синхронный vs асинхронный
От: Shmj Ниоткуда  
Дата: 30.09.21 11:02
Оценка:
Здравствуйте, Teolog, Вы писали:

T>Ну еще можно побаловться с контекстом синхронизации, что замаскирет проблему и код станет таким же кривым и бажным как UI Windows


Вот это интересно посмотреть...

T>Чтобы работало нормально- надо лезть в библиотеку и переделывать ту синхронную функцию которую у вас символизирует Thread.Sleep(1000)


Вы что весь мир будете переделывать под async? Знаете сколько библиотек, которые игнорят Task'и?
Re[8]: [Этюд] - синхронный vs асинхронный
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 30.09.21 11:09
Оценка: +1
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Здравствуйте, Shmj, Вы писали:


S>>Добавил в стартовом сообщении.


НС>Вынудил запустить. Переписал чтобы копипастой не заниматьсся:

НС>



НС>        private static async Task RunAsync(string name, Func<int, Task> action)
НС>        {
НС>            var sw = new Stopwatch();

НС>            Console.WriteLine($"Start {name}");

НС>            sw.Start();

НС>            var tasks = Enumerable
НС>                .Range(0, 1000)
НС>                .Select(AsyncMethod);

НС>            await Task.WhenAll(tasks);

НС>            sw.Stop();

НС>            Console.WriteLine($"Done. ElapsedMilliseconds={sw.ElapsedMilliseconds}");
НС>        }


НС>

А где action применяется?
и солнце б утром не вставало, когда бы не было меня
Re[8]: [Этюд] - синхронный vs асинхронный
От: Shmj Ниоткуда  
Дата: 30.09.21 11:10
Оценка: :)
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Первый варинт 38 сек, второй — 22 секунды. Что вполне логично, учитывая что размер пула воркер-потоков все таки поменьше 1000 единиц, в отличие от твоей 1 секунды на все потоки, каждый из которых блокируется на секунду.


Вы что решарпер не используете? У вас же описка — передаете action но забываете его задействовать.

Рекомендую пользоваться профессиональными инструментами, чтобы не совершать таких ошибок.
Re[3]: [Этюд] - синхронный vs асинхронный
От: Teolog  
Дата: 30.09.21 11:12
Оценка:
S>Вы что весь мир будете переделывать под async? Знаете сколько библиотек, которые игнорят Task'и?
Кто, я? Да чур меня, делать мне больше нечего.
Суть async/await в использовании кооперативной многозадачности для уменьшения количества ждущих потоков.
Проблема та-же что и во времена windows 3.11 — при плохом поведении любого кода в дальнем углу, встает колом всё.
В общем виде, проблема не решаеться никак,но в пределах своего кода и надежных библиотек требуемый результат достижим.
Поэтому этот самый async постепенно расползаеться везде где возможно ожидание данных.
S>Знаете сколько библиотек, которые игнорят Task'и?
Вероятно много, однако любая библиотека без async работающая со вводом-выводом и периферийными устройствами строем идет нафиг, сразу как находится замена.
Re[5]: [Этюд] - синхронный vs асинхронный
От: alexander_r  
Дата: 30.09.21 11:21
Оценка: 20 (1)
Здравствуйте, Shmj, Вы писали:

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


S>>>...Синхронная версия отрабатывает 1-2 сек., асинхронная 1-2 мин.

_>>а как вы время замеряете, покажите весь код??

S>Там и так все понятно, разница на порядки. Ну могу дописать ожидание завершения всех задач, но это ничего не изменит.


не знаю откуда у вас там разица на порядок
у меня ваш синхронный метод и тот что переделал Serginio1 выполняется за одинаковое время ~7.5сек
        static void SyncMethod(int i)
        {
            Task.Delay(1).Wait(); // Много разных асинхронных вызовов обессинхрониваем - не комильфо...
            Task.Delay(1).Wait();

            // Это убрать нельзя - эмуляция вызова асинхронного метода, который мы изменить не можем.
            Thread.Sleep(1000);

            Console.WriteLine(i);
        }
        static async Task AsyncMethod(int i)
        {
            await Task.Delay(1); // Много разных асинхронных вызовов...
            await Task.Delay(1);

            // Это убрать нельзя - эмуляция вызова асинхронного метода, который мы изменить не можем.
            //Thread.Sleep(1000);
            await Task.Factory.StartNew(() =>
            {
                Thread.Sleep(1000);
            }, TaskCreationOptions.LongRunning);

            Console.WriteLine(i);
        }


        static async Task Main(string[] args)
        {
            var sw = new Stopwatch();

            Console.WriteLine("Start");

            sw.Start();

            //var tasks = Enumerable
            //    .Range(0, 1000)
            //    .Select(i => Task.Factory.StartNew(() => { SyncMethod(i); }, TaskCreationOptions.LongRunning));

            var tasks = Enumerable
                .Range(0, 1000)
                .Select(i => AsyncMethod(i));

            await Task.WhenAll(tasks);

            sw.Stop();

            Console.WriteLine("Done!");
            Console.WriteLine($"ElapsedMilliseconds={sw.ElapsedMilliseconds}");

            Console.ReadKey();
        }


если добавить ConfigureAwait(false) то 7.1 сек
Re[6]: [Этюд] - синхронный vs асинхронный
От: Shmj Ниоткуда  
Дата: 30.09.21 11:27
Оценка:
Здравствуйте, alexander_r, Вы писали:

_>не знаю откуда у вас там разица на порядок

_>у меня ваш синхронный метод и тот что переделал Serginio1 выполняется за одинаковое время ~7.5сек

Serginio1 предлагает добавлять обертку для каждого вызова синхронного метода, который мы можем подозревать в длительном исполнении — а это уродство.
Re[7]: [Этюд] - синхронный vs асинхронный
От: alexander_r  
Дата: 30.09.21 11:41
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Serginio1 предлагает добавлять обертку для каждого вызова синхронного метода, который мы можем подозревать в длительном исполнении — а это уродство.


т.е проблемы с производительностью нет, проблема в уродстве??
Re[8]: [Этюд] - синхронный vs асинхронный
От: Shmj Ниоткуда  
Дата: 30.09.21 12:03
Оценка: :)
Здравствуйте, alexander_r, Вы писали:

_>т.е проблемы с производительностью нет, проблема в уродстве??


Выбор из двух: или тормоза или уродство.

В синхронном варианте уродства даже меньше.

Однако же есть способ, как минимум 1, как избежать уродства. Пока жду, может кто-то еще что-то лучшее предложит.
Отредактировано 30.09.2021 12:03 Shmj . Предыдущая версия .
Re[9]: [Этюд] - синхронный vs асинхронный
От: alexander_r  
Дата: 30.09.21 12:21
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Выбор из двух: или тормоза или уродство.


не знаю почему уродство, вполне рабочее решение
Re: [Этюд] - синхронный vs асинхронный
От: Danchik Украина  
Дата: 30.09.21 14:22
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Что-то давно этюдов не было. Не знаю тянет ли это на этюд, но попробую.


[Skip]

Скажите, почему эмуляция Асинхронного вызова делается через Thread.Sleep()?
Или поправьте на
await Task.Delay(1000)

или поправьте коментарий что, вы делаете эмуляцию Синхронного вызова.
Re[2]: [Этюд] - синхронный vs асинхронный
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 30.09.21 14:25
Оценка: +1
Здравствуйте, Danchik, Вы писали:

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

Он к тому что есть библиотеки где есть использование потоков и ожидание выполнения другого потока итд.
А использовать он хочет его в асинхронном коде. И говорит, что есть простое решение.
А завертывание долгого синхронного кода

 await Task.Factory.StartNew(() =>
            {
                Thread.Sleep(1000);
            }, TaskCreationOptions.LongRunning);


Не красиво
и солнце б утром не вставало, когда бы не было меня
Re[3]: [Этюд] - синхронный vs асинхронный
От: Shmj Ниоткуда  
Дата: 30.09.21 15:01
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>А использовать он хочет его в асинхронном коде. И говорит, что есть простое решение.

S>А завертывание долгого синхронного кода

S>
S> await Task.Factory.StartNew(() =>
S>            {
S>                Thread.Sleep(1000);
S>            }, TaskCreationOptions.LongRunning);
S>


S>Не красиво


Ага. Представьте 5 вызовов в методе (чередуются с синхронным) и 5 ваших гармошек с Task.Factory.StartNew...

На каждый вызов вы создаете по отдельному потому. А в синхронной версии всего 1 поток на метод. Тут не просто не красиво — тут еще и не оптимально.
Отредактировано 30.09.2021 15:02 Shmj . Предыдущая версия .
Re[4]: [Этюд] - синхронный vs асинхронный
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 30.09.21 15:07
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Ага. Представьте 5 вызовов в методе (чередуются с синхронным) и 5 ваших гармошек с Task.Factory.StartNew...


S>На каждый вызов вы создаете по отдельному потому. А в синхронной версии всего 1 поток на метод. Тут не просто не красиво — тут еще и не оптимально.


Еще раз разработчик библиотеки не должен смешивать работу с задачами и потоками! Это разные парадигмы и есть асинхронные аналоги.
Если жевсе же ты решишл использовать, то ССЗС и тогда нужно профилировать код.
Ибо есть короткий и долгий код. Вот для долгого то кода и нужен отдельныая задача с LongRunning, что бы не останавливал поток из пула.
А все остальные используй как синхронный.
Мне интересно какое решение у тебя без использования профайлера
и солнце б утром не вставало, когда бы не было меня
Re[5]: [Этюд] - синхронный vs асинхронный
От: Shmj Ниоткуда  
Дата: 30.09.21 15:10
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Мне интересно какое решение у тебя без использования профайлера


Подождем еще — может кто-то решит этюд.
Re: [Этюд] - синхронный vs асинхронный
От: pilgrim_ Россия  
Дата: 30.09.21 16:27
Оценка: 3 (1)
Здравствуйте, Shmj, Вы писали:

S>Сразу код: синхронный вариант и асинхронный вариант метода (SyncMethod и AsyncMethod):


S>Итак, если запустить код — то увидим, что синхронный вариант отработает за 1-2 секунды а асинхронный — около 1 минуты (примерно, не ждал до конца). Но есть минус — в синхронном варианте внутри мы вызываем внешние асинхронные методы и каждый раз вынуждены их обессинхронивать — что не гуд.


S>Вопрос: как сделать, чтобы асинхронный метод отрабатывал так же быстро?


Установить мин. кол-во потоков в пуле в 1000 (ThreadPool.SetMinThreads). Это не бесплатно ессн, но если очень надо .
Связанно в политикой создания новых потоков в пуле, по умолчанию насколько я помню когда кол-во потоков в пуле превышает некоторое значение (где-то кол-во ядер * на некоторую константу), то добавление нового потока в пул происходит с некоторой задержкой (если память не изменяет чуть ли не секунду), и возможно эта задержка даже динамически увеличивается в зависимости от текущего размера пула.

ps: так было в большом .NET, насчёт Core хз.
Re[2]: [Этюд] - синхронный vs асинхронный
От: Shmj Ниоткуда  
Дата: 30.09.21 16:36
Оценка: :)
Здравствуйте, pilgrim_, Вы писали:

_>Установить мин. кол-во потоков в пуле в 1000 (ThreadPool.SetMinThreads). Это не бесплатно ессн, но если очень надо .


Эх, жаль что вы мой козырь раскрыли. Думал может кто-то что-то нормальное предложит, но похоже другого варианта просто нет
Re[3]: [Этюд] - синхронный vs асинхронный
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 01.10.21 08:45
Оценка:
Здравствуйте, Shmj, Вы писали:

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


_>>Установить мин. кол-во потоков в пуле в 1000 (ThreadPool.SetMinThreads). Это не бесплатно ессн, но если очень надо .


S>Эх, жаль что вы мой козырь раскрыли. Думал может кто-то что-то нормальное предложит, но похоже другого варианта просто нет

Ну да. Пул из 1000 потоков это коронное решение?
По моему мое решение с профайлером намного оптимальнее!
и солнце б утром не вставало, когда бы не было меня
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.