Вложение и наследование асинхронных/задач

#c# #.net #async-await #cross-platform

#c# #.net #асинхронность-ожидание #кроссплатформенный

Вопрос:

Я работаю над PCL, у которого есть async API (я новичок в этой теме). Из исследования, которое я провел в Интернете, я запутался в поведении и последствиях дизайна. Скажем, приложение использует некоторый API точки входа, который оборачивает некоторый абстрактный нижний уровень для доступа к файлам. Предположим, что этот код выполняется на стороне клиента.

 public interface IFileProcessor
{
    Task ProcessFile(string filename);
}

public class MyFileProcessor : IFileProcessor
{
    // Adapter can be SomeAdapter or SomeOtherAdapter
    private IMyAdapter _adapter;

    public Task ProcessFile(string filename)
    {
        File file = await _adapter.GetFileAsync(filename).ConfigureAwait(false);

        // Some CPU bound operation
        DoSomeWorkOnFile(file);

        await _adapter.SaveAsync(file);
    }

    private void DoSomeWorkOnFile(File file)
    {
        // do some CPU heavy work here
    }
}

internal interface IMyAdapter
{
    Task<File> GetFileAsync(string filename);
    Task SaveAsync(File file);
}

// Some adapter for a client that has an async API and is mainly I/O bound
internal class SomeAdapter : IMyAdapter
{
    private SomeClient _client;

    public async Task<File> GetFileAsync(string filename)
    {
        // Fetch from server or something
        return await _client.SearchForFileAsync(filename).ConfigureAwait(false);
    }

    public async Task SaveAsync(File file)
    {
        // Push to server or something
        await _client.SaveFileAsync(file).ConfigureAwait(false);
    }
}
  

Но, скажем, у меня есть другой адаптер, у которого нет async API, и его операции блокируются:

 // Some adapter for a client that has no async API and is mainly I/O bound
internal class SomeOtherAdapter : IMyAdapter
{
    private SomeOtherClient _client;

    // Don't declare as async since it can't await?
    public Task<File> GetFileAsync(string filename)
    {
        // Read from disk or something
        File file = _client.GetFile(filename);
        return Task.FromResult(file);
    }

    public Task SaveAsync(File file)
    {
        // Write to disk or something
        _client.Save(file);
    }
}
  
  • SomeOtherAdapter Есть ли какая-либо бизнес-реализация IMyAdapter , несмотря на различия в поведении?
  • Есть ли какая-либо выгода в том, что IMyAdapter возвращает Task типы? Предположительно, приложение вызывает await MyFileProcessor.DoSomeWorkAsync(...) , так зачем позволять адаптерам быть async ?
  • Эти операции в основном связаны с вводом-выводом, а не с процессором — должно ли это повлиять на мое решение о том, как я буду разрабатывать эти компоненты?

Я знаю, что трудно уловить основной вопрос на простом примере, поэтому приношу свои извинения, если приведенный мной пример слишком тривиален, чтобы прояснить мои вопросы.

Дополнительный вопрос: если MyFileProcessor не нужно выполнять какую-либо работу, связанную с процессором, есть ли какая-либо польза от использования async вообще?

Ответ №1:

Есть ли у SomeOtherAdapter какой-либо бизнес, реализующий IMyAdapter, несмотря на различия в поведении?

ДА. Когда вы имеете дело с интерфейсами, метод, возвращающий задачу, указывает, что он может возможно быть асинхронным. Если у вас есть реальная (т. Е. Не тестовая заглушка) синхронная реализация, я бы отметил в документации к самому интерфейсу, что вызов метода на самом деле может быть синхронным.

Есть ли какая-либо выгода в том, что IMyAdapter возвращает типы задач? Предположительно, вызовы приложения ожидают MyFileProcessor.DoSomeWorkAsync(…), так почему же адаптеры должны быть асинхронными?

ДА. Ваш первый пример связан с асинхронной операцией ввода-вывода, поэтому имеет смысл сделать интерфейс, возвращающий задачу (т. Е. асинхронно совместимый).

Эти операции в основном связаны с вводом-выводом, а не с процессором — должно ли это повлиять на мое решение о том, как я буду разрабатывать эти компоненты?

ДА. Каждый раз, когда у вас есть интерфейс, который, вероятно, будет реализован асинхронно, он должен иметь подписи, совместимые с асинхронностью, для этих методов.

Если MyFileProcessor не нуждается в выполнении какой-либо работы, связанной с процессором, есть ли какая-либо польза от использования async вообще?

Я не понимаю этот вопрос; похоже, это подразумевает, что асинхронность следует использовать для работы с ЦП. Но это противоположно тому, как работает асинхронность; асинхронность естественным образом подходит для кода, связанного с вводом-выводом, а не для кода, связанного с процессором.

Возможно, вас заинтересует серия моих блогов о async ООП.

Комментарии:

1. Спасибо за разъяснение. Я прочитал и нашел некоторую противоречивую информацию о том, async лучше ли для работы с ЦП или ввода-вывода, что привело к некоторой путанице.