Что такое асинхронность в System.Data.Common.DbDataReader.ReadAsync?

Я смотрю на код для DbDataReader (также DbCommand) в справочнике MS и не могу понять, что такое асинхронность в методе ReadAsync().

    virtual public Task<bool> ReadAsync(CancellationToken cancellationToken) {
        if (cancellationToken.IsCancellationRequested) {
            return ADP.CreatedTaskWithCancellation<bool>();
        }
        else {
            try {
                return Read() ? ADP.TrueTask : ADP.FalseTask;
            }
            catch (Exception e) {
                return ADP.CreatedTaskWithException<bool>(e);
            }
        }
    }

Метод ReadAsync просто вызывает метод Read и возвращает завершенную задачу. Разве это не блокирует вызывающий поток так же, как и вызов Read напрямую?

Я заметил ту же картину в DbCommand ExecuteReaderAsync и других методах. Они просто вызывают версии синхронизации и возвращают выполненные задачи.

Что мне здесь не хватает?

ОБНОВЛЕНИЕ: я ничего не пропустил, как хорошо объяснил @PeterBons (также в документации). Мне все еще не нравится это, но это моя проблема.

1 ответ

Решение

Вы смотрите на виртуальный метод в абстрактном классе. Если вы хотите, чтобы (будущие) реализации могли выполнять действительно асинхронную работу, вам нужно определить сигнатуру метода, которая это позволяет. Так что должно вернуть Task или же Task<T>, Помните, что простое использование Задачи не делает ничего асинхронным, оно делает его ожидаемым.

Использование Task<bool> Тип возвращаемого значения в этом примере виртуальный метод предназначен для облегчения других классов, производных от DbDataReader, для обеспечения реального асинхронного поведения в их реализации ReadAsync.

Например, действительно асинхронная реализация может сделать что-то вроде

class TrueAsyncReader : DbDataReader
{
    ...

    public override async Task<bool> ReadAsync(CancellationToken cancellationToken) 
    {
        ...

        return await ReadFromDbAsync();
    }
}

Как вы можете видеть, теперь у вас могут быть асинхронные и не асинхронные реализации без необходимости изменять сигнатуру метода.

Так как вы можете легко вызвать синхронный код из асинхронного метода, это путь. Вызов асинхронного кода из синхронного метода - дело не из легких.

для не асинхронных реализаций, которые должны вернуть задачу, вы можете вернуть что-то вроде Task.FromResult<T> или же Task.CompletedTask, Это не будет блокировать.

Смотрите также ждите Task.CompletedTask для чего?

Подводя итог: реализация по умолчанию не делает ничего асинхронного, но производные классы могут без необходимости изменять сигнатуру метода.

Другие вопросы по тегам