簡體   English   中英

合同異步和同步代碼

[英]Contractual async and sync code

有很多問題詢問是否要混合異步代碼和同步代碼。

大多數答案都說,為異步方法公開同步包裝,為同步方法公開異步包裝是一個壞主意。

但是,沒有一個答案能解決您必須混合使用異步和同步代碼的特定情況,以及如何避免由於該問題而引起的常見陷阱。

請參見以下示例:

class Program
{
    static void Main(string[] args)
    {
        IContract signatory = new SyncSignatory();
        signatory.FullfillContractAsync().Wait();
        signatory = new AsyncSignatory();
        signatory.FullfillContractAsync().Wait();
    }
}

using System.Threading.Tasks;

interface IContract
{
    Task FullfillContractAsync();
}

using System.Threading.Tasks;

class AsyncSignatory : IContract
{
    public async Task FullfillContractAsync()
    {
        await Task.Delay(5000);
    }
}

using System.Threading;
using System.Threading.Tasks;

class SyncSignatory : IContract
{
    public Task FullfillContractAsync()
    {
        Thread.Sleep(5000);
        return Task.FromResult<object>(null);
    }
}

要么:

using System.Threading;
using System.Threading.Tasks;

class SyncSignatory : IContract
{
    public Task FullfillContractAsync()
    {
        return Task.Run(() => Thread.Sleep(5000));
    }
}

在此示例中,SyncSignatory和AsyncSignatory代表兩個可互換的類,因為它們執行相似的功能,但是它們以不同的方式(同步和異步)執行這些功能。

如何在避免常見陷阱的情況下混合合同同步代碼和異步代碼?

希望syncSig運行異步但運行同步的用戶呢?

可以通過異步運行來優化syncSig的用戶又如何呢?由於假設他們已經異步運行而不再進行優化,該怎么辦?

這是混合異步和同步的正確方法嗎?

通常是的。 如果您有一個公共接口,則其中的某些實現將能夠提供同步的實現,而其他實現僅是異步的,則返回Task<T>是有意義的。 一個簡單的return Task.FromResult可能是合適的。 但是也有例外,請參見下文。

希望syncSig運行異步但運行同步的用戶呢?

接口的某些方面無法用代碼表示。

如果您的IContract要求它在返回Task之前不阻塞調用線程的時間不超過X毫秒(以這種確切形式,這不是一個合理的硬性要求,但是您已經掌握了基本思想),並且無論如何它都會阻塞該線程,這是違反合同的行為,用戶應將其作為錯誤報告給實施了syncSig的任何人。

如果IContract要求不引發同步異常,則必須使用Task.FromException或等效方法報告任何錯誤,而syncSig仍然引發同步異常,這也違反了合同。

除此之外,如果syncSig只是立即返回正確的結果,那么沒有理由為什么會打擾任何用戶。

可以通過異步運行來優化syncSig的用戶又如何呢?由於假設他們已經異步運行而不再進行優化,該怎么辦?

如果syncSig同步運行不會引起任何問題,那么沒關系,還不需要進行優化。

如果同步運行的syncSig確實引起了問題,則基本調試工具應盡快告知開發人員syncSig引起了問題,應進行調查。

但是,沒有一個答案能解決您必須混合使用異步和同步代碼的特定情況,以及如何避免由於該問題而引起的常見陷阱。

那是因為這是一個壞主意。 任何混合代碼本質上都應該是完全臨時的,僅在過渡到異步API時才存在。

就是說,我已經寫了整篇文章

如何在避免常見陷阱的情況下混合合同同步代碼和異步代碼?

正如我在異步接口博客文章中所描述的那樣, async是實現細節。 任務返回方法可以同步完成。 但是,我建議避免阻塞實現。 如果由於某種原因無法避免它們,那么我會仔細記錄它們的存在。

另外,您可以使用Task.Run作為實現; 我不建議這樣做(原因詳細的在我的博客 ),但如果你必須有一個阻擋實現它是一個選項。

希望syncSig運行異步但運行同步的用戶呢?

調用線程被同步阻止。 這通常只是UI線程的問題-參見下文。

可以通過異步運行來優化syncSig的用戶又如何呢?由於假設他們已經異步運行而不再進行優化,該怎么辦?

如果調用代碼是ASP.NET,則應直接調用它並await 同步代碼將被同步執行,這在該平台上是理想的。

如果調用代碼是UI應用程序,則需要知道存在同步實現,並且可以將其包裝在Task.Run 這樣可以避免阻塞UI線程,而不管實現是同步還是異步。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM