Используя TPL, как мне установить максимальный размер пула потоков

Я использую TPL для добавления новых задач в пул системных потоков с помощью функцииTask.Factory.StartNew(), Единственная проблема заключается в том, что я добавляю много потоков и думаю, что это создает слишком много для моего процессора. Есть ли способ установить максимальное количество потоков в этом пуле потоков?

 Panagiotis Kanavos18 июн. 2012 г., 15:06
Есть примеры кода?
 svick18 июн. 2012 г., 03:12
Не думайте, выясните, правда ли это на самом деле.

Ответы на вопрос(4)

Решение Вопроса

TaskScheduler (получен изTaskScheduler.Default) имеет тип (внутренний класс)ThreadPoolTaskScheduler, Эта реализация используетThreadPool класс для постановки задач в очередь (еслиTask не создан сTaskCreationOptions.LongRunning - в этом случае новый поток создается для каждой задачи).

Итак, если вы хотите ограничить количество потоков, доступных дляTask объекты, созданные с помощьюnew Task(() => Console.WriteLine("In task"))Вы можете ограничить доступные потоки в глобальном пуле потоков следующим образом:

// Limit threadpool size
int workerThreads, completionPortThreads;
ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
workerThreads = 32;
ThreadPool.SetMaxThreads(workerThreads, completionPortThreads);

Призыв кThreadPool.GetMaxThreads() сделано, чтобы избежать сокращенияcompletionPortThreads.

Обратите внимание, что это может быть плохой идеей - поскольку все задачи без указанного планировщика и любое количество других классов используют ThreadPool по умолчанию, установка слишком малого размера может вызвать побочные эффекты: голодание и т. Д.

ествуют различные проблемы, которые могут привести к снижению использования:

Scheduling long-running tasks without the LongRunningTask option Trying to open more than two concurrent connections to the same web address Blocking for access to the same resource Trying to access the UI thread using Invoke() from multiple threads

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

 03 февр. 2015 г., 08:54
Спасибо за отрицательный ответ, хотите объяснить? Распространенная ошибка - люди, предполагающие, что задачи равны потокам, и пытаются ограничить количество задач, что приводит к еще большим проблемам с производительностью.

по умолчанию & quot; размер пула Если вам действительно нужно меньше тем, посмотритеКак: создать планировщик задач, ограничивающий степень параллелизма

выполняемых задач, но если вы действительно хотите иметь контроль над нимМой блог показывает, как сделать это как с Задачами, так и с Действиями, и предоставляет пример проекта, который вы можете загрузить и запустить, чтобы увидеть оба в действии.

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

Для того, что вы описываете, кажется, что вы можете получить больше пользы от того, чтобы убедиться, что вы используете async / await со своими задачами, чтобы предотвратить ненужное использование потоков. Это будет зависеть от того, выполняете ли вы работу с процессором или работу с IO в ваших задачах. Если это связано с IO, то вы можете получить большую выгоду от использования async / await.

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

With Actions

При использовании Actions вы можете использовать встроенную функцию .Net Parallel.Invoke. Здесь мы ограничиваем его одновременной работой максимум 3 потоков.

var listOfActions = new List<Action>();
for (int i = 0; i < 10; i++)
{
    // Note that we create the Action here, but do not start it.
    listOfActions.Add(() => DoSomething());
}

var options = new ParallelOptions {MaxDegreeOfParallelism = 3};
Parallel.Invoke(options, listOfActions.ToArray());
With Tasks

Поскольку здесь вы используете Задачи, встроенной функции нет. Тем не менее, вы можете использовать тот, который я предоставляю в моем блоге.

    /// <summary>
    /// Starts the given tasks and waits for them to complete. This will run, at most, the specified number of tasks in parallel.
    /// <para>NOTE: If one of the given tasks has already been started, an exception will be thrown.</para>
    /// </summary>
    /// <param name="tasksToRun">The tasks to run.</param>
    /// <param name="maxTasksToRunInParallel">The maximum number of tasks to run in parallel.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    public static void StartAndWaitAllThrottled(IEnumerable<Task> tasksToRun, int maxTasksToRunInParallel, CancellationToken cancellationToken = new CancellationToken())
    {
        StartAndWaitAllThrottled(tasksToRun, maxTasksToRunInParallel, -1, cancellationToken);
    }

    /// <summary>
    /// Starts the given tasks and waits for them to complete. This will run, at most, the specified number of tasks in parallel.
    /// <para>NOTE: If one of the given tasks has already been started, an exception will be thrown.</para>
    /// </summary>
    /// <param name="tasksToRun">The tasks to run.</param>
    /// <param name="maxTasksToRunInParallel">The maximum number of tasks to run in parallel.</param>
    /// <param name="timeoutInMilliseconds">The maximum milliseconds we should allow the max tasks to run in parallel before allowing another task to start. Specify -1 to wait indefinitely.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    public static void StartAndWaitAllThrottled(IEnumerable<Task> tasksToRun, int maxTasksToRunInParallel, int timeoutInMilliseconds, CancellationToken cancellationToken = new CancellationToken())
    {
        // Convert to a list of tasks so that we don&#39;t enumerate over it multiple times needlessly.
        var tasks = tasksToRun.ToList();

        using (var throttler = new SemaphoreSlim(maxTasksToRunInParallel))
        {
            var postTaskTasks = new List<Task>();

            // Have each task notify the throttler when it completes so that it decrements the number of tasks currently running.
            tasks.ForEach(t => postTaskTasks.Add(t.ContinueWith(tsk => throttler.Release())));

            // Start running each task.
            foreach (var task in tasks)
            {
                // Increment the number of tasks currently running and wait if too many are running.
                throttler.Wait(timeoutInMilliseconds, cancellationToken);

                cancellationToken.ThrowIfCancellationRequested();
                task.Start();
            }

            // Wait for all of the provided tasks to complete.
            // We wait on the list of "post" tasks instead of the original tasks, otherwise there is a potential race condition where the throttler&#39;s using block is exited before some Tasks have had their "post" action completed, which references the throttler, resulting in an exception due to accessing a disposed object.
            Task.WaitAll(postTaskTasks.ToArray(), cancellationToken);
        }
    }

А затем, создав список задач и вызвав функцию для их запуска, скажем, максимум 3 одновременно, вы можете сделать это:

var listOfTasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    var count = i;
    // Note that we create the Task here, but do not start it.
    listOfTasks.Add(new Task(() => Something()));
}
Tasks.StartAndWaitAllThrottled(listOfTasks, 3);

Ваш ответ на вопрос