Реализация асинхронных интерфейсов в синхронных объектах - PullRequest
0 голосов
/ 25 мая 2018

Изучая асинхронное программирование, я пытался реализовать интерфейс, который применяется как к асинхронным, так и к синхронным классам, но я вижу противоречивые практики.

Так что, например, если я пытался реализоватьILight Интерфейс с методами On () и Off ().

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

При WiredLight методы являются синхронными и все работают с быстрым ограничением ЦП.

public class WiredLight : ILight
{
    private bool _powered;

    public void On()
    {
        _powered = true;
    }

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

Но с WirelessLight методы асинхронные, где есть работа, связанная с IO.(Здесь методы не следуют подписи интерфейса, но реализованы как асинхронные, чтобы избежать асинхронной пустоты.)

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

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

Чтение вокруг ( здесь и здесь ), способ сделать это - просто принудительно установить асинхронные подписи в интерфейсе, тогда все синхронные вызовы будут подвергнуты рефакторингу, чтобы стать асинхронными (Ref: Async all the way ).Это звучит нормально для меня, но я действительно не видел ничего о том, как должны обрабатываться синхронные методы (из WiredLight).В отличие от этого вопроса, операции ввода-вывода не связаны, поэтому ждать нечего.Я подумал об их упаковке в асинхронный вызов (return Task.Run(() => { _powered = true; });), но это противоречит большинству рекомендаций .Я также подумал о том, чтобы просто вернуть уже выполненную задачу (аналогично this или this )

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

Но представление метода в асинхронном режиме при синхронном запуске - ложь , а также против рекомендаций.Кроме того, похоже, что возврат Task.CompletedTask может возвращать одну и ту же задачу различным вызовам.Я не могу сказать, где это может вызвать проблемы в данный момент, но кажется, что это может вызвать проблемы.

Существует ли принятая практика для реализации асинхронного интерфейса для метода, который ничего не возвращает и действительно должен быть синхронным ?

1 Ответ

0 голосов
/ 25 мая 2018

Выполнение чего-либо асинхронного из синхронного метода может быть действительно опасным.Не существует идеального способа сделать это, и вы часто можете столкнуться с тупиковой проблемой истощения потоков.Это не та ситуация, в которой вы хотите оказаться.

С другой стороны, синхронное выполнение асинхронного метода безопасно.Конечно, вы лжете звонящему, но это не проблема, если он не хочет выполнить ваш код параллельно (в этом случае он просто добавит Task.Run, как только заметит проблему, которую вы также должны упомянуть вкомментарии).В ожидании выполненной задачи среда выполнения достаточно умна, чтобы оптимизировать вызов, поэтому влияние на производительность для вызывающего абонента очень мало и незначительно для большинства приложений.

Так что, если у вас есть причина думать, чтоВам нужно будет выполнить асинхронный код в одной из реализаций вашего интерфейса, не стесняйтесь и пометьте его как асинхронный.Для реализаций, которые на самом деле являются синхронными, обычно лучше всего возвращать выполненную задачу:

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

Я бы посоветовал не использовать Task.Run внутри метода, так как это часто нежелательно и можетможет быть добавлено вызывающим абонентом в случае необходимости.async в .net означает, что метод может завершиться асинхронно, но не так, что он быстро вернется.

...