限制任务数量

时间:2017-08-27 05:51:35

标签: asynchronous async-await task task-parallel-library taskscheduler

我有一个代码可以为2000多家公司启动下载数据例程。为了保持这个例子的简单,我已经将下载例程改为300秒等待。以下是调用者多次调用的单个公司的例程。

Public Async Function DoJob(ByVal company As Company) As Task(Of Boolean)
    Console.WriteLine(String.Format("Started:{0}", company.CompanySymbol))
    For i As Long = 1 To 300
        Await Task.Delay(1000).ConfigureAwait(False)
    Next
    Console.WriteLine(String.Format("Ended:{0}", company.CompanySymbol))
    Return True
End Function

来自来电者,我使用:

Dim downloadTasksQuery As IEnumerable(Of Task(Of Boolean)) =
               From company In companies Select DoJob(company)
'***Use ToList to execute the query And start the download tasks. 
Dim downloadTasks As IEnumerable(Of Task(Of Boolean)) = downloadTasksQuery.ToList()
Await Task.WhenAll(downloadTasks) 

它的作用是并行激活所有任务,任务排队等待到达互联网并回复。由于任务数量很多,许多任务正在超时,因为他们无法在时间内得到响应,因为在任何时间点等待此类响应的任务数量巨大。 (请记住,我删除了实际的下载代码,以保持简单,并在上面的DoJob方法中等待300秒的长时间运行任务代替。)

我想要做的是限制可以触发的任务数量。说,50。这意味着在任何时候只有50个任务将处于活动状态,休息将等待任务从50个团队中完成,然后在任务完成时排队。

我试过这个:

Dim options As New ParallelOptions()
options.MaxDegreeOfParallelism = 100
Parallel.ForEach(companies, options, Sub(company)
                                                 ' logic
                                                 DoJob(company)
                                             End Sub)

但看起来这是一次性解雇所有任务,而不是先取消100然后再等待(来自DoJob的打印来自所有2000多个项目,然后任务完成)。

这里也有同样的问题:

Dim listOfActions = New List(Of Action)()
For Each company In companies
    ' Note that we create the Action here, but do not start it.
    listOfActions.Add(Function() DoJob(company))
Next

Dim options As New ParallelOptions()
options.MaxDegreeOfParallelism = 100
Parallel.Invoke(options, listOfActions.ToArray())

我在How to limit the Maximum number of parallel tasks in c#

中尝试过@ClearLogics示例

它也表现出相同的行为。所有任务都会立刻被解雇。

我如何解决这个问题 - 只需要解雇100个任务并等待随后排队,以便在任何时候,我都没有超过100个任务。

1 个答案:

答案 0 :(得分:0)

您对MaxDegreeOfParallelism的期望不正确,请查看this文章,该文章解释了为什么您可以看到同时启动的2000个主题。当Await Task.Delay(1000).ConfigureAwait(False)被执行时,假定线程是空闲的,并且可以在下一个任务开始。

  

我想要做的是限制可以解雇的任务数量。

您必须自己实施。您可以采取两种方法:

  1. this文章中实施自定义TaskScheduller
  2. 控制更高级别上创建的任务的数量,例如,使用信号量来控制并发任务。您可以找到here
  3. 的示例

    如果您选择第二个选项,我警告您,这只是与Semaphore合作的一个例子。我的意思是,代码不适合生产。