【问题标题】:Restricting number of tasks限制任务数量
【发布时间】:2017-08-27 05:51:34
【问题描述】:

我有一个代码可以触发 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 个任务处于活动状态,rest 将等待 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 个。

【问题讨论】:

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


【解决方案1】:

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

我想做的是限制可以触发的任务数量。

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

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

如果您选择第二个选项,我警告您这只是使用 Semaphore 的一个说明。我的意思是,代码不用于生产。

【讨论】:

    猜你喜欢
    • 2011-02-23
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多