异步/等待。方法的等待部分在哪里执行?

编程入门 行业动态 更新时间:2024-10-23 05:02:01
本文介绍了异步/等待。方法的等待部分在哪里执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我真的很好奇异步/等待如何使您的程序不停止。 我真的很喜欢 Stephen Cleary解释async / await的方式:我喜欢将 await视为异步等待。也就是说,异步方法会暂停直到awaitable完成(因此等待),但实际线程不会被阻塞(所以它是异步的。)

我读到异步方法可以同步工作,直到编译器遇到await关键字为止。好。 如果编译器无法找出可等待的对象,则编译器会将可等待的对象和收益控制排队到调用方法 AccessTheWebAsync 的方法中。确定。 在调用者内部(本例中为事件处理程序),处理模式继续。在等待结果之前,呼叫者可能会执行其他与 AccessTheWebAsync 结果无关的工作,或者呼叫者可能会立即等待。事件处理程序正在等待 AccessTheWebAsync ,而 AccessTheWebAsync 正在等待 GetStringAsync 。让我们看看一个msdn示例:

异步任务< int> AccessTheWebAsync() { // //您需要添加对System.Net.Http的引用以声明客户端。 HttpClient客户端=新的HttpClient(); // GetStringAsync返回一个Task< string>。这意味着当您等待 //任务时,您将获得一个字符串(urlContents)。 Task< string> getStringTask = client.GetStringAsync( msdn.microsoft); //您可以在此处进行操作,而不必依赖GetStringAsync中的字符串。 DoIndependentWork(); //等待操作符挂起AccessTheWebAsync。 // //-在getStringTask完成之前,AccessTheWebAsync无法继续。 //-同时,控制权返回给AccessTheWebAsync的调用方。 // //当getStringTask完成时,控制在此处恢复。 // //-等待操作符然后从getStringTask中检索字符串结果。 字符串urlContents =等待getStringTask; // return语句指定一个整数结果。 //任何正在等待AccessTheWebAsync的方法都将检索长度值。 return urlContents.Length; }

msdn博客上的另一篇文章说, async / await不会创建新线程或使用线程池中的其他线程。

我的问题:

  • 异步/等待在哪里执行等待的代码(在我们的示例中为下载网站)导致控件对我们程序的下一行代码产生控制权,并且程序只询问 Task< string>的结果。 getStringTask ?我们知道没有新线程,没有线程池。

  • 我是愚蠢的假设吗,CLR只是在一个线程的范围内彼此切换当前的可执行代码和方法的可等待部分?但是更改加数的顺序并不会更改总和,并且UI可能会在一段时间内被阻塞。

  • 方案

    异步/等待在哪里执行等待的代码(在我们的示例中,下载网站)导致控制权移交给我们程序的下一行代码,并且程序仅询问以下结果:任务getStringTask?我们知道没有新线程,没有使用线程池。

    如果该操作是真正异步的,则没有代码可以执行。您可以将其视为所有通过回调处理的对象。 HTTP请求被发送(同步),然后 HttpClient 注册一个回调,该回调将完成 Task< string> 。下载完成后,将调用回调,从而完成任务。

    我有一篇博客文章,其中详细介绍了异步操作如何实现无线程。

    我是不是很愚蠢地认为CLR只是在一个线程范围内将当前的可执行代码和方法的等待部分在彼此之间切换?

    这是部分正确的心理模型,但并不完整。一方面,当 async 方法恢复时,其(先前)调用堆栈不会随之恢复。因此 async / await 与纤维或协同例程,即使它们可以用来完成类似的工作

    与其将 await 视为切换到其他代码,不如将其视为返回任务不完整。如果调用方法还调用 await ,则它还会返回一个未完成的任务,等等。最终,您将把一个未完成的任务返回给框架(例如ASP.NET MVC / WebAPI / SignalR或单元测试运行器);否则您将具有 async void 方法(例如,UI事件处理程序)。

    该操作位于进度,您最终会获得任务对象的堆栈。不是真正的堆栈,而是依赖关系树。每个 async 方法均由一个任务实例表示,它们都在等待该异步操作完成。

    在哪里继续执行方法的等待部分?

    在等待任务时, await 默认情况下将在捕获的上下文中恢复其 async 方法。该上下文为 SynchronizationContext.Current ,除非它为 null ,在这种情况下为 TaskScheduler。当前。实际上,这意味着在UI线程上运行的 async 方法将在该UI线程上恢复;一个处理ASP.NET请求的 async 方法将恢复处理同一ASP.NET请求(可能在不同的线程上);在大多数情况下, async 方法将在线程池线程上恢复。

    在您的示例代码中问题, GetStringAsync 将返回不完整的任务。下载完成后,该任务将完成。因此,当 AccessTheWebAsync 对该下载任务调用 await 时(假设下载尚未完成),它将捕获它的当前上下文,然后从 AccessTheWebAsync 返回一个不完整的任务。

    下载任务完成后,继续 AccessTheWebAsync 将被安排到该上下文(UI线程,ASP.NET请求,线程池等),并将提取 Length 。当 AccessTheWebAsync 方法返回时,它将设置先前从 AccessTheWebAsync 返回的任务的结果。依次恢复下一个方法,等等。

    I am really curious how async/await enables your program not to be halted. I really like the way how Stephen Cleary explains async/await: "I like to think of "await" as an "asynchronous wait". That is to say, the async method pauses until the awaitable is complete(so it waits), but the actual thread is not blocked (so it's asynchornous)."

    I've read that async method works synchronously till compilator meets await keywords. Well. If compilator cannot figure out awaitable, then compilator queues the awaitable and yield control to the method that called method AccessTheWebAsync. OK. Inside the caller (the event handler in this example), the processing pattern continues. The caller might do other work that doesn't depend on the result from AccessTheWebAsync before awaiting that result, or the caller might await immediately. The event handler is waiting for AccessTheWebAsync, and AccessTheWebAsync is waiting for GetStringAsync. Let's see an msdn example:

    async Task<int> AccessTheWebAsync() { // You need to add a reference to System.Net.Http to declare client. HttpClient client = new HttpClient(); // GetStringAsync returns a Task<string>. That means that when you await the // task you'll get a string (urlContents). Task<string> getStringTask = client.GetStringAsync("msdn.microsoft"); // You can do work here that doesn't rely on the string from GetStringAsync. DoIndependentWork(); // The await operator suspends AccessTheWebAsync. // - AccessTheWebAsync can't continue until getStringTask is complete. // - Meanwhile, control returns to the caller of AccessTheWebAsync. // - Control resumes here when getStringTask is complete. // - The await operator then retrieves the string result from getStringTask. string urlContents = await getStringTask; // The return statement specifies an integer result. // Any methods that are awaiting AccessTheWebAsync retrieve the length value. return urlContents.Length; }

    Another article from msdn blog says that async/await does not create new thread or use other threads from thread pool. OK.

    My questions:

  • Where does async/await execute awaitable code(in our example downloading a web site) cause control yields to the next row of code of our program and program just asks result of Task<string> getStringTask? We know that no new threads, no thread pool are not used.

  • Am I right in my silly assumption that CLR just switches the current executable code and awaitable part of the method between each other in scope of one thread? But changing the order of addends does not change the sum and UI might be blocked for some unnoticeable time.

  • 解决方案

    Where does async/await execute awaitable code(in our example downloading a web site) cause control yields to the next row of code of our program and program just asks result of Task getStringTask? We know that no new threads, no thread pool are not used.

    If the operation is truly asynchronous, then there's no code to "execute". You can think of it as all being handled via callbacks; the HTTP request is sent (synchronously) and then the HttpClient registers a callback that will complete the Task<string>. When the download completes, the callback is invoked, completing the task. It's a bit more complex than this, but that's the general idea.

    I have a blog post that goes into more detail on how asynchronous operations can be threadless.

    Am I right in my silly assumption that CLR just switches the current executable code and awaitable part of the method between each other in scope of one thread?

    That's a partially true mental model, but it's incomplete. For one thing, when an async method resumes, its (former) call stack is not resumed along with it. So async/await are very different than fibers or co-routines, even though they can be used to accomplish similar things.

    Instead of thinking of await as "switch to other code", think of it as "return an incomplete task". If the calling method also calls await, then it also returns an incomplete task, etc. Eventually, you'll either return an incomplete task to a framework (e.g., ASP.NET MVC/WebAPI/SignalR, or a unit test runner); or you'll have an async void method (e.g., UI event handler).

    While the operation is in progress, you end up with a "stack" of task objects. Not a real stack, just a dependency tree. Each async method is represented by a task instance, and they're all waiting for that asynchronous operation to complete.

    Where is continuation of awaitable part of method performed?

    When awaiting a task, await will - by default - resume its async method on a captured context. This context is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. In practice, this means that an async method running on a UI thread will resume on that UI thread; an async method handling an ASP.NET request will resume handling that same ASP.NET request (possibly on a different thread); and in most other cases the async method will resume on a thread pool thread.

    In the example code for your question, GetStringAsync will return an incomplete task. When the download completes, that task will complete. So, when AccessTheWebAsync calls await on that download task, (assuming the download hasn't already finished) it will capture its current context and then return an incomplete task from AccessTheWebAsync.

    When the download task completes, the continuation of AccessTheWebAsync will be scheduled to that context (UI thread, ASP.NET request, thread pool, ...), and it will extract the Length of the result while executing in that context. When the AccessTheWebAsync method returns, it sets the result of the task previously returned from AccessTheWebAsync. This in turn will resume the next method, etc.

    更多推荐

    异步/等待。方法的等待部分在哪里执行?

    本文发布于:2023-11-10 02:19:15,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1574073.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:方法

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!