我有一个方法尝试从多个 URL 中并行下载数据,并返回反序列化类型的 IEnumerable
方法如下所示:
public IEnumerable<TContent> DownloadContentFromUrls(IEnumerable<string> urls)
{
var list = new List<TContent>();
Parallel.ForEach(urls, url =>
{
lock (list)
{
_httpClient.GetAsync(url).ContinueWith(request =>
{
var response = request.Result;
//todo ensure success?
response.Content.ReadAsStringAsync().ContinueWith(text =>
{
var results = JObject.Parse(text.Result)
.ToObject<IEnumerable<TContent>>();
list.AddRange(results);
});
});
}
});
return list;
}
在我的单元测试中(我将 _httpClient stub 以返回一组已知的文本)我基本上得到了
Sequence contains no elements
这是因为该方法在任务完成之前返回。
如果我在 .ContinueWith() 调用的末尾添加 .Wait() ,它会通过,但我确定我在这里滥用了 API...
最佳答案
如果你想要一个使用 HttpClient.GetAsync 方法并行下载的阻塞调用,那么你应该像这样实现它:
public IEnumerable<TContent> DownloadContentFromUrls<TContent>(IEnumerable<string> urls)
{
var queue = new ConcurrentQueue<TContent>();
using (var client = new HttpClient())
{
Task.WaitAll(urls.Select(url =>
{
return client.GetAsync(url).ContinueWith(response =>
{
var content = JsonConvert.DeserializeObject<IEnumerable<TContent>>(response.Result.Content.ReadAsStringAsync().Result);
foreach (var c in content)
queue.Enqueue(c);
});
}).ToArray());
}
return queue;
}
这将创建一组任务,每个 Url 一个,代表一个 GetAsync/Deserialize 操作。这是假设 Url 返回 TContent 的 Json 数组。空数组或单个成员数组可以很好地反序列化,但单个无数组对象则不行。
关于c# - Parallel.ForEach 与 HttpClient 和 ContinueWith,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19383910/