如何避免为异步和非异步方法编写两次相同的代码。 我目前正在使用ASP.NET,所以我目前正在使用请求线程,我很快就知道他在代码下面(应该显示我的意图),这肯定是错误的做法。
应用程序死锁,因为await关键字试图返回.Result阻塞的同一个线程。
我这样做的全部原因是避免写相同的" FindAll"代码两次。
public IEnumerable<Resource> FindAll()
{
return FindAllAsync().Result;
}
public async Task<IEnumerable<Resource>> FindAllAsync()
{
return await Context.Resources.ToListAsync();
}
那你怎么解决这个问题呢?
答案 0 :(得分:11)
如何避免为异步和非异步方法编写相同的代码两次。
在一般情况下,你不可以。
有问题的操作要么是自然异步的,要么是自然同步的。在此示例(数据库请求)中,它自然是异步的。因此,使API异步。就是这样。
Stephen Toub有一对着名的博客文章Should I expose synchronous wrappers for asynchronous methods?和Should I expose asynchronous wrappers for synchronous methods?这两个问题的简短答案是&#34;没有。&#34;
你可以做各种黑客来揭露这两种类型的API(斯蒂芬在他的帖子中涵盖了每种方法),但与缺点相比,其好处是微不足道的。
答案 1 :(得分:3)
同步和异步方法应采取不同的行动。通常这意味着同步调用应该调用作为请求的一部分阻塞的API,async应该调用“一直异步”的API
如果您不想创建完全同步的api,在您的情况下,您可以使用ConfigureAwait(false)
。
当您使用Task
标记ConfigureAwait(false)
时,您实际上说的是“不需要在同一{{await
内运行延续(SynchronizationContext
之后的代码) 1}},你可以在你当前的上下文中完成(通常是一个ThreadPool线程)“
至于第二种方法,您可以删除async
关键字并保存状态机的冗余生成:
public IEnumerable<Resource> FindAll()
{
return FindAllAsync().Result;
}
public Task<IEnumerable<Resource>> FindAllAsync()
{
return Context.Resources.ToListAsync();
}
一些阅读参考:
Stephan Cleary - Dont block on async code