我试图使用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();
});
但这看起来有点笨拙,我不确定它是否是解决这个问题的正确方法。有没有人知道如何使用Tasks和async / await以异步方式运行一堆同步代码?
答案 0 :(得分:6)
这是正确的解决方案。 WebRequest.GetResponse
不是异步方法,因此它不返回任务。它无法异步运行。
实际上,你所拥有的是你能得到的最正确和最简便的解决方案(使用Task.Run
)。
我的印象是var task = DoRequestAsync()会 创建一个新线程并异步运行该方法中的所有内容, 但事实并非如此。
这不是魔术。为了使它以异步方式运行,必须在异步方法中创建一个新的Task(而不是线程),或者它必须等待一个或多个方法)返回Task
,Task<T>
或{{1 (这适用于事件处理程序)。
方法void
中的最后一个语句只返回已完成的return "done!";
,结果为“已完成”。
作为旁注,这就是HttpClient成为事实上的类HTTP请求的原因,特别是对于与Web API的互操作,还用于通用GET / POST /等:它具有异步支持。
任务也支持包装Begin * / End *函数(符合前一个asynchronous programming model - APM)。你也可以这样做:
Task<string>
答案 1 :(得分:0)
这是完全正确的解决方案。
如果要使用异步,则必须确保始终异步。换句话说,如果您没有调用方法的异步版本,则需要自己使用Task包装它。