你没有展示它,所以我们只能猜测,但我假设 tasks
是一个List<>
。这种集合类型是不线程安全的; 你的并行循环可能会“覆盖”值。要么手动锁定列表,要么切换到线程安全的集合,如ConcurrentQueue<>
var tasks = new ConcurrentQueue<Task<string>>();
Parallel.ForEach(numbers, number =>
{
var value = Regex.Replace(number, @"\s+", "%20");
tasks.Enqueue(client.GetAsync(url + value));
});
await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false);
foreach (var task in tasks)
{
}
话虽如此,你对 Parallel.ForEach
的使用方式相当可疑。循环内部没有执行任何真正重要的操作。使用 Parallel
,特别是带有适当的锁定,可能具有更高的开销,从而抵消了您所声称观察到或通过并行化 Regex
调用实现的任何潜在收益。我建议将其转换为普通的 foreach
循环,并预编译 Regex
以抵消(某些)其开销:
private static readonly Regex SpaceRegex = new Regex(@"\s+", RegexOptions.Compiled);
var tasks = new List<Task<string>>();
foreach (var number in numbers)
{
var value = SpaceRegex.Replace(number, "%20");
tasks.Add(client.GetAsync(url + value));
}
await Task.WhenAll(tasks).ConfigureAwait(false);
foreach (var task in tasks)
{
}
或者干脆不使用正则表达式。使用适当的Uri转义机制,这将带来更多好处,不仅可以修复空格:
var value = Uri.EscapeDataString(number);
var fullUri = Uri.EscapeUriString(url + number);
请注意有两种不同的方法。要使用正确的方法取决于url
和number
的值。还有其他机制,例如HttpUtility.UrlEncode
方法...但我认为这些是首选方法。
System.Collections.Generic.List
来存储tasks
。这个集合是非线程安全的,你必须使用线程安全的集合。请参阅 System.Collections.Concurrent 命名空间。 - Alexander PetrovParallel.ForEach
。使用异步方式,文档将自动并行下载。 - vc 74Parallel.ForEach
的意义是什么?你在其中没有执行任何工作。只需使用普通的foreach
循环将所有任务添加到列表中即可。这样,您就不会遇到上面评论中描述的问题。 - pinkfloydx33WhenAll
。 - vc 74