【问题标题】:Partitioning lists to execute parallel tasks分区列表以执行并行任务
【发布时间】:2021-01-07 14:24:07
【问题描述】:

我触发任务以下载多个 URL。

    Dim downloadTasksQuery As IEnumerable(Of Task(Of Boolean)) =
        From company In companies Select DownloadCompanyFromYahooAsync(company, numberOfDays)
    ' ***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)

companies 列表包含 2000 个 URL。我观察到添加到列表末尾的 URL 更频繁地超时。我有重试逻辑并正在处理这种超时情况,它会在下次尝试时下载 URL。但是,我不想仅仅因为 URL 出现在列表的开头就给予优惠。

因此我们试图考虑是否可以分叉 4 个主要任务,将 URL 列表分成 500 个(可能更易于管理),然后使用上面的代码。但是,我无法找到一种方法来引入它,而不必在上面的代码中重写太多。非常感谢任何帮助。

编辑:

类似这样的:

    Dim chunkPart As OrderablePartitioner(Of Tuple(Of Integer, Integer)) = Partitioner.Create(1, companies.Count, 500)

    Parallel.ForEach(chunkPart, Sub(chunkRange)
                                    For i As Integer = chunkRange.Item1 To chunkRange.Item2 - 1
                                        Dim downloadTasksQuery As IEnumerable(Of Task(Of Boolean)) =
                                        From company In companies.Skip(chunkRange.Item1).Take((chunkRange.Item2 - chunkRange.Item1) + 1) Select DownloadCompanyFromYahooAsync(company, numberOfDays)
                                        Dim downloadTasks As IEnumerable(Of Task(Of Boolean)) = downloadTasksQuery.ToList()
                                        Await Task.WhenAll(downloadTasks)
                                    Next
                                End Sub

这是对代码的更改最少,但问题是我不能在 Parallel.ForEach 中使用 Await

任何建议请改变这个。

【问题讨论】:

  • 更像是使用带有分区的 Parallel.ForEach。发布更新的问题。

标签: vb.net multithreading asynchronous async-await task-parallel-library


【解决方案1】:

不是 VB.NET 专家,但我认为 Stephen Toub 在 implementing a simple ForEachAsync 上的好帖子可能对您有所帮助。

他的帖子中的一些代码 sn-p,它允许您限制能够并行运行的操作数。

public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body) 
{ 
  return Task.WhenAll( 
    from partition in Partitioner.Create(source).GetPartitions(dop) 
    select Task.Run(async delegate { 
      using (partition) 
        while (partition.MoveNext()) 
          await body(partition.Current); 
  })); 
}

对于您的具体问题,您可以这样使用:

public async Task DownloadForAllCompanies(List<string> companies, int numberOfDays)
{
  await companies.ForEachAsync(4, async company =>
  {
    await DownloadCompanyFromYahooAsync(company, numberOfDays);
  });
}

【讨论】:

    猜你喜欢
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-18
    相关资源
    最近更新 更多