限制任务数量
Restricting number of tasks
我有一个代码可以触发 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)
它的作用是并行触发所有任务,任务排队直到它连接到 Internet 并得到响应。由于任务数量很多,很多任务会超时,因为它们无法在时间内获得响应,因为在任何时间点等待此类响应的任务数量都是巨大的。 (请记住我已经删除了实际的下载代码以保持简单,并用一个长 运行 任务代替,该任务只在上面的 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())
我在
中尝试了 @ClearLogics 示例
它也表现出相同的行为。所有任务都会立即触发。
我该如何解决这个问题 - 只需要触发 100 个任务,然后等待,然后继续排队,这样在任何时候,我的任务都不会超过 100 个。
您对 MaxDegreeOfParallelism
的预期不正确,请查看 this 文章,其中解释了为什么您可以看到同时启动了 2000 个线程。当 Await Task.Delay(1000).ConfigureAwait(False)
被执行时,线程被认为是空闲的并且可以开始下一个任务。
What I want to do is limit the number of tasks that can be fired.
你得自己去实现。您可以采取两种方法:
如果您选择第二个选项,我警告您,这只是使用 Semaphore 的示例。我的意思是,该代码不适用于生产。
我有一个代码可以触发 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)
它的作用是并行触发所有任务,任务排队直到它连接到 Internet 并得到响应。由于任务数量很多,很多任务会超时,因为它们无法在时间内获得响应,因为在任何时间点等待此类响应的任务数量都是巨大的。 (请记住我已经删除了实际的下载代码以保持简单,并用一个长 运行 任务代替,该任务只在上面的 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())
我在
它也表现出相同的行为。所有任务都会立即触发。
我该如何解决这个问题 - 只需要触发 100 个任务,然后等待,然后继续排队,这样在任何时候,我的任务都不会超过 100 个。
您对 MaxDegreeOfParallelism
的预期不正确,请查看 this 文章,其中解释了为什么您可以看到同时启动了 2000 个线程。当 Await Task.Delay(1000).ConfigureAwait(False)
被执行时,线程被认为是空闲的并且可以开始下一个任务。
What I want to do is limit the number of tasks that can be fired.
你得自己去实现。您可以采取两种方法:
如果您选择第二个选项,我警告您,这只是使用 Semaphore 的示例。我的意思是,该代码不适用于生产。