2017-09-15 218 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()',該怎麼辦?所以消費者知道它只是一個異步方法的包裝。 –