powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Как делать кучу параллельных IO-Bound операций ?
25 сообщений из 57, страница 2 из 3
Как делать кучу параллельных IO-Bound операций ?
    #39689310
WaspNewCore
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Petro123,

Ну короче сейчас все сделано через T-SQL процедуру. Извлекаются данные курсором и потом идет длинный алгоритм со сложной логикой со считыванием данных из других таблиц и последущими расчетами. По каждому элементу отдельно. Получается обрабатывать около 20-30 элементов в секунду. Нужно существенно увеличить эту цифру. Т.к. нужно обрабатывать архивы данных.
Что я хочу сделать через перевод на C# и увеличение количества потоков, выполняющих данный алгоритм, что выльется в некую цепочку: CpuBound(мелкая обработка)+IOBound(долго)+CpuBound(мелкая обработка)+IOBound(долго)+IOBound(долго)+CpuBound(мелкая обработка).
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689319
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreИзвлекаются данные курсором и потом идет длинный алгоритм со сложной логикой со считыванием данных из других таблиц и последущими расчетами.
Курсоры в T-SQL = тормоза. Это было подтверждено уже не раз. И способ убыстрения таких алгоритмов, как ни странно - отказ от курсоров (и скалярных UDF). Все расчеты и извлечение данных помещаются в один запрос.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689322
WaspNewCore
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А тему я создал потому, что хотел понять есть ли стандартные способы от разработчиков C#. Странно стало, что PLinq и Parallel не умеют по async. Думал может чего упустил, но получается не упустил.

Ну, придется воспользоватся велосипедом ForEachAsyncConcurrent, только я думаю там имеет смысл добавить ThreadPool.SetMaxThreads если maxDegreeOfParallelism задан больше Environment.ProcessorCount, что не учтено в данном методе. Иначе толку от maxDegreeOfParallelism не будет - пул потоков тупо не запустит новые задачи.

Вот поэтому я и не хотел использовать велосипеды, уж разрабы C# точно не упустят важные вещи.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689323
WaspNewCore
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сон Веры ПавловныWaspNewCoreИзвлекаются данные курсором и потом идет длинный алгоритм со сложной логикой со считыванием данных из других таблиц и последущими расчетами.
Курсоры в T-SQL = тормоза. Это было подтверждено уже не раз. И способ убыстрения таких алгоритмов, как ни странно - отказ от курсоров (и скалярных UDF). Все расчеты и извлечение данных помещаются в один запрос.

Ну а как без алгоритмов то, в условиях когда есть алгоритмы вида if сделай то-то, else сделай длинную цепочку другого алгоритма.
Упихивать это в чистый SQL слишком сложно и запутанно - через всякий там merge и прочие.
Ну вот думаю проще перенести логику на C# хотя бы.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689333
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreНу а как без алгоритмов то, в условиях когда есть алгоритмы вида if сделай то-то, else сделай длинную цепочку другого алгоритма.
Упихивать это в чистый SQL слишком сложно и запутанно - через всякий там merge и прочие.
Вполне нормально. Декомпозиция решает. Сложные/громоздкие вычисления выносятся в инлайновые TVF, и используются в основном запросе посредством cross/outer apply. Поскольку функции инлайновые, то оптимизатором всё это будет собрано в один запрос с единым планом выполнения.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689334
Tosh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreСон Веры Павловныпропущено...

Курсоры в T-SQL = тормоза. Это было подтверждено уже не раз. И способ убыстрения таких алгоритмов, как ни странно - отказ от курсоров (и скалярных UDF). Все расчеты и извлечение данных помещаются в один запрос.

