等待成千上万的任务

我有一个应用程序,通常有1.000 – 30.000文件转换一些数据。

我需要做3个步骤:

  1. 复制文件(替换那里的一些文字)
  2. 使用WebClient创建Webrequest以下载文件(我将复制的文件发送到WebServer,将文件转换为另一种格式)
  3. 获取下载的文件并更改部分内容

所以这三个步骤包括一些I / O,我使用了async / await方法:

var tasks = files.Select(async (file) => { Item item = await createtempFile(file).ConfigureAwait(false); await convert(item).ConfigureAwait(false); await clean(item).ConfigureAwait(false); }).ToList(); await Task.WhenAll(tasks).ConfigureAwait(false); 

我不知道这是否是最好的做法,因为我创造了超过一千个任务。 我想过将这三个步骤拆分为:

 List items = new List(); var tasks = files.Select(async (file) => { Item item = await createtempFile(file, ext).ConfigureAwait(false); lock(items) items.Add(item); }).ToList(); await Task.WhenAll(tasks).ConfigureAwait(false); var tasks = items.Select(async (item) => { await convert(item, baseAddress, ext).ConfigureAwait(false); }).ToList(); await Task.WhenAll(tasks).ConfigureAwait(false); var tasks = items.Select(async (item) => { await clean(targetFile, item.Doctype, ext).ConfigureAwait(false); }).ToList(); await Task.WhenAll(tasks).ConfigureAwait(false); 

但这似乎没有更好或更快,因为我创造了数千次任务。

我应该限制任务的创建吗? 像100个任务的大块? 或者我只是过度思考它,创造成千上万的任务就好了。

CPU处于空闲状态,峰值为2-4%,因此我想到了太多的等待或上下文切换。

也许WebRequest调用太多了,因为WebServer / WebService不能同时处理数千个请求,我只应该限制WebRequests?

我已经在app.config文件中增加了.NET maxconnection。

正如评论者正确指出的那样,你是在思考它。 .NET运行时跟踪数千个任务绝对没有问题。

但是,您可能需要考虑使用TPL Dataflow管道,这使您可以轻松地为管道中的不同操作(“块”)提供不同的并发级别。

可以并行执行异步操作限制并发操作的数量。 有一个很酷的扩展方法,它不是.Net框架的一部分

 ///  /// Enumerates a collection in parallel and calls an async method on each item. Useful for making /// parallel async calls, eg independent web requests when the degree of parallelism needs to be /// limited. ///  public static Task ForEachAsync(this IEnumerable source, int degreeOfParalellism, Func action) { return Task.WhenAll(Partitioner.Create(source).GetPartitions(degreeOfParalellism).Select(partition => Task.Run(async () => { using (partition) while (partition.MoveNext()) await action(partition.Current); }))); } 

这样叫:

 var files = new List {"one", "two", "three"}; await files.ForEachAsync(5, async file => { // do async stuff here with the file await Task.Delay(1000); });