我不太了解与线程相比的async / await好处。
如果在方法内部,我有一个没有async / await版本的操作,在其他异步操作的中间消耗一些时间,比如20ms。
调用此方法1000次,因为async / await仅在一个线程内执行,它将在我的测试中使用至少20ms x 1000次(使用Thread.Sleep进行模拟)。
是否有关于async / await的误解?
public void Start()
{
Task[] task = new Task[500];
for (int i = 0; i < 500; i++)
{
task[i] = AsyncGet();
}
await Task.WhenAll(task);
}
public async Task<bool> AsyncGet()
{
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://www.example.com");
req.Method = "GET";
using(HttpWebResponse res = (HttpWebResponse)await req.GetResponseAsync())
{
Thread.Sleep(20);//Simulate an operation without async/await version that consume a little bit time
using (Stream responseStream = res.GetResponseStream())
{
StreamReader sr = new StreamReader(responseStream, Encoding.ASCII);
string resp = await sr.ReadToEndAsync();
}
}
}
更新问题:
如果我需要做一些非异步/等待操作,比如在使用外部库获取http响应后操纵json。什么是避免浪费时间的最佳做法?
答案 0 :(得分:4)
不,不一定。如果您从单个线程的 SynchronizationContext 调用Start
方法(比如说任何UI上下文,如WindowsFormsSynchronizationContext或DispatcherSynchronizationContext),则答案为是[*]。
如果从其他线程(比如工作线程)调用Start
。它不会花费 20ms x 1000 。因为在那种情况下,等待后的代码将在ThreadPool thread中执行。因此,在等待之后可以有N个线程执行代码。在你的情况下,N将小于或等于500。
那就是说,你不应该阻止异步方法。如果您需要在异步方法中使用任何同步代码,则应使用await Task.Run(()=> CodeThatBlocks())
* 如果SynchronizationContext.SetSynchronizationContext
不覆盖SynchronizationContext
答案 1 :(得分:2)
是否有关于async / await的误解?
是的,你似乎有误会。您无法使用阻止呼叫async-await
来模拟Thread.Sleep
行为。当您await Task.WhenAll
时,多个异步请求会同时执行,而忽略底层线程。
如果您想同时卸载多个请求,请使用await Task.Delay
对其进行测试,您会注意到行为的变化。
您可以更进一步,在调用ConfigureAwait(false)
时使用GetResponseAsync
,这样您的方法的继续不会将工作重新编写回原SynchronizationContext
(这在处理自定义时很重要诸如WinFormSynchronizationContext之类的并继续在IOCP上执行。
答案 2 :(得分:0)
无论是否有异步/等待结构,休眠线程仍然会在线程中休眠。使用async / await的想法是尽可能保持每个线程都被占用,以避免在等待I / O时创建大量线程。在后台执行CPU密集型操作仍然需要您创建线程。
换句话说,您提供的示例将导致线程冻结20毫秒,无论它是否是async / await的预期用例。
换句话说,要么: