我有一个非常奇怪的问题。我的WebClient.DownloadDataCompleted
大部分时间都不会触发。
我正在使用这个类:
public class ParallelFilesDownloader
{
public Task DownloadFilesAsync(IEnumerable<Tuple<Uri, Stream>> files, CancellationToken cancellationToken)
{
var localFiles = files.ToArray();
var tcs = new TaskCompletionSource<object>();
var clients = new List<WebClient>();
cancellationToken.Register(
() =>
{
// Break point here
foreach (var wc in clients.Where(x => x != null))
wc.CancelAsync();
});
var syncRoot = new object();
var count = 0;
foreach (var file in localFiles)
{
var client = new WebClient();
client.DownloadDataCompleted += (s, args) =>
{
// Break point here
if (args.Cancelled)
tcs.TrySetCanceled();
else if (args.Error != null)
tcs.TrySetException(args.Error);
else
{
var stream = (Stream)args.UserState;
stream.Write(args.Result, 0, args.Result.Length);
lock (syncRoot)
{
count++;
if (count == localFiles.Length)
tcs.TrySetResult(null);
}
}
};
clients.Add(client);
client.DownloadDataAsync(file.Item1, file.Item2);
}
return tcs.Task;
}
}
当我在LINQPad中独立调用
DownloadFilesAsync
时,预期情况下大约半秒钟后就会调用DownloadDataCompleted
。然而,在我的实际应用程序中,它根本不会触发,等待它完成的代码被卡住了。如注释所示,我有两个断点,但都没有被击中。但是,有时它确实会触发。相同的URL、相同的代码,只是一个新的调试会话,没有任何规律可言。
我检查了线程池中可用的线程:workerThreads > 30k,completionPortThreads = 999。
在返回之前,我添加了10秒的休眠,并在休眠后检查我的Web客户端没有被垃圾回收,我的事件处理程序仍然附加着。
现在,我已经没有更多的想法来解决这个问题了。还有什么可能导致这种奇怪的行为?
DownloadFilesAsync(......).Wait()
。 - L.BTask.WaitAll
等待此任务和其他任务。但是,(1)我不明白这会对异步下载产生什么影响,请详细说明;(2)当我添加睡眠时问题并没有消失,因此将不会调用Task.WaitAll
。 - Daniel Hilgarthawait Task.WhenAll
) 调用它,而不会阻塞调用线程(我怀疑会出现死锁)。 - L.BDownloadDataCompleted
在调用线程的同步上下文中运行,则会出现相同的问题。 - L.B