我有以下代码
ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadAsync), apiMethod);
downloadHandle.WaitOne();
DownloadAsync的位置
private void DownloadAsync(object _uri)
{
var url = _uri as string;
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri(GLOBALS.MAIN_API_URL + url, UriKind.Absolute));
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
result = e.Result;
downloadHandle.Set();
}
所以我的问题是downloadHandle.Set()永远不会调用。但我不明白为什么?我为DownloadAsync和downloadHandle创建了一个新线程.WaitOne()不应该阻止他。
我需要的是创建一个Sync方法而不是Async。
谢谢!
UPD:使用异步调用更新了源代码。
答案 0 :(得分:4)
client.DownloadString
是同步方法,因此永远不会调用您完成的处理程序。您需要调用异步版本:client.DownloadStringAsync()
您可以在msdn上阅读有关DownloadStringAsync的更多信息。将代码放入try-catch块并处理异常也是明智的,如果你依赖于这个事实,应该调用一些代码。
您的代码可能如下所示:
private void DownloadAsync(object _uri)
{
try
{
var url = _uri as string;
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri(GLOBALS.MAIN_API_URL + url, UriKind.Absolute));
}
catch //appropriate exception
{
//Handle exception (maybe set downloadHandle or report an error)
}
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
result = e.Result;
downloadHandle.Set();
}
答案 1 :(得分:2)
可能存在阻止调用完成回调方法的异常。你有没有检查它是否被调用了?
顺便说一下,你实际上并不需要在这里使用线程池 - 你可以在主线程上调用DownloadAsync(),因为它不会阻塞。
答案 2 :(得分:2)
我的猜测:你是从UI线程调用downloadHandle.WaitOne()
的。如果您正在从UI事件处理程序执行代码(例如,单击按钮或导航到新页面),或者事件处理程序调用的函数,那么您就在UI线程中。
为什么这是一个问题?
果然,DownloadAsync
在后台执行,这要归功于线程池。但是,WebClient类总是使用UI线程执行其回调(即,您的client_DownloadStringCompleted
方法)...但是downloadHandle.WaitOne()
阻止了这个相同的线程!
这就是为什么当你对锁定超时时,client_DownloadStringCompleted
方法会被神奇地执行。
如何解决这个问题?两种解决方案。
1 /停止在主线程中执行downloadHandle.WaitOne()
。它阻止了用户界面,你的应用程序变得没有响应,这是从不是一件好事。
2 /使用HttpWebRequest
代替WebClient
。 HttpWebRequest
在开始下载的同一个线程上执行回调,因此您不会遇到此死锁问题。
答案 3 :(得分:0)
当您从downloadHandle.WaitOne();
致电UI
时阻止UI thread
,因此ThreadPool
将永远不会致电。转到后台:
ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadAsync), apiMethod);
downloadHandle.WaitOne();