如何将await/async与同步代码一起使用? [英] How do I use await/async with synchronous code?
问题描述
我试图使用await/async来使一些同步代码异步.例如,这可以工作并取消阻止UI线程:
I'm trying to use await/async in order to make some synchronous code asynchronous. For example, this works and unblocks the UI thread:
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线程:
But this doesn't, and will hang the UI thread:
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()
将创建一个新线程并异步运行该方法中的所有内容,但事实并非如此.
I'm trying to understand why this is the case. I was under the impression that var task = DoRequestAsync()
will create a new thread and run everything in the method asynchronously, but that appears to not be the case.
我可以使用它来使其工作:
I can use this to make it work:
await Task.Run(() => {
var request = WebRequest.Create("http://123.123.123.123");
request.Timeout = 5000;
request.GetResponse();
});
但是,这似乎有点棘手,我不确定这是否是解决此问题的正确方法.有人知道我如何才能使用Tasks和async/await以异步方式运行一堆同步代码吗?
But this seems a bit hacky and I'm not sure if it's the right solution to this issue. Does anybody know how I can just run a bunch of synchronous code in an asynchronous way using Tasks and async/await?
推荐答案
那是正确的解决方案. WebRequest.GetResponse
不是异步方法,因此它不会返回Task.它不能异步运行.
That's the right solution. WebRequest.GetResponse
is not an async method therefore it does not return a Task. It cannot run asynchronously.
实际上,您所拥有的是(Task.Run
)可以获得的最正确,最简捷的解决方案.
Actually, what you have there is the most correct and shorthand solution you can get (with Task.Run
).
我的印象是var task = DoRequestAsync()将 创建一个新线程并异步运行方法中的所有内容, 但事实并非如此.
I was under the impression that var task = DoRequestAsync() will create a new thread and run everything in the method asynchronously, but that appears to not be the case.
这不是魔术.为了使其异步运行,必须在您的异步方法中创建一个新的Task(非线程),或者必须等待一个或多个方法),该Task返回Task
,Task<T>
或void
(这是为了事件处理程序.)
It's not magic. In order for it to run asynchronously, a new Task (not thread) must be created in your async method or it must await on one or more methods)that return either Task
, Task<T>
or void
(this is for event handlers).
您在方法return "done!";
中的最后一条语句仅返回完成的Task<string>
,结果为完成".
Your last statement in the method return "done!";
just returns a completed Task<string>
with result "done".
作为旁注,这就是HttpClient成为事实上的类HTTP请求的原因,尤其是用于与Web API互操作以及用于通用GET/POST/etc:它具有异步支持.
As a side note, this is why HttpClient is becoming the de facto class HTTP requests, especially for interoperating with web APIs but also for general purpose GETs/POSTs/etc: it has async support.
Tasks also have support to wrap Begin*/End* functions (conforming to the former asynchronous programming model - APM). You can also do:
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
}
这篇关于如何将await/async与同步代码一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!