Всегда используйте ключевые слова "async" и "ожидание" в асинхронных методах в библиотеке? - программирование
Подтвердить что ты не робот

Всегда используйте ключевые слова "async" и "ожидание" в асинхронных методах в библиотеке?

Резюме. В методе библиотеки, когда следует использовать ключевые слова async и await вместо прямого возврата Task?

Я считаю, что мой вопрос связан с этим. Однако этот вопрос касается .NET 4.0 и TPL, в то время как я использую .NET 4.6 с ключевыми словами async и await. Итак, я думаю, что мой вопрос может получить разные ответы, потому что эти ключевые слова не существовали, когда был задан связанный вопрос.

Объяснение: Я пишу простую оболочку для внешней службы WCF, и оболочка делает несколько вызовов SendAsync. Теперь я думаю, что каждый метод обертки должен просто вернуть Task<> напрямую, не ожидая. Я понимаю, что async/await следует использовать на уровне приложения, а не в библиотеке.

Итак, например, вот такой подход, который, как я думаю, должен взять для каждого метода обертки:

private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
    return _service.SendAsync(request);
}

Но в Интернете я нашел несколько сообщений, которые используют этот подход:

private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
    return await _service.SendAsync(request).ConfigureAwait(false);
}

И вот еще один пример, который я нашел в technet:

async Task PutTaskDelay()
{
    await Task.Delay(5000);
} 

private async void btnTaskDelay_Click(object sender, EventArgs e)
{
    await PutTaskDelay();
    MessageBox.Show("I am back");
}

Итак, когда я должен использовать второй подход (тот, который включает ключевые слова async и await)? Почему бы просто не вернуть целое Task без создания PutTaskDelay async? Я думаю, что я должен возвращать Task напрямую, когда это возможно, и использовать async/await, чтобы получить окончательный результат только на прикладном уровне. Я прав? Если нет, в чем разница между двумя подходами, которые я показываю здесь?

Моя забота. Когда используются ключевые слова async и await, кажется, что он просто предоставляет дополнительную работу компилятору без каких-либо преимуществ.

4b9b3361

Ответ 1

Должен ли я использовать async в библиотеке?

Все зависит. Если вы собираетесь использовать асинхронную парадигму программирования, тогда ответ будет "да", ключевые слова async и await необходимы большую часть времени. Скорее всего, вам понадобится использовать async/await. Это связано с тем, что в большинстве ситуаций было бы трудно использовать только Task и Task<T>, так как вам, скорее всего, придется рассуждать о результатах операций async, которые вы вызываете.

Кроме того, на основе вашего вопроса кажется, что у вас может быть некоторая путаница в отношении самих ключевых слов и их отношении к типам Task и Task<T>. Позвольте мне уточнить это для вас.

Ключевое слово async позволяет использовать метод await. Лучшая практика заключается в том, чтобы все методы async возвращали либо Task, либо Task<T>, если вы не можете (например, обработчик события нажатия кнопки, как вы показали выше).

Методы, возвращающие Task или Task<T>, представляют асинхронные операции. Когда вы находитесь в библиотеке, рекомендуется использовать .ConfigureAwait(false) по причинам, описанным ниже здесь. Кроме того, я всегда указываю людям на эту подробную статью по этому вопросу.

Чтобы дифференцировать два подхода в вашем вопросе:

В приведенном ниже методе возвращается a Task<SignResponse>. Это асинхронная операция, которая представляет работу для входа. Метод может быть вызван вызывающим абонентом для получения SignResponse.

private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
    return _service.SignAsync(request);
}

Аналогично, эта версия делает то же самое... за исключением того, что ключевые слова async/await не нужны. Причина, по которой они не нужны, заключается в том, что самому методу не нужно использовать SignResponse, и поэтому он может просто вернуть Task<SignResponse>, как показано выше. И, как вы указали в своем вопросе, действительно существует штраф, если вы используете ключевые слова async/await, когда они не нужны. При этом добавляется дополнительный шаг конечного автомата, так как результат получается, так как его ожидали.

private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
    return await _service.SignAsync(request).ConfigureAwait(false);
}

Наконец, если вам нужно было обосновать ответ, вы можете использовать вышеупомянутые ключевые слова, чтобы сделать это следующим образом:

private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
    var result = await _service.SignAsync(request).ConfigureAwait(false);
    if (result.SomeProperty == SomethingWeCareToCheck)
    {
        _log.Log("Wow, this was un-expected...");
    }
    return result;
}

Ответ 2

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

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