我需要异步从同一页面获取数据,不要阻止主线程。
我尝试使用类WebClient的DownloadDataAsync方法,但似乎它的行为并非真的是异步方式。
为了测试这个,我制作代码
private void button1_Click(object sender, EventArgs e)
{
checkLink_async();
Thread.CurrentThread.Join(5000);
checkLink_async();
Thread.CurrentThread.Join(5000);
checkLink_async();
Thread.CurrentThread.Join(5000);
}
/// <summary>
/// Check the availability of IP server by starting async read from input sensors.
/// </summary>
/// <returns>Nothing</returns>
public void checkLink_async()
{
string siteipURL = "http://localhost/ip9212/getio.php";
Uri uri_siteipURL = new Uri(siteipURL);
// Send http query
WebClient client = new WebClient();
try
{
client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(checkLink_DownloadCompleted_test);
client.DownloadDataAsync(uri_siteipURL);
tl.LogMessage("CheckLink_async", "http request was sent");
}
catch (WebException e)
{
tl.LogMessage("CheckLink_async", "error:" + e.Message);
}
}
private void checkLink_DownloadCompleted_test(Object sender, DownloadDataCompletedEventArgs e)
{
tl.LogMessage("checkLink_DownloadCompleted", "http request was processed");
}
log:
的结果01:32:12.089 CheckLink_async http request was sent
01:32:17.087 CheckLink_async http request was sent
01:32:22.097 CheckLink_async http request was sent
01:32:27.102 checkLink_DownloadComplet http request was processed
01:32:27.102 checkLink_DownloadComplet http request was processed
01:32:27.102 checkLink_DownloadComplet http request was processed
我预计每个启动的DownloadDataAsync方法将并行运行并在主线程代码runnig期间完成(我使用Thread.CurrentThread.Join在代码中模拟它)。 但似乎在button1_Click结束之前,没有任何DownloadDataAsync调用都已完成(尽管有足够的时间)。
有没有办法改变这种行为,或者我应该使用另一种方法?
答案 0 :(得分:2)
您正在观察的内容有一个简单的(r)解释。 DownloadDataAsync
在封面下使用System.ComponentModel.AsyncOperation
,在SynchronizationContext
操作开始时保留对DownloadDataAsync
当前的引用,并在完成时发回给它。这可以确保在具有有效DownloadDataCompleted
的应用程序中启动下载的同一个线程上引发SynchronizationContext
事件(即Windows窗体,它看起来就像您正在使用的那样) )。
由于我们回发到已经被阻止的线程,因此完成处理程序必须等待它才能执行。
在SynchronizationContext.SetSynchronizationContext(null);
处理程序的开头介绍button1_Click
,在按钮处理程序运行完成之前,您将看到完成按照原始期望执行。
修改强>
正如@PeterDuniho指出的那样,SetSynchronizationContext(null)
不应该在快速和肮脏的测试之外使用。证明围绕SynchronizationContext
的存在或缺失的理论的更好方法是使用单独的测试应用程序(即,如果已经使用Windows窗体,启动一个快速的控制台项目,以查看代码的行为如何没有SynchronizationContext
)。与SyncronizationContext.Current
混淆的用途有限,可能让你陷入痛苦的世界。
答案 1 :(得分:0)
我认为您最好使用Task
WebClient
与async-await
的{{1}} API,这会使您的代码更加整洁:
private async void button1_Click(object sender, EventArgs e)
{
await checkLink_async();
await checkLink_async();
await checkLink_async();
}
/// <summary>
/// Check the availability of IP server by starting async read from input sensors.
/// </summary>
/// <returns>Nothing</returns>
public async Task checkLink_async()
{
string siteipURL = "http://localhost/ip9212/getio.php";
// Send http query
var client = new System.Net.WebClient();
try
{
Task t = client.DownloadDataTaskAsync(siteipURL);
//tl.LogMessage("CheckLink_async", "http request was sent");
await t;
//tl.LogMessage("checkLink_DownloadCompleted", "http request was processed");
}
catch (System.Net.WebException e)
{
// tl.LogMessage("CheckLink_async", "error:" + e.Message);
}
}