Ну а как без алгоритмов то, в условиях когда есть алгоритмы вида if сделай то-то, else сделай длинную цепочку другого алгоритма.
Упихивать это в чистый SQL слишком сложно и запутанно - через всякий там merge и прочие.
Ну вот думаю проще перенести логику на C# хотя бы.
Да запросто - от CASE в качестве полей выбора, до UNION нескольких наборов, удовлетворяющих разным условиям. Настоятельно рекомендую Вам об этом подумать ... ну или назовите приложение, над которым работаете, - чтобы нечаянно с ним не познакомиться
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689335
WaspNewCore
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
мне проще на C#. тут видимо вопрос опыта в конкретных тенологиях.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689340
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreмне проще на C#. тут видимо вопрос опыта в конкретных тенологиях.именно батенька.
Вопрос где размещать БЛ бизнес логику. Он флеймовый.
Можно в бд на его ЯП. Можно в АппСервере.
Ты выбрал второе т.к. больше знаешь шарп.
Логично).
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689341
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры ПавловныПоскольку функции инлайновые, то оптимизатором всё это будет собрано в один запрос с единым планом выполнения.в этом я не силен.
Я либо оптимизатор бд и его большая хранимка.
Либо ОРМ и тогда оптимизатор голова разработчика).
Конечно, при аналитике как бы и ОРМ уже не подходит.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689345
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreТ.к. нужно обрабатывать архивы данных.сделайте для архива денормализацию и olap\oltp.
Обычно архивы для ускорения как раз отдельно.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689349
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здесь есть еще один нюанс: когда данные собираются единым запросом, сервер сам обеспечивает консистентность этих данных (либо механизмом блокировок, либо механизмом IRCS). Если зависящие друг от друга данные собираются кучей атомарных запросов в параллельных потоках (и сессиях), есть достаточно неплохой шанс смоделировать ситуацию грязного чтения.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689350
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreчто выльется в некую цепочку:при увлечении цепочками будут потери при переключении контекста.
Со школы известно что 2 потока не быстрее в 2 раза одного.
А например, денормализация ускорит вам в 10 раз.
IMHO
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689357
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловныгрязного чтения.ну, у него архив вроде. Данные статичны.
Но конечно, один запрос без курсоров это идеал.
Это обычно в ветке БД пробуют написать.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689378
WaspNewCore
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Petro123WaspNewCoreчто выльется в некую цепочку:при увлечении цепочками будут потери при переключении контекста.
Со школы известно что 2 потока не быстрее в 2 раза одного.
А например, денормализация ускорит вам в 10 раз.
IMHO

Petro123Сон Веры Павловныгрязного чтения.ну, у него архив вроде. Данные статичны.
Но конечно, один запрос без курсоров это идеал.
Это обычно в ветке БД пробуют написать.

Написать такую сложную логику для меня будет сложновато. Тем более с OLTP и пр. Мне проще перенести на C#. Понятно, что параллельность не увеличит производительность прям ровно в нужное количество потоков, см. Закон Амдала . Но я думаю увеличение будет достаточно существенным. Раз этак в 1.87 с двух потоков и т.д. Со 100 потоков может выжмется ускорение раз в 70. Полагаю для моей текущей задачи такой производительности хватит за глаза. Если потом упрусь в потолок и его все равно будет не хватать (а это вряд ли произойдет в ближайшие годы) подключу спеца по SQL, чтобы он уже ворочал OLPT и пр. Но это слишком далекие планы.

Что касается грязного чтения.. хм. Вряд ли. Работа идет с уже готовыми статичными данными. Берется родительская запись и ее обрабатывает один поток. Который запрашивает подчиненные сущности и их обрабатывает, с последующей заливкой в другие таблицы. Пересечений и дедлоков в принципе не должно быть.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689379
WaspNewCore
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Или это не Закон Амдала утверждает, что накладные расходы при распараллеливании вычислений уменьшают общую производительность. Забыл, не важно в общем )
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689408
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCore Берется родительская запись и ее обрабатывает один поток. Который запрашивает подчиненные сущности и их обрабатывает, с последующей заливкой в другие таблицы. Пересечений и дедлоков в принципе не должно быть.
Ну тут прямо напрашивается select->insert. без всяких await/async
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689443
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreСо 100 потоков может выжмется ускорение раз в 70.сомневаюсь.
По правилом нужна демка ПРОТОТИП.
Ставьте sleep() вместо БЛ и уже завтра, в выходной отпишитсь во сколько раз
20 потоков SELECT record быстрее чем курсор в базе.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689446
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВWaspNewCore Берется родительская запись и ее обрабатывает один поток. Который запрашивает подчиненные сущности и их обрабатывает, с последующей заливкой в другие таблицы. Пересечений и дедлоков в принципе не должно быть.
Ну тут прямо напрашивается select->insert. без всяких await/asyncон хочет 100 select по одной записи одновременно в базу.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689743
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreСтранно стало, что PLinq и Parallel не умеют по async.
Видимо, научить непросто. Представьте, к очереди элементов еще первоначально не опоточенных, добавится очередь готовых к
продолжению после await. Части (или всем) из этих последних нужно продолжить в первоначальном потоке. А еще бывают и такие асинхи , которые не умеют продолжать в чужом потоке (несмотря на ConfigureAwait(false)).
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39689855
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LR
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
/// <summary>
    /// Concurrently Executes async actions for each item of <see cref="IEnumerable<typeparamref name="T"/>
    /// </summary>
    /// <typeparam name="T">Type of IEnumerable</typeparam>
    /// <param name="enumerable">instance of <see cref="IEnumerable<typeparamref name="T"/>"/></param>
    /// <param name="action">an async <see cref="Action" /> to execute</param>
    /// <param name="maxDegreeOfParallelism">Optional, An integer that represents the maximum degree of parallelism,
    /// Must be grater than 0</param>
    /// <returns>A Task representing an async operation</returns>
    /// <exception cref="ArgumentOutOfRangeException">If the maxActionsToRunInParallel is less than 1</exception>
    public static async Task ForEachAsyncConcurrent<T>(
        this IEnumerable<T> enumerable,
        Func<T, Task> action,
        int? maxDegreeOfParallelism = null)
    {
        if (maxDegreeOfParallelism.HasValue)
        {
            using (var semaphoreSlim = new SemaphoreSlim(
                maxDegreeOfParallelism.Value, maxDegreeOfParallelism.Value))
            {
                var tasksWithThrottler = new List<Task>();

                foreach (var item in enumerable)
                {
                    // Increment the number of currently running tasks and wait if they are more than limit.
                    await semaphoreSlim.WaitAsync();

                    tasksWithThrottler.Add(Task.Run(async () =>
                    {
                        await action(item);

                        // action is completed, so decrement the number of currently running tasks
                        semaphoreSlim.Release();
                    }));
                }

                // Wait for all tasks to complete.
                await Task.WhenAll(tasksWithThrottler.ToArray());
            }
        }
        else
        {
            await Task.WhenAll(enumerable.Select(item => action(item)));
        }
    }



