再解释异步等待这是我的事件处理程序代码:为了保持UI响应,我使用async/await方法。据我了解,我现在可以在SaveTestRunAsync()中执行一些冗长的操作而不会阻塞UI,因为它是通过使用await关键字解耦的。私有异步任务SaveTestRunAsync(){//System.Threading.Thread.Sleep(5000);-->这会阻塞UIawaitTask.Delay(5000);//这不会阻塞UIreturntrue;你能解释一下为什么对Thread.Sleep的调用仍然会阻塞UI,而Task.Delay不会吗?代码仍在UI线程上运行。它不在后台线程上运行。因此,您在异步方法中执行的任何冗长、昂贵的操作仍会在这段时间内阻塞UI。Thread.Sleep使UI线程进入休眠状态。在这种情况下,您需要了解async和await的工作原理。await基本上在这里说:我们在这里将方法分成两部分。第一部分是等待点之前执行的任何内容。第二部分是等待对象完成后应该执行的任何部分。所以,基本上,该方法一直执行到等待Task.Delay(5000);.然后它将“延迟5秒”置于播放状态并表示“安排其余代码在完成后执行”。然后它返回以便UI线程可以继续发送消息。一旦5秒结束,UI线程将执行该方法的其余部分。基本上,如果您正在执行异步I/O,这很好,但如果您正在执行昂贵的操作(如处理大型数据集或类似操作),则不太好。那你怎么能这样做呢?您可以使用Task.Run。这将启动另一个线程来执行给它的委托,同时UI线程可以自由地做其他事情。基本上你可以想到一个使用await的方法:Lifeofmethod:Parts:[startofmethod----][awaitable][restofmethod-----]所以方法会执行第一部分,直到到达awaitX,然后它将检查X是否已完成,如果没有,它将设置一些Task对象,使可等待对象能够运行,一旦完成,“方法的其余部分”将运行。如果X已经完成,也许它是一个已经完成的异步I/O操作,或者它完成得非常快,那么该方法将继续执行该方法的其余部分,就像您在那里写了await而没有await一样。但如果没有,那么它会返回。这很重要,因为它允许UI线程(在本例中)返回给用户以获取鼠标点击等消息。一旦等待那个“等待对象”的任务被告知等待已经完成,“方法的其余部分”就会被安排,基本上(在这种情况下)将消息放在消息队列中,要求它执行其余的方法。这个方法中的await语句越多,基本上它只是将方法分解成更多的部分。您可以使用早期.NET版本中引入的Task类来完成所有这些工作。async/await的全部意义在于使编写代码更容易,因为将代码包装在任务对象中具有将代码转换为内部代码的不幸效果,并且难以处理异常和循环之类的事情。据我了解,我现在可以在SaveTestRunAsync()中执行一些冗长的操作而不会阻塞UI,因为它是通过使用await关键字解耦的。async/await并不意味着您可以在不阻塞UI的情况下执行“冗长的操作”。相反,当您使用await时,您不会在内部排队等待在另一个线程上完成的工作,您的代码将继续在同一个线程(在您的情况下是UI线程)上执行,直到内部await被命中并且您返回调用经过。Thread.Sleep和Task.Delay之间的区别在于,前者是一个阻塞调用,它将暂停您的UI线程,直到指定的时间过去。后者将在内部使用Timer并将控制权返回给调用方法。一旦该计时器的时钟已经过去,它将从它停止的地方继续执行(这就是编译器魔术的用武之地)Await不创建线程或任务,它“简单地”调用等待的函数(不应该阻塞,否则调用者将阻塞,因为它仍然是同步的),要求编译器为返回的任务生成一个继续等待函数,包含等待之后的代码的“其余部分”,并向调用者返回一个新任务(如果等待函数返回一个任务)。当继续完成时,任务将指示为已完成。该框架确保延续将在UI线程上运行(如果应用程序有一个线程),如果您希望能够从异步函数访问UI元素,这是必须的。所以异步函数不应该包含阻塞调用。应使用Task.Run()将阻塞调用“包装”在任务中。Async/await是比线程更高级别的抽象。一个真正的实现可以使用异步工作线程,但它可以(并且经常)在同一个线程中使用其他同步技术。因此,如果async/await的当前实现不是基于线程的,则调用Thread.Sleep将阻塞UI线程。相关阅读:关于SynchronizationContext的所有内容。以上就是C#学习教程:详解async的全部内容等待再次分享。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
