我有一个应用程序可以转换一些数据,通常有 1.000 - 30.000 个文件。
我需要做 3 个步骤:
- 复制一个文件(替换里面的一些文本)
- 使用 WebClient 发出 Webrequest 以下载文件(我将复制的文件发送到 WebServer,后者将文件转换为另一种格式)
- 获取下载的文件并更改部分内容
所以所有三个步骤都包含一些 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<Item> items = new List<Item>();
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);
但这似乎并没有更好或更快,因为我创建了 3 倍于数千个任务。
我应该限制任务的创建吗?像 100 个任务的 block ? 还是我想多了,创建数千个任务就可以了。
CPU 以 2-4% 的峰值闲置,所以我想到了太多的等待或上下文切换。
也许 WebRequest 调用太多,因为 WebServer/WebService 无法同时处理数千个请求,我应该只限制 WebRequests?
我已经在 app.config 文件中增加了 .NET maxconnection。
最佳答案
可以并行执行异步操作,同时限制并发操作的数量。有一个很酷的扩展方法,它不是 .Net 框架的一部分。
/// <summary>
/// Enumerates a collection in parallel and calls an async method on each item. Useful for making
/// parallel async calls, e.g. independent web requests when the degree of parallelism needs to be
/// limited.
/// </summary>
public static Task ForEachAsync<T>(this IEnumerable<T> source, int degreeOfParalellism, Func<T, Task> 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<string> {"one", "two", "three"};
await files.ForEachAsync(5, async file =>
{
// do async stuff here with the file
await Task.Delay(1000);
});
关于c# - 等待数千个任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40124360/