我一直在尝试理解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,你需要等待调用它,否则你得到消息'因为这个调用是不等的......'因此添加await会导致执行点同步等等。
非常感谢任何理解这一点的帮助。
答案 0 :(得分:8)
是否添加了暂停点,强制该方法同步操作,即在继续之前完成await标记的任务。
不,你想到的这个词是"顺序"而不是"同步"。 await
导致异步顺序代码。 "序列"意思是"一次一个&#34 ;; "同步"意思是"阻塞直到完成"。
如何正常调用异步方法?
使用await
。
你将如何逃避'这个包装的async / await来运行方法吗?
理想情况下,您不。你去async all the way。现代框架(包括ASP.NET MVC,Azure Functions / WebJobs,NUnit / xUnit / MSTest等)都允许您拥有返回Task
的入口点。不太现代的框架(包括WinForms,WPF,Xamarin Forms,ASP.NET WebForms等)都允许async void
个入口点。
因此,理想情况下,不从同步代码中调用异步代码。如果您考虑异步代码 ,这是有道理的:它的全部内容是不阻塞调用线程,因此如果您阻止异步代码上的调用线程,那么你首先会失去异步代码的所有好处。
尽管如此,在极少数情况下您需要同步处理代码。例如,如果您正处于转换为异步的过程中,或者您受到强制您的代码同步并且不能使用{{1 }}。在这种情况下,您可以使用其中一个hacks in my article on brownfield async。
答案 1 :(得分:3)
你的理解非常好:)。你似乎缺少的主要观点是"异步" .NET中的方法意味着可以在不阻塞调用线程的情况下停止执行的方法。
正如您在(1)中指出的那样,async
关键字基本上允许使用await
,并且要求返回类型为void
或Task/Task<T>
。 await
只是指示当前方法暂停执行,直到任务完成。
这里缺少的是它暂停当前方法。它不阻止该方法正在执行的线程。这在像WPF应用程序的UI线程这样的情况下很重要。挂起方法执行,一切都继续运行,阻塞线程,应用程序停止响应。
您通常希望async
调用一直到顶部(如事件处理程序),这样可以提供最大的灵活性并防止出现死锁情况。然而;您可以等待Task
返回方法完成Wait
:
someAsyncMethod.Wait()
或者获得返回值:
var result = someAsyncMethod.Result;
请注意,这两个都是同步并阻止调用线程。如果异步任务正在等待调用线程上的其他一些工作完成,这样做可能会导致死锁。
上述内容应在(3)中回答您的问题;方法本身似乎同步执行(这是await/async
的神奇之处),但任务不会阻止调用线程。
答案 2 :(得分: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