在C#中能用异步来包装同步调用吗?
今天早上在地铁上看到一篇公众号文章,指出滥用async/await的两种情况。
如下:
一、在异步方法中返回Task。
错误调用代码示例:
var responseTask = Task.Run(() => client.GetServicesAsync(request)); ServiceResponse response = await responseTask;
正确调用代码示例:
1 ServiceResponse response = await client.GetServicesAsync(request);
这种确实属于滥用了异步调用了。
二、使用异步方法来包装同步方法
代码示例:
1 var responseTask = Task.Run(() => client.GetData(request));
公众号上说这种调用是有问题的,我看到这里就有点纳闷了,如果client.GetData(request)是一个耗时的操作怎么办,那不是阻塞了主线程吗。
于是我立马搜索相关资料,找到了这篇文章。
文章中指出,是可以在异步方法中包装同步调用的,但是要根据实际情况而定。
看完这篇文章,我就在想,现在的公众号写文章这么不负责吗,写得这么肯定 。
我再回到公众号上的文章,点阅读原文,进去一看,原来这两种情况是针对 Asp.Net的,他搬运的时候,把标题给精简了。
我对Web开发不熟,只是我平常在桌面开发中,肯定是需要这种包装的,否则UI线程就会卡死,界面失去响应。要不是我平常读过点书,差点被这公众号文章给骗了。
总结:
1.在服务器开发中,不要用异步方法包装同步方法,因为这只是转移了执行任务的线程,并不能带来实际性的性能提升,而且线程调度还会带来一定的开销
2.在桌面开发中,使用异步方法包装同步方法是可行的,因为某些操作会长期执行而阻塞UI。使用异步将UI线程转移到线程池执行,这点开销是值得的。
3.在桌面开发中,使用异步方法包装同步方法对并行性也很重要。 并行编程就是把一个问题分割成可以并发处理的子问题。 如果你将一个问题分割成子问题,然后串行地处理每个子问题,就没有任务并行可言,因为是在一个线程上处理。 相反,如果你通过异步调用将一个子问题转移到另一个线程,你就可以并发地处理这些子问题。 这样就可以通过包装来实现并行性。
4.平常我们在封装接口时,如果一个方法没有异步实现,就不要再去增加一个Task.Run包装的异步实现。因为这对调用者来说,并不友好。是否需要包装成异步,应该由调用者决定,我们直接给出同步实现的接口即可。

浙公网安备 33010602011771号