Кстати, по поводу этой реализации, которая встречается множество раз (автор знатно постарался в распространении своего говнокода), должен сказать.

Не нужно использовать эту реализацию у себя, так как при достаточно большом количестве элементов тупо пожирает память и выход может быть более медленным, чем хотелось бы.

В общем, не нужно бездумно копировать всякую дичь со стеков :)
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39690314
WaspNewCore
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
hVosttНе нужно использовать эту реализацию у себя, так как при достаточно большом количестве элементов тупо пожирает память и выход может быть более медленным, чем хотелось бы.

А можете объяснить в чем проблемы ? Я не вижу критичных, метод выглядит вполне юзабельным. А значит я чего-то не понимаю в async/await. Нужно срочно это исправить, просвятите :)
И что значит "выход может быть более медленным" ? Какого порядка цифры ? Если речь о лишних микросекундах из-за ожиданий await semaphoreSlim.WaitAsync() то не вижу тут проблем, потери в десяток микросекунд я не считаю - такой сверхоптимизации мне не требуется.

У меня всего лишь пара мелких замечаний:
1. добавить ConfigureAwait(false) везде.
2.
Код: c#
1.
await Task.WhenAll(tasksWithThrottler.ToArray());


Начиная с 4.5 фреймворка уже не нужно преобразовывать в массив. WhenAll с тех пор принимает IEnumerable.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39690322
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCore,

Проблема здесь:

LR
Код: c#
1.
var tasksWithThrottler = new List<Task>();



Если через аргумент функции enumerable будет прокачано миллиард элементов, в памяти останутся миллиард экземпляров Task, да и эвейтить этот миллиард то ещё удовольствие.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39690329
WaspNewCore
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
hVostt,

Да, я думал на этот момент. Но это стандартная проблема с кодом вообще - не создать случайно List на триллиард записей.
Полагаю, что проблема как раз из-за необходимости передать в Task.WhenAll массив.

Можно немного оптимизировать
- заменить
Код: c#
1.
var tasksWithThrottler = new List<Task>(); 


на
Код: c#
1.
var tasksWithThrottler = new BlockingCollection<Task>(); 



- заменить
Код: c#
1.
await Task.WhenAll(tasksWithThrottler.ToArray());


на
Код: c#
1.
await Task.WhenAll(tasksWithThrottler.GetConsumingEnumerable ());



не смотрел код Task.WhenAll, но если там что-то типа
Код: c#
1.
2.
foreach (var element in enumerable)
  await element;



то должно работать гладко.


Но в принципе на не очень больших коллекциях ( ну чтобы не растить List до миллиардов) и так будет работать. В принципе конкретно в своем решении я разбиваю работы на пакеты по ~1000 элементов, так, что особых рисков не будет.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39690392
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreМожно немного оптимизировать

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

https://docs.microsoft.com/ru-ru/dotnet/standard/asynchronous-programming-patterns/consuming-the-task-based-asynchronous-pattern#throttling

:)

не думаю, что BlockingCollection в контексте отсутствия параллелизма, а это именно так на таск эвейте, хорошая идея, скорее очень плохая.
...
Рейтинг: 0 / 0
Как делать кучу параллельных IO-Bound операций ?
    #39690393
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WaspNewCoreНо в принципе на не очень больших коллекциях ( ну чтобы не растить List до миллиардов) и так будет работать. В принципе конкретно в своем решении я разбиваю работы на пакеты по ~1000 элементов, так, что особых рисков не будет.

Это заряженное ружьишко, которое может очень больно может садануть и прострелить ногу.
...
Рейтинг: 0 / 0
25 сообщений из 57, страница 2 из 3
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Как делать кучу параллельных IO-Bound операций ?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]