简体   繁体   English

在同步对象中实现异步接口

[英]Implementing Asynchronous Interfaces in Synchronous objects

In learning about asynchronous programming, I have been trying to implement an interface that applies to both Asynchronous and Synchronous classes, but I am seeing conflicting practices. 在学习异步编程时,我一直在尝试实现一个适用于异步和同步类的接口,但是我看到了相互冲突的做法。

So take for example, if I was trying to implement an ILight Interface, with methods On() and Off(). 例如,如果我尝试使用方法On()和Off()实现ILight接口。

public interface ILight
{
    void On();
    void Off();
}

With a WiredLight , the methods are synchronous, and is all quick CPU bound work. 使用WiredLight ,这些方法是同步的,并且可以快速完成CPU绑定工作。

public class WiredLight : ILight
{
    private bool _powered;

    public void On()
    {
        _powered = true;
    }

    public void Off()
    {
        _powered = false;
    }
}

But with a WirelessLight , the methods are Asynchronous, where there is IO bound work. 但是,使用WirelessLight ,这些方法是异步的,在那里有IO绑定工作。 (Here the methods do not follow the interface signature, but are implemented as async, to avoid async void.) (这里的方法不遵循接口签名,而是实现为异步,以避免异步无效。)

public class WirelessLight : ILight
{
    public async Task On()
    {
        await EnablePowerAsync();
    }

    public async Task Off()
    {
        await DisablePowerAsync();
    }
}

Reading around ( here and here ), the way to do this is just force asynchronous signatures in the interface, then all the synchronous calls would be refactored to be asynchronous (Ref: Async all the way ). 仔细阅读( 在这里这里 ),方法是在接口中强制执行异步签名,然后将所有同步调用重构为异步(参见: Async all way )。 This sounds fine to me, but I haven't really seen anything about how the synchronous methods (from WiredLight ) should be handled. 这对我来说听起来不错,但是我还没有真正了解如何处理同步方法(来自WiredLight )。 Unlike this question, there are no IO bound operations, so there is nothing to await. 问题不同,没有IO绑定操作,因此没有任何等待。 I considered wrapping them in an asynchronous call ( return Task.Run(() => { _powered = true; }); ), but this is contrary to most recommendations . 我考虑过将它们包装在一个异步调用中( return Task.Run(() => { _powered = true; }); ),但这与大多数建议相反。 I also considered simply returning an already completed task(Similar to this or this ) 我还考虑过简单地返回一个已经完成的任务(类似于thisthis

public class WiredLight : ILight
{
    public Task OnAsync()
    {
        _powered = true;
        return Task.CompletedTask;
    }
}

But presenting the method as Async when runs synchronously is lying , and also against reccomendations. 但是在同步运行时将方法表示为Async是说谎的 ,并且也反对建议。 In addition, it looks like returning a Task.CompletedTask may return the same Task to different calls. 此外,看起来好像返回Task.CompletedTask可能会将同一Task返回不同的调用。 I can't tell where this would cause problems at the moment, but it seems like something that would cause problems. 我目前无法确定这将在哪里引起问题,但似乎会导致问题。

Is there an accepted practice for implementing an async interface on a method that returns nothing and really should be synchronous ? 是否有一种在不返回任何内容的方法上实现异步接口并且实际上应该是同步的做法?

Doing something asynchronous from a synchronous method can be really dangerous. 通过同步方法进行异步操作可能非常危险。 There's no perfect way of doing that, and you may often run into deadlock of thread-starvation issues. 没有完美的方法,而且您可能经常遇到线程匮乏问题的僵局。 That's not a situation you want to find yourself in. 那不是您想陷入困境的情况。

On the other end, doing something synchronous from an asynchronous method is safe. 另一方面,从异步方法执行同步操作是安全的。 Sure, you're lying to the caller, but that's not really a problem unless he wanted execute your code in parallel (in which case, he'll simply add a Task.Run once he notices the issue, that you should also mention in the comments). 当然,您在对调用方撒谎,但这并不是真正的问题,除非他想并行执行您的代码(在这种情况下,他会简单地添加一个Task.Run一旦发现问题,您也应该在其中提到)评论)。 When awaiting a completed task, the runtime is smart enough to optimize away the call, so the performance impact for the caller is very small, negligible for most applications. 在等待完成的任务时,运行时足够智能以优化呼叫,因此对调用方的性能影响很小,对于大多数应用程序而言可以忽略不计。

So if you have a reason to think that you'll need to execute asynchronous code in one of the implementations of your interface, don't hesitate and mark it asynchronous. 因此,如果您有理由认为需要在接口的一种实现中执行异步代码,请不要犹豫并将其标记为异步。 For the implementations that are actually synchronous, returning a completed task is usually the best thing to do: 对于实际上是同步的实现,通常最好返回一个完成的任务:

public Task DoSomethingAsync()
{
    DoSomething(); 
    return Task.CompletedTask;
}

I would advise against using Task.Run inside of the method, as it would often be undesirable and can be added easily by the caller if needed. 我建议不要在方法内部使用Task.Run ,因为它通常是不希望的,并且在需要时可以由调用方轻松添加。 async in .net means that the method may finish asynchronously, not that it'll return quickly. .net中的async意味着该方法可以异步完成,而不是将其快速返回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM