栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如果async-await没有创建任何其他线程,那么它如何使应用程序响应?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如果async-await没有创建任何其他线程,那么它如何使应用程序响应?

实际上,异步/等待并不是那么神奇。整个主题非常广泛,但是对于您的问题,我想我们可以解决,但需要快速而完整的答案。

让我们处理一个Windows Forms应用程序中的简单按钮单击事件:

public async void button1_Click(object sender, EventArgs e){    Console.WriteLine("before awaiting");    await GetSomethingAsync();    Console.WriteLine("after awaiting");}

我要 明确 不是 谈论什么它

GetSomethingAsync
是返回现在。我们只说这将在2秒后完成。

在传统的非异步环境中,您的按钮单击事件处理程序将如下所示:

public void button1_Click(object sender, EventArgs e){    Console.WriteLine("before waiting");    DoSomethingThatTakes2Seconds();    Console.WriteLine("after waiting");}

当您单击表单中的按钮时,该应用程序将冻结约2秒钟,而我们等待此方法完成。发生的事情是基本上阻塞了一个“消息泵”,使其成为一个循环。

该循环不断询问Windows:“是否有人做过某些事情,例如移动鼠标,单击某些东西?我需要重新粉刷一些东西吗?如果是,请告诉我!”
然后处理那个“东西”。此循环收到一条消息,提示用户单击“
button1”(或Windows中的等效消息类型),并最终调用了

button1_Click
上面的方法。在此方法返回之前,此循环现在一直处于等待状态。这需要2秒钟,在此期间,不会处理任何消息。

与窗口打交道的大多数事情都是使用消息完成的,这意味着,如果消息循环停止泵送消息,即使只是一秒钟,用户很快就会注意到它。例如,如果将记事本或任何其他程序移到自己程序的顶部,然后再次移开,则会向您的程序发送一连串的绘画消息,指示现在突然又可以看到的窗口区域。如果处理这些消息的消息循环正在等待某些东西(已阻塞),则不会完成绘制。

那么,如果在第一个示例中,

async/await
不创建新线程,它将如何做呢?

好吧,发生的是您的方法被一分为二。这是那些广泛的主题类型之一,因此我将不做过多的详细说明,但足以说明该方法分为以下两种情况:

  1. 直至的所有代码
    await
    ,包括对
    GetSomethingAsync
  2. 以下所有代码
    await

插图:

pre... pre... pre... await X(); ... pre... pre... pre...

重新排列:

pre... pre... pre... var x = X(); await X; pre... pre... pre...^ ^          ^          ^+---- portion 1 -------------------+          +---- portion 2 ------+

基本上,该方法执行如下:

  1. 它执行一切,直到
    await
  2. 它调用该
    GetSomethingAsync
    方法,该方法将执行其操作,并返回 将在未来2秒内完成的操作

到目前为止,我们仍然位于对message1调用的主线程上对button1_Click的原始调用内。
如果导致代码

await
花费大量时间,则UI仍将冻结。在我们的示例中,没有那么多

  1. 什么
    await
    关键字,一些聪明的编译器魔术一起,确实是它基本上像“好吧,你知道吗,我会简单地从这里按钮单击事件处理程序返回,当你(在,事情我们”重新等待),直到完成为止,让我知道,因为我还有一些代码需要执行。”

实际上,它将使 SynchronizationContext类知道已完成,这将根据当前正在运行的实际同步上下文排队等待执行。Windows
Forms程序中使用的上下文类将使用消息循环正在泵送的队列对其进行排队。

  1. 因此,它返回到消息循环,现在可以自由继续发送消息,例如移动窗口,调整窗口大小或单击其他按钮。

对于用户而言,UI现在可以再次响应,可以处理其他按钮单击,调整大小,最重要的是可以 重新绘制 ,因此它似乎不会冻结。

  1. 2秒钟后,我们等待的事情完成了,现在发生的事情是,它(同步上下文)将一条消息放入了消息循环正在查看的队列中,并说:“嘿,我还有更多代码可用于您执行”,而这段代码就是等待 的所有代码。
  2. 当消息循环到达该消息时,它基本上会在中断后的地方重新“进入”该方法,
    await
    然后继续执行该方法的其余部分。请注意,此代码再次从消息循环中调用,因此,如果此代码恰好长时间执行而未
    async/await
    正确使用,它将再次阻塞消息循环

这里有很多活动部件,因此这里有一些指向更多信息的链接,我想说的是“您是否需要它”,但是该主题涉及 很广,了解 其中一些活动部件
非常重要。您将始终了解异步/等待仍然是一个漏水的概念。一些潜在的局限性和问题仍然会泄漏到周围的代码中,如果没有,您通常最终不得不调试似乎无缘无故地随机中断的应用程序。

  • 使用Async和Await进行异步编程(C#和Visual Basic)
  • SynchronizationContext类
  • Stephen Cleary-没有线程 值得一读!
  • 频道9-Mads Torgersen:在C#Async内部 非常值得一看!

OK,那么如果

GetSomethingAsync
启动一个将在2秒内完成的线程该怎么办?是的,那么显然有一个新的线索在起作用。但是,此线程不是 由于
此方法的异步性,而是因为此方法的程序员选择了一个线程来实现异步代码。几乎所有异步I / O 都不
使用线程,它们使用不同的东西。
async/await
本身 不会增加新线程,但是显然“等待的事情”可以使用线程来实现。

.NET中有很多东西不一定独立运行一个线程,但它们仍然是异步的:

  • Web请求(以及许多其他与网络相关的事情,这需要时间)
  • 异步文件读写
  • 还有更多的好兆头是,如果所讨论的类/接口具有名为
    SomethingSomethingAsync
    BeginSomething
    和的方法,
    EndSomething
    并且
    IAsyncResult
    涉及其中。

通常,这些东西不使用引擎盖下的螺纹。


好吧,所以您想要一些“广泛的主题”?

好吧,让我们向Roslyn咨询一下我们的按钮单击:

尝试罗斯林

我不会在这里链接完整的生成类,但这是很糟糕的事情。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/415341.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号