异步和同步方法[重复]
Posted
技术标签:
【中文标题】异步和同步方法[重复]【英文标题】:Asynchronous and synchronous methods [duplicate] 【发布时间】:2018-02-24 15:56:10 【问题描述】:我有一个异步方法:
public async Task<Foo> GetFooAsync();
我需要它的同步版本。像这样的:
public Foo GetFoo();
我真的不想完全重写GetFooAsync
的代码,我想做一些事情,比如
public Foo GetFoo()
return GetFooAsync().GetAwaiter().GetResult();
这是个好主意还是这种方法有什么不明显的问题?据我所知,如果我在同步上下文中使用GetFooAsync().Result
,我可能会遇到死锁。但是GetFooAsync().GetAwaiter().GetResult()
呢?
【问题讨论】:
return GetFooAsync().Result;
?
不要使用.Result
使用.GetAwaiter().GetResult()
,因为后者处理聚合异常,前者不处理。
如果你想要一个同步版本然后单独添加一个 shync 重载
@Rahul 显然我不明白。你能用一个例子来解释你的想法吗?
我同意 Rahul 的观点,不要用同步调用来包装你的异步方法。咬紧牙关改写吧。
【参考方案1】:
混合同步/异步代码可能会导致死锁as described in this article(“一路异步”段落)。
问题是Task
延续运行的地方,这取决于当前的SynchronizationContext
。如果同步计划安排在当前因调用Wait()
/Result
/GetResult()
而被阻塞的同一线程上,那么您将遇到麻烦
【讨论】:
【参考方案2】:如果您想要一个同步版本,请单独添加该方法的同步重载,以获得 SOC(关注点分离)。 I.c,像下面这样添加一个你已经完成的重载
public Foo GetFoo()
///code body
【讨论】:
一般来说,应该先写一个同步版本,然后修改为异步(可能带有标志),还是可以简单地将同步版本包装在一个工作线程中进行异步? @samusarin,不,如回答中所述,最好有两个不同版本的方法,即使在 .NET BCL 中也可以看到相同的版本【参考方案3】:您应该不将异步实现隐藏在同步运行的方法后面,例如通过使用
Task.Run(async () => await GetFooAsync());
要么单独实现同步版本,要么让消费者显式同步 GetFooAsync。 问题是,运行任务将消耗工作线程并且可用工作人员池是有限的。您可能会遇到阻塞代码。所以 API 使用者应该知道同步实现是异步处理的。
【讨论】:
如果你把名字改成public Foo SynchronisedGetFooAsync()
怎么办?这样消费者就知道它只是一个异步方法的包装器。以上是关于异步和同步方法[重复]的主要内容,如果未能解决你的问题,请参考以下文章