首页 文章

无法理解异步并等待

提问于
浏览
6

我一直试图理解as#/ await和C#中的任务,但是尽管观看了YouTube视频,阅读文档和遵循复数课程,但仍然失败了 .

我希望有人可以帮助回答这些略微抽象的问题,以帮助我的大脑 .

1.为什么他们说async / await在它自己的async关键字什么都不做并且await关键字添加一个暂停点时启用'asynchonrous'方法?不是添加一个暂停点,强制该方法同步操作,即在继续之前完成await标记的任务 .

2.显然除了事件处理程序之外你不应该使用async void,那么你如何正常调用异步方法呢?似乎为了使用await关键字调用异步方法,调用它本身的方法/类需要标记为async . 我见过的所有示例都“启动”了一个带有事件处理程序的异步void方法 . 你如何“逃避”async / await的包装以运行该方法?

3 .

public async Task SaveScreenshot(string filename, IWebDriver driver)
{
    var screenshot = driver.TakeScreenshot();
    await Task.Run(() =>
    {
        Thread.Sleep(2000);
        screenshot.SaveAsFile(filename, ScreenshotImageFormat.Bmp);
        Console.WriteLine("Screenshot saved");
    });
    Console.WriteLine("End of method");
}

回到1.这看起来像一个同步方法 . 当执行到 Task.Run 时执行暂停,因此在任务完成之前不会执行 Console.WriteLine("End of method"); . 也许整个方法本身将在代码中触发它时异步执行?但是回到2,你需要等待调用它,否则你得到消息'Because this call is not awaited..'因此添加await会导致执行点同步等等 .

任何帮助理解这一点将非常感激 .

3 回答

  • 3

    不添加暂停点,强制该方法同步操作,即在继续之前完成await标记的任务 .

    不,你想到的这个词是"sequential",而不是"synchronous" . await 导致异步顺序代码 . "Sequential"的意思"one at a time"; "synchronous"含义"blocking until completed" .

    你如何正常调用异步方法?

    使用 await .

    你将如何“逃避”async / await的包装以运行该方法?

    理想情况下,你 don't . 你去async all the way . 现代框架(包括ASP.NET MVC,Azure Functions / WebJobs,NUnit / xUnit / MSTest等)都允许您拥有返回 Task 的入口点 . 不太现代的框架(包括WinForms,WPF,Xamarin Forms,ASP.NET WebForms等)都允许 async void 入口点 .

    因此,理想情况下,您不会从同步代码中调用异步代码 . 如果你考虑异步代码 is 这是有意义的:它的全部意义是不阻塞调用线程,所以如果你阻塞异步代码上的调用线程,那么你首先会失去异步代码的所有好处 .

    也就是说,在极少数情况下您需要同步处理代码 . 例如,如果您正处于异步转换的过程中,或者您受到强制您的代码同步且不能与 async void 一起使用的库/框架的约束 . 在这种情况下,您可以使用hacks in my article on brownfield async之一 .

  • 8

    你的理解非常好:) . 您似乎缺少的主要观点是.NET中的“异步”方法意味着可以在不阻塞调用线程的情况下停止执行的方法 .

    正如您在(1)中指出的那样, async 关键字基本上允许使用 await ,并且要求返回类型为 voidTask/Task<T> . await 只是指示当前方法暂停执行,直到任务完成 .

    你在这里缺少的是它暂停 just the current method . 它不会阻止方法执行的线程 . 这在像WPF应用程序的UI线程这样的情况下很重要 . 挂起方法执行,一切都继续运行,阻塞线程,应用程序停止响应 .

    您通常希望 async 调用一直到顶部(如事件处理程序),这允许最大的灵活性并防止死锁情况 . 然而;您可以等待 Task 返回方法完成 Wait

    someAsyncMethod.Wait()
    

    或者获得返回值:

    var result = someAsyncMethod.Result;
    

    请注意,这两个都是同步的并阻止调用线程 . 如果异步任务正在等待调用线程上的其他一些工作完成,这样做可能会导致死锁 .

    以上内容应在(3)中回答您的问题;方法本身似乎同步执行(这是 await/async 的魔力),但任务不会阻止调用线程 .

  • 2

    它是异步,因为您不必等待方法返回 . 在您的代码中,您可以调用异步方法并将任务保存在变量中 . 继续做其他事情 . 之后,当需要方法结果时,等待响应(任务) .

    // Synchronous method.
    static void Main(string[] args)
    {
        // Call async methods, but don't await them until needed.
        Task<string> task1 = DoAsync();
        Task<string> task2 = DoAsync();
        Task<string> task3 = DoAsync();
    
        // Do other stuff.
    
        // Now, it is time to await the async methods to finish.
        Task.WaitAll(task1, task2, task3);
    
        // Do something with the results.
        Console.WriteLine(task1.Result);
        Console.ReadKey();
    }
    
    private static async Task<string> DoAsync()
    {
        Console.WriteLine("Started");
        await Task.Delay(3000);
        Console.WriteLine("Finished");
    
        return "Success";
    }
    
    // Output:
    // Started
    // Started
    // Started
    // Finished
    // Finished
    // Finished
    // Success
    

相关问题