如何正确创建一个等待的方法
我正在写一些等待的方法,我在互联网上找到了很多方法。 所以我来到这里是为了了解每一条路上到底发生了什么,以及是否必须放弃某些方法。
据我所知,有两种等待方法:
那些称其他等待方法的人:
public async Task GetFooAsync() { var foo = await TrulyGetFooAsync(); // Do stuff with foo return foo; }
我没有找到任何其他方法来做到这一点,我认为这是正确的方法。 告诉我,如果我错了!
那些只称不可等待方法的人:
这里出现了问题。
例如,我看到了这个:
例1
public async Task GetFooAsync() { return await Task.Run(() => TrulyGetFoo()); }
据我所知,async / await关键字是无用的,可以避免这样做:
例2
public Task GetFooAsync() { return Task.Run(() => TrulyGetFoo()); }
最后一个例子是我到目前为止所做的事情。 关于那,是否有区别:
Task.Run(() => TrulyGetFoo());
和
Task.Run((Foo)TrulyGetFoo); // I don't know if the cast is required at any time but in my code, it was
???
但我最近发现了这种方式:
例3
public Task GetFooAsync() { TaskCompletionSource tcs = new TaskCompletionSource(); tcs.SetResult(TrulyGetFoo()); return tcs.Task; }
如果我理解正确,一个等待的方法并不总是在另一个线程上运行??? 我的猜测是第三个例子是提供这种机制(但是如何?我只在第三个例子中看到同步代码),当示例1和2将始终在工作线程上运行时???
可能还有另外一种方法来编写等待方法,所以让我知道它们。
例如,我看到[
Task.Run
包装同步代码]
这是一种不好的做法 。 我有一篇博客文章解释了为什么Task.Run
应该将Task.Run
用作方法实现 。
据我所知,async / await关键字是无用的,可以避免
是的,但我不建议在更复杂的方法中使用async
/ await
。
我最近发现[
TaskCompletionSource
]
如评论中所述,您的代码示例仍然是同步的。
要使其异步,您的代码应该启动一些操作并返回TaskCompletionSource
。 然后,只要该操作完成,您的完成处理程序应该调用TaskCompletionSource
(或类似方法)。 有关示例,请参阅EAP的 TAP包装器或WaitHandle
的TAP包装器 。
TaskFactory.FromAsync
也是TaskCompletionSource
包装器,用于APM的TAP包装器 。
简短版本是这样的: 在async
代码块中可以等待返回任务的任何内容 。
public async Task MyAsyncMethod() { // do some stuff await TrulyAsyncFoo(); // do some other stuff return; }
如果等待异步调用是该方法唯一的做法,您可以简单地返回任务本身,这将等待“上游”:
public Task MyAsyncMethod() { return TrulyAsyncFoo(); }
至于在异步方法中调用同步(非异步)代码,它没有任何内容。 只需像普通代码一样调用它:
public async Task MyAsyncMethod() { MySyncMethod(); await TrulyAsyncFoo(); MyOtherSyncMethod(); }
执行Task.Run(() => Foo())
几乎总是代码气味,你没有做异步/等待权。 编写异步代码与编写multithreading代码不同。 Async只是告诉编译器您需要等待某个网络或IO绑定任务完成的好方法。
总结一下:
- Await允许您并排编写异步和同步代码
- 异步应仅用于等待网络或IO绑定任务,而不是计算绑定任务
- 异步方法应始终返回
Task
或Task
- 避免
async void
- 除非您知道自己在做什么,否则请避免在ASP.NET和其他线程应用程序中使用
task.Wait()
和task.Result
进行阻塞
我正在使用它来处理操作我的数据库的异步事件
private async void btnSave_Click(object sender, EventArgs e) { success = await someClass.someMethod(some args); }
而someMethod是这样的任务:
public static async Task someMethod(args) { //do something here }