Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 限制同时执行任务的数量_C#_C# 4.0_Task Parallel Library - Fatal编程技术网

C# 限制同时执行任务的数量

C# 限制同时执行任务的数量,c#,c#-4.0,task-parallel-library,C#,C# 4.0,Task Parallel Library,将其视为一个庞大的任务池: var tasks = new Task[4] { Task.Factory.StartNew(() => DoSomething()), Task.Factory.StartNew(() => DoSomething()), Task.Factory.StartNew(() => DoSomething()), Task.Factory.StartNew(() => Do

将其视为一个庞大的任务池:

var tasks = new Task[4]
    {
        Task.Factory.StartNew(() => DoSomething()),
        Task.Factory.StartNew(() => DoSomething()),
        Task.Factory.StartNew(() => DoSomething()),
        Task.Factory.StartNew(() => DoSomething()),
        Task.Factory.StartNew(() => DoSomething())
    };

Task.WaitAll(tasks);

如果我只想同时运行3个任务呢?我将如何在代码中实现这一点?

所以您希望指定同时执行的任务的数量。请注意,这是一个糟糕的设计思想-至少在大多数情况下,您应该让系统决定同时执行多少任务。当您使用
Task.Factory.StartNew
方法以这种方式创建任务而无需附加参数时,任务将尽快执行(尽快),因此通常不应明确指定同时执行任务的数量

在这种情况下,尽快是什么意思?任务管理器将决定是立即启动所有任务,还是删除部分任务,或者等待其他任务完成,等等

您可以使用某种手动同步来实现您的目标。我的意思是像一个信号灯


如果您不需要做其他工作,只想等待任务完成,我更愿意按照Gary S.的建议调用并行调用。

我在MSDN上找到的。我相信它实现了您试图实现的目标。

一个比MSDN版本更简单的示例是使用并行。调用设置最大并行度:

Parallel.Invoke(
    new ParallelOptions() { MaxDegreeOfParallelism = 3 }, 
    () => DoSomething(), 
    () => DoSomething(),
    () => DoSomething(),
    () => DoSomething(),
    () => DoSomething());
然而,Parallel.Invoke()将一直阻塞,直到所有并行操作都完成为止(这意味着Parallel.Invoke之外的代码在它们全部完成之前不会运行)。如果这对您不起作用,那么您将需要创建自己的任务计划程序,如Daniel链接的MSDN文章所示。

展示了如何使用任务和操作来实现这一点,并提供了一个示例项目,您可以下载并运行该项目来查看这两种操作

最初的海报没有说明他们是否喜欢使用动作或任务,有时从一个切换到另一个并不容易,所以我在这里介绍这两种解决方案

用行动 如果使用操作,则可以使用内置的.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());
var listOfActions=new List();
对于(int i=0;i<10;i++)
{
//注意,我们在这里创建操作,但不启动它。
添加(()=>DoSomething());
}
var options=new ParallelOptions{maxdegreeofpparallelism=3};
Parallel.Invoke(options,listOfActions.ToArray());
有任务 由于您在这里使用的是任务,因此没有内置函数。但是,你可以使用我在我的博客上提供的

    /// <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);
        }
    }
//
///启动给定的任务并等待它们完成。这将最多并行运行指定数量的任务。
///注意:如果给定任务之一已启动,将引发异常。
/// 
///要运行的任务。
///并行运行的最大任务数。
///取消令牌。
public static void StartAndWaitAllThrottled(IEnumerable tasksToRun,int maxstaskstorunipallel,CancellationToken CancellationToken=new CancellationToken())
{
StartAndWaitAllThrottled(tasksToRun,MaxTaskStorUninPallel,-1,cancellationToken);
}
/// 
///启动给定的任务并等待它们完成。这将最多并行运行指定数量的任务。
///注意:如果给定任务之一已启动,将引发异常。
/// 
///要运行的任务。
///并行运行的最大任务数。
///在允许另一个任务启动之前,我们应该允许max任务并行运行的最长毫秒数。指定-1无限期等待。
///取消令牌。
public static void StartAndWaitAllThrottled(IEnumerable tasksToRun,int-maxTasksToRunInParallel,int-timeoutin毫秒,CancellationToken CancellationToken=new CancellationToken())
{
//转换为任务列表,这样我们就不会不必要地重复多次。
var tasks=tasksToRun.ToList();
使用(var节流器=新信号量LIM(MaxTaskStorUninPallel))
{
var postTaskTasks=新列表();
//让每个任务在完成时通知节流器,以减少当前正在运行的任务数。
tasks.ForEach(t=>postTaskTasks.Add(t.ContinueWith(tsk=>throttler.Release()));
//开始运行每个任务。
foreach(任务中的var任务)
{
//增加当前正在运行的任务数,如果正在运行的任务太多,请等待。
throttler.Wait(timeoutin毫秒,cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
task.Start();
}
//等待提供的所有任务完成。
//我们等待的是“post”任务列表,而不是原始任务,否则可能存在争用情况,即在某些任务的“post”操作完成之前退出节流器的using块,该操作引用节流器,从而导致由于访问已处置对象而出现异常。
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);
var listOfTasks=new List();
对于(int i=0;i<10;i++)
{
var计数=i;
//注意,我们在这里创建任务,但不启动它。
添加(新任务(()=>Something());
}
任务。启动和等待所有限制(任务列表,3);

一般情况下,您可以将其留给TPL调度程序。你有充分的理由干涉吗?我大体上同意。然而,在我的具体用例中,有一个处理节流的需求。您是如何决定这种任务应该尽快执行的?这是完全不可能的某种要求可能需要一些