2017-09-15 258 views
1

我有一个异步方法:异步和同步方法

public async Task<Foo> GetFooAsync(); 

我需要它的同步版本。事情是这样的:

public Foo GetFoo(); 

我真的不希望完全重写的GetFooAsync代码,我希望做一些诸如

public Foo GetFoo() 
{ 
    return GetFooAsync().GetAwaiter().GetResult(); 
} 

这是好主意还是这个方法有任何不明显的问题?据我所知,如果我在同步上下文中使用GetFooAsync().Result,我可能会遇到死锁问题。但是GetFooAsync().GetAwaiter().GetResult()呢?

+4

''return GetFooAsync()。Result;''? –

+1

请勿使用'.Result'使用'.GetAwaiter()。GetResult()',因为后者处理聚合异常,前者不会。 – Lloyd

+3

如果你想要一个同步版本,然后分别添加一个shync过载 – Rahul

回答

4

混合同步/异步代码可能导致死锁as described in this article(段落“异步一路”)。

问题是Task继续运行,这取决于当前SynchronizationContext。如果同步意味着如果你想有一个同步的版本,然后按顺序分别添加方法的shynchronous过载,因此目前已被调用Wait()/Result/GetResult()你正在运行陷入困境

3

在同一线程上被调度拥有SOC(分离关注)。 .C,添加过载像下面为你已经做了

public Foo GetFoo() 
{ 
    ///code body 
} 
+0

通常应该先写一个同步版本,然后修改为异步(可能带有标志),或者同步版本是否可以简单地包装在工作者线程中以进行异步操作? – samosaris

+3

@samusarin,不,如答案中所述,最好有两种不同版本的方法,即使在.NET BCL中也可以看到相同的版本 – Rahul

3

你应该躲在一个同步运行的方法,例如异步执行通过使用

Task.Run(async() => await GetFooAsync()); 

要么单独实现同步版本,要么让消费者显式同步GetFooAsync。 问题是,运行该任务将消耗工作线程,并且可用的工作者池是有限的。您可能会遇到阻止代码。所以API消费者应该意识到同步实现是异步处理的。

+0

如果将名称更改为'public Foo SynchronisedGetFooAsync()',该怎么办?所以消费者知道它只是一个异步方法的包装。 –