繁体   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