我正在尝试使用await/async 来使一些同步代码异步。例如,这可以工作并解除 UI 线程的阻塞:
private async void button1_Click(object sender, EventArgs e)
{
var task = DoRequestAsync();
textBox1.Text = "starting async task";
var text = await task;
textBox1.Text = text;
}
private async Task<string> DoRequestAsync()
{
try
{
var client = new HttpClient();
client.Timeout = new TimeSpan(0, 0, 0, 5);
await client.GetAsync("http://123.123.123.123"); // force a timeout exception
}
catch (Exception e)
{
}
return "done!";
}
但这不会,并且会挂起 UI 线程:
private async void button1_Click(object sender, EventArgs e)
{
var task = DoRequestAsync();
textBox1.Text = "starting async task";
var text = await task;
textBox1.Text = text;
}
private async Task<string> DoRequestAsync()
{
try
{
var request = WebRequest.Create("http://123.123.123.123");
request.Timeout = 5000;
request.GetResponse(); // force a timeout exception
}
catch (Exception e)
{
}
return "done!";
}
我试图理解为什么会出现这种情况。我的印象是var task = DoRequestAsync()
将创建一个新线程并异步运行该方法中的所有内容,但情况似乎并非如此。
我可以用它来使它工作:
await Task.Run(() => {
var request = WebRequest.Create("http://123.123.123.123");
request.Timeout = 5000;
request.GetResponse();
});
但这似乎有点老套,我不确定这是否是解决这个问题的正确方法。有谁知道我如何使用任务和异步/等待以异步方式运行一堆同步代码?
这是正确的解决方案。WebRequest.GetResponse
不是异步方法,因此它不返回任务。它不能异步运行。
实际上,您所拥有的是您可以获得的最正确和速记的解决方案(使用Task.Run
).
我的印象是 var task = DoRequestAsync() 会
创建一个新线程并异步运行方法中的所有内容,
但事实似乎并非如此。
这不是魔法。为了使其异步运行,必须在异步方法中创建一个新任务(不是线程),或者它必须等待一个或多个返回任一方法的方法)Task
, Task<T>
or void
(这是针对事件处理程序的)。
方法中的最后一条语句return "done!";
只返回一个已完成的Task<string>
结果“完成”。
附带说明一下,这就是 HttpClient 成为事实上的 HTTP 请求类的原因,特别是对于与 Web API 互操作,但也用于通用 GET/POST/等:它有异步支持.
任务还支持包装 Begin*/End* 函数(符合前面的异步编程模型——APM http://msdn.microsoft.com/en-us/library/ms228963(v=vs.110).aspx)。您还可以这样做:
try
{
var request = WebRequest.Create("http://123.123.123.123");
request.Timeout = 5000;
await Task.Factory.FromAsync(request.BeginGetResponse(), request.EndGetResponse, null); // force a timeout exception
}
catch (Exception e)
{
//TODO handle exception here
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)