有人可以向我解释为什么我会从这段代码中收到ArgumentException
吗?它告诉我tasks
函数中的Task.WhenAll
参数包含空值。但是,它只在我运行它时偶尔发生。
static async Task TestRequestSpeed()
{
var requestTasks = new List<Task>();
await Task.Run(() =>
{
Parallel.For(0, 50, (i) =>
{
requestTasks.Add(HttpSocket.Instance.GetAsync("http://google.com"));
});
});
await Task.WhenAll(requestTasks).ConfigureAwait(false);
}
我不明白其中一个请求最终会返回一个空任务。如果有人能指导我解决潜在的问题,我将不胜感激!
更新
我应该澄清一下,我的意图是并行提出多个请求以加快执行速度。我正在处理一个个人项目,需要在单个方法调用中完成200个请求,我希望减少发出这些请求所需的时间。使用正常的async-await程序执行此操作目前大约需要45秒,因此我希望并行地发出请求以尽可能减少时间。如果有更好的方法,请告诉我。
答案 0 :(得分:4)
使用多个线程来初始化任务列表绝对没有充分的理由。开销超过收益。您可以改为使用Enumerable.Select
:
static async Task TestRequestSpeedAsync()
{
var requestTasks = Enumerable.Range(0, 50).Select(HttpSocket.Instance.GetAsync("http://www.google.com"));
await Task.WhenAll(requestTasks).ConfigureAwait(false);
}
注意我添加了Async
后缀以遵循TAP指南。
答案 1 :(得分:2)
普通List<T>
不是线程安全的。而且你是Add
来自潜在的50个并行线程。那不会起作用。
按顺序插入该列表,或使用线程安全的容器进行添加。
答案 2 :(得分:1)
正如nvoigt所说,List<T>
不能支持被多个线程写入。幸运的是,.net已经包含一组支持System.Collections.Concurrent
(http://msdn.microsoft.com/en-us/library/system.collections.concurrent%28v=vs.110%29.aspx)命名空间下的线程安全写入的集合。
作为一个例子,这似乎对我有用:
static async Task TestRequestSpeed()
{
var requestTasks = new ConcurrentQueue<Task>();
await Task.Run(() =>
{
Parallel.For(0, 50, (i) =>
{
HttpClient hc = new HttpClient();
requestTasks.Enqueue(hc.GetStringAsync(new Uri("http://google.com")));
});
});
await Task.WhenAll(requestTasks).ConfigureAwait(false);
}