Task Parallel Library
От: Somescout  
Дата: 30.01.17 13:40
Оценка:
Начал изучать task'и и буквально сразу возник вопрос как ограничить их одновременное количество. Есть ли какой-нибудь штатный способ? Или хотя-бы рекомендуемый лучшими Net'оводами?

Перефразирую в виде задачи — есть большое количество элементов, над которыми надо выполнить параллельную работу, но если просто запустить её сразу для всех — кончается память. Хотелось бы скормить все элементы и просто дождаться завершения. В идеале с возможностью добавления новых элементов в очередь с ожиданием.

В принципе можно и самому написать, но если есть готовое протестированное решение — было бы приятно.

PS. Можно ли жёстко прервать задачу? (т.е. не через Cancellation token)
ARI ARI ARI... Arrivederci!
Отредактировано 30.01.2017 18:40 AndrewVK . Предыдущая версия .
async tpl
Re: Task Parallel Library
От: Sharov Россия  
Дата: 30.01.17 14:02
Оценка: +1
Здравствуйте, Somescout, Вы писали:

S>Начал изучать task'и и буквально сразу возник вопрос как ограничить их одновременное количество. Есть ли какой-нибудь штатный способ? Или хотя-бы рекомендуемый лучшими Net'оводами?


S>Перефразирую в виде задачи — есть большое количество элементов, над которыми надо выполнить параллельную работу, но если просто запустить её сразу для всех — кончается память. Хотелось бы скормить все элементы и просто дождаться завершения. В идеале с возможностью добавления новых элементов в очередь с ожиданием.


S>В принципе можно и самому написать, но если есть готовое протестированное решение — было бы приятно.


S>PS. Можно ли жёстко прервать задачу? (т.е. не через Cancellation token)


Можете задачи разбить на группы и скармливать их Parallel.For(each). Можете написать собственный планировщик для своих задач, который придерживал бы задачи в пиковую нагрузку на память.

А если совсем по существу, то вот:
http://stackoverflow.com/a/22011880/241446
http://stackoverflow.com/questions/11138927/best-way-to-limit-the-number-of-active-tasks-running-via-the-parallel-task-libra

Там ключевой параметр всюду MaxDegreeOfParallelism, его и пользуйте.
Кодом людям нужно помогать!
Re: Task Parallel Library
От: Sinix  
Дата: 30.01.17 14:14
Оценка:
Здравствуйте, Somescout, Вы писали:

S>Перефразирую в виде задачи — есть большое количество элементов, над которыми надо выполнить параллельную работу, но если просто запустить её сразу для всех — кончается память. Хотелось бы скормить все элементы и просто дождаться завершения. В идеале с возможностью добавления новых элементов в очередь с ожиданием.


Для раскидывания наргузки по нескольким ядрам проще всего использовать Parallel.ForEach. Если хочется то же самое на тасках — свой шедулер. Как пример.


S>PS. Можно ли жёстко прервать задачу? (т.е. не через Cancellation token)


Формально — можно, в CancellationToken есть метод Register(), который позволяет получить уведомление о прерывании операции, дальше прерываем, как удобно.

На практике бесполезно, т.к. в принципе оно ничем не отличается от расстрела произвольной области памяти — продолжать выполнение после прерывания потока в произвольной точке бессмысленно.

UPD, к ответу ув. Sharov:
и вот это тогда: http://stackoverflow.com/a/11100423
Отредактировано 30.01.2017 14:19 Sinix . Предыдущая версия .
Re: Task Parallel Library
От: Kolesiki  
Дата: 30.01.17 14:26
Оценка:
Здравствуйте, Somescout, Вы писали:

S>Начал изучать task'и и буквально сразу возник вопрос как ограничить их одновременное количество.


См. SemaphoreSlim
Re: Task Parallel Library
От: TK Лес кывт.рф
Дата: 31.01.17 04:01
Оценка:
Здравствуйте, Somescout, Вы писали:

S>Начал изучать task'и и буквально сразу возник вопрос как ограничить их одновременное количество. Есть ли какой-нибудь штатный способ? Или хотя-бы рекомендуемый лучшими Net'оводами?


S>Перефразирую в виде задачи — есть большое количество элементов, над которыми надо выполнить параллельную работу, но если просто запустить её сразу для всех — кончается память. Хотелось бы скормить все элементы и просто дождаться завершения. В идеале с возможностью добавления новых элементов в очередь с ожиданием.


Можно взять ActionBlock — ограничивается как количество одновременных воркеров так и размер входящей очереди.

S>В принципе можно и самому написать, но если есть готовое протестированное решение — было бы приятно.

S>PS. Можно ли жёстко прервать задачу? (т.е. не через Cancellation token)

Делайте микросервис. Шлете, ему CtrlBreak, а если не понимает то и TerminateProcess — есть масса готовых средств как для их разворачивания/управления/балансировки нагрузки.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re: Task Parallel Library
От: Vladek Россия Github
Дата: 31.01.17 09:45
Оценка:
Здравствуйте, Somescout, Вы писали:

S>Перефразирую в виде задачи — есть большое количество элементов, над которыми надо выполнить параллельную работу, но если просто запустить её сразу для всех — кончается память. Хотелось бы скормить все элементы и просто дождаться завершения. В идеале с возможностью добавления новых элементов в очередь с ожиданием.


Я что-то ваял подобное: http://rsdn.org/forum/dotnet/6436611.1
Автор: Vladek
Дата: 05.05.16


S>PS. Можно ли жёстко прервать задачу? (т.е. не через Cancellation token)


Это, мягко говоря, неправильно. Они и так будут жёстко прерываться на первых порах — из-за багов. Код, который в любой момент может прервать выполнение, по определению является нерабочим.
Re[2]: Task Parallel Library
От: kov_serg Россия  
Дата: 31.01.17 10:20
Оценка:
Здравствуйте, Sinix, Вы писали:

S>... продолжать выполнение после прерывания потока в произвольной точке бессмысленно.

WTF? откуда такое утверждение?
Re[3]: Task Parallel Library
От: Sinix  
Дата: 31.01.17 10:24
Оценка: 2 (1)
Здравствуйте, kov_serg, Вы писали:

S>>... продолжать выполнение после прерывания потока _в произвольной точке_ бессмысленно.

_>WTF? откуда такое утверждение?

Начнём с

When a thread calls Abort on itself, the effect is similar to throwing an exception; the ThreadAbortException happens immediately, and the result is predictable. However, if one thread calls Abort on another thread, the abort interrupts whatever code is running. There is also a chance that a static constructor could be aborted.

(c)

Миль пардон, документацию не обновили. По факту ThreadAbortException не прерывает выполнение static-конструктора

Чуть позже пример приведу.

UPD А собственно, чо эт я? Буквально полгода назад ловил, дарю:
  запускать без отладчика
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace LargeArrays
{
    class Program
    {
        private class ListProof
        {
            private static readonly List<int> _list = new List<int>();

            public static void RunListProof()
            {
                while (true)
                {
                    if (_list.Count > 0 && _list.Last() != 42)
                    {
                        Console.WriteLine("Bugged!!!");
                        break;
                    }

                    if (_list.Count > 100 * 1000)
                    {
                        _list.Clear();
                    }
                    _list.TrimExcess();

                    var h = new ManualResetEvent(false);
                    var t = new Thread(
                        () =>
                        {
                            int i;
                            for (i = 0; i < 10; i++)
                            {
                                _list.Add(42);
                            }
                            _list.TrimExcess();
                            h.Set();
                            try
                            {
                                for (; i < 10000; i++)
                                {
                                    _list.Add(42);
                                }
                            }
                            catch (ThreadAbortException)
                            {
                                Console.WriteLine("x" + i);
                            }
                        });
                    t.Start();
                    h.WaitOne();
                    Thread.Sleep(1);
                    t.Abort();
                    t.Join();
                }

                var lastItems = _list.AsEnumerable().Reverse().Take(10).Reverse();
                Console.WriteLine("Last items of list: " + string.Join(", ", lastItems));
            }
        }

        public static void Main(string[] args)
        {
            ListProof.RunListProof();

            Console.WriteLine("complete!");
        }
    }
}


x4945
x5454
x3086
x10
x10
x10
x10
x8809
x470
x5316
x10
x6259
x10
x6146
Bugged!!!
Last items of list: 42, 42, 42, 42, 42, 42, 42, 42, 42, 0
complete!
Для продолжения нажмите любую клавишу . . .


кто расскажет, откуда после вызова _list.Add(42) в списке взялся 0 — тому +1 к пониманию всей прелести проблемы.
Отредактировано 31.01.2017 11:18 Sinix . Предыдущая версия . Еще …
Отредактировано 31.01.2017 10:37 Sinix . Предыдущая версия .
Re[4]: Task Parallel Library
От: vorona  
Дата: 31.01.17 13:21
Оценка: 6 (1) +1
Здравствуйте, Sinix, Вы писали:

S>кто расскажет, откуда после вызова _list.Add(42) в списке взялся 0 — тому +1 к пониманию всей прелести проблемы.


размер списка увеличился значение еще не присвоилось
Re[4]: Task Parallel Library
От: kov_serg Россия  
Дата: 31.01.17 15:54
Оценка: :)
Здравствуйте, Sinix, Вы писали:

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


S>>>... продолжать выполнение после прерывания потока _в произвольной точке_ бессмысленно.

_>>WTF? откуда такое утверждение?

S>Начнём с

S>

S>When a thread calls Abort on itself, the effect is similar to throwing an exception; the ThreadAbortException happens immediately, and the result is predictable. However, if one thread calls Abort on another thread, the abort interrupts whatever code is running. There is also a chance that a static constructor could be aborted.

S>(c)
Abort не случается где попало
void abort_safe(Action a) { try {} finally { a(); } }
...
abort_safe(()=>{ ... });

Хотя MS умудрился изгатить реализацию так что abort использовать не безопасно почти всюду, при этом оставив его в runtime.
Компилятор генерирует abort не безопасный код даже для using, но это особенность MS C#.
Но это никак не соответствует утверждению "продолжать выполнение после прерывания потока в произвольной точке бессмысленно". Смыл в этом есть, а то что реализация в C# кривая тут уж
Re[5]: Task Parallel Library
От: Sinix  
Дата: 31.01.17 16:08
Оценка: +1
Здравствуйте, kov_serg, Вы писали:

_>Хотя MS умудрился изгатить реализацию так что abort использовать не безопасно почти всюду, при этом оставив его в runtime.

Тут не в компиляторе проблема, а в пользователях. Они не хотят платить производительностью за STM и не хотят платить разработчикам за переписывание всей codebase в failsafe-стиле.
Поэтому в общем случае, для произвольного кода, прерванный поток == поломанное состояние процесса == давай, до свидания.


_>Но это никак не соответствует утверждению "продолжать выполнение после прерывания потока в произвольной точке бессмысленно". Смыл в этом есть, а то что реализация в C# кривая тут уж


Ну так мы в каком разделе? Тут чисто прикладные вопросы обсуждаются. Поговорить на тему наличия у бабушки признаков дедушки — это лучше в Философию программирования
Re[6]: Task Parallel Library
От: Kolesiki  
Дата: 31.01.17 17:16
Оценка: :)
Здравствуйте, Sinix, Вы писали:

_>>Но это никак не соответствует утверждению "продолжать выполнение после прерывания потока в произвольной точке бессмысленно". Смыл в этом есть, а то что реализация в C# кривая тут уж


S>Ну так мы в каком разделе? Тут чисто прикладные вопросы обсуждаются.


.NET — это не только поделие микрософта, которым мы вынуждены пользоваться, но и сама по себе "теория программ в виртуальных машинах". Никому не интересны костыли, которые M$ приизолентила к дотнету — часто важна именно теоретическая составляющая: "Можно ли?". Если теоретически — можно, значит признаётся косяк за M$, а в копилку НЕНУЖНЫХ знаний добавляется сноска "пользовать такой то workaround". В данном случае, Abort() — абсолютно легальная, естественная операция, но реализация которой остаётся на совести индусов.
Re[6]: Task Parallel Library
От: kov_serg Россия  
Дата: 01.02.17 06:35
Оценка:
Здравствуйте, Sinix, Вы писали:

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


_>>Хотя MS умудрился изгатить реализацию так что abort использовать не безопасно почти всюду, при этом оставив его в runtime.

S>Тут не в компиляторе проблема, а в пользователях. Они не хотят платить производительностью за STM и не хотят платить разработчикам за переписывание всей codebase в failsafe-стиле.
S>Поэтому в общем случае, для произвольного кода, прерванный поток == поломанное состояние процесса == давай, до свидания.
Самое интересное что когда вам надо срочно что-то остановить, как правило, слегка кривое состояние процесса и его результаты не особо интересуют.
Re[7]: Task Parallel Library
От: Sinix  
Дата: 01.02.17 06:43
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Самое интересное что когда вам надо срочно что-то остановить, как правило, слегка кривое состояние процесса и его результаты не особо интересуют.


Топикстартер спрашивал про жёстко прервать задачу, не весь процесс целиком.
Re: Task Parallel Library
От: alexzzzz  
Дата: 01.02.17 17:13
Оценка:
Здравствуйте, Somescout, Вы писали:

S>Начал изучать task'и и буквально сразу возник вопрос как ограничить их одновременное количество. Есть ли какой-нибудь штатный способ? Или хотя-бы рекомендуемый лучшими Net'оводами?


В справке по TaskScheduler есть рабочий пример LimitedConcurrencyLevelTaskScheduler.
Re[2]: Task Parallel Library
От: alexzzzz  
Дата: 05.02.17 18:53
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>В справке по TaskScheduler есть рабочий пример LimitedConcurrencyLevelTaskScheduler.


Что-то он подозрительно себя ведёт. Не стоит им пользоваться.

Пробовал использовать у себя в проекте. Вроде работает нормально, но потом заметил, что некоторые задачи не выполняются. Вообще, даже не начинают. Где-то их проглатывает. Запустил те же задачи в ThreadPool ― всё заработало нормально.


Нет, это я дурак. LimitedConcurrencyLevelTaskScheduler нормально работает.
Отредактировано 05.02.2017 19:55 alexzzzz . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.