Асинхронное предупреждение озадачивает меня - PullRequest
0 голосов
/ 09 июня 2018

Это не вопрос отладочного типа, я просто ищу определенное образование в области асинхронного программирования, области, в которой, по общему признанию, я не дома, здесь.

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

Меня удивляет то, что когда я вызываю его из метода Main, я получаю предупреждение о том, что мне следует использоватьКлючевое слово await, чтобы заставить программу ждать завершения вызова метода, иначе я не смог бы получить ожидаемое поведение, что было странно для меня.Я полагаю, что суть написания асинхронного метода состоит в том, чтобы запустить его, а затем двигаться дальше, не дожидаясь его завершения, поэтому игнорирование предупреждения приведет к поражению цели.С другой стороны, я недостаточно высокомерен, чтобы предположить, что знаю лучше, чем профессионалы, которые разработали Visual Studio и добавили предупреждение, поэтому должно быть больше случаев, когда добавление ключевого слова await имеет больше смысла, чем нет.

Мой вопрос: как обычно используются асинхронные методы, которые требуют внимания к этому предупреждению?

Редактировать: Люди запрашивали код и конкретный текст предупреждения, поэтому:

Асинхронный метод:

public static async Task FindPairs(TimeSpan interval, CancellationToken cancellationToken)
            {
            while (true)
                {
                lock (relevantVariable)
                    {
                    doStuffEveryInterval();
                    }
                await Task.Delay(interval, cancellationToken);
                }
            }

И предупреждение таково: «Поскольку этот вызов не ожидается, выполнение текущего метода продолжается до завершения вызова. Рассмотрите возможность применения оператора 'await' к результату вызова. Текущий вызов методаасинхронный метод, который возвращает задачу или задачу и не применяет к результату оператор await. При вызове асинхронного метода запускается асинхронная задача. Однако, поскольку оператор await не применяется, программа продолжает работу, не ожидая задачидля завершения. В большинстве случаев такое поведение не то, что вы ожидаетект.Обычно другие аспекты вызывающего метода зависят от результатов вызова или, как минимум, ожидается, что вызываемый метод завершится до того, как вы вернетесь из метода, содержащего вызов.

Не менее важная проблема заключается в том, что происходит сисключения, которые возникают в вызываемом асинхронном методе.Исключение, которое возникает в методе, который возвращает задачу или задачу, сохраняется в возвращенной задаче.Если вы не ожидаете выполнения задачи или явно не проверяете наличие исключений, исключение теряется.Если вы ожидаете выполнение задачи, ее исключение перебрасывается.

В качестве оптимальной практики всегда следует ожидать вызова.

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

1 Ответ

0 голосов
/ 09 июня 2018

То, как я понимаю, сам смысл написания асинхронного метода состоит в том, чтобы запустить его, а затем двигаться дальше, не дожидаясь его завершения

Тогда почему вы await the Delay, если ты в это веришь?Delay возвращает задачу;Вы начали эту задачу, конечно же, вы хотите двигаться дальше до ее завершения и просто повторить следующую итерацию цикла?

Конечно, нет.Это победило бы всю точку задержки , если бы она работала асинхронно и завершилась, и никто ее не ждал.

Что тогда точно означает await?Это означает то, что говорится: асинхронно ждать .То есть: этот рабочий процесс не может продолжаться до тех пор, пока эта задача не будет завершена, поэтому, если она не завершена, найдите другую работу и вернитесь позже .

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

Это то, что вы бы обычно делали, но ваш метод ненормальный. Ваш метод никогда не завершается нормально! Если бы вы сделали await этот метод, вы бы подождали, пока он не бросил (потому что он был отменен), пока он не завершится нормально , потому что он не завершается нормально!

Таким образом, await задачи, возвращаемой вашим методом, на практике, вероятно, будет ждать вечно, а это не то, что вам нужно.

Таким образом, вы можете игнорировать или подавить предупреждение в этом случае.Но в обычном случае вы вызываете метод, потому что вам нужны либо его побочные эффекты, либо его результат , и вы не можете продолжить свой рабочий процесс, пока не получите его.Таким образом, вы await выполняете задачу, чтобы ваш абонент мог выполнять больше работы, пока вы ожидаете рабочего процесса вашего вызываемого абонента.

Убедитесь, что абсолютно очистите, прежде чем писать больше асинхронного кода.await - это последовательность операций в асинхронных рабочих процессах. Это означает, что «этот рабочий процесс не будет продолжаться до тех пор, пока эта задача не будет завершена; найдите что-то еще, пока вы ждете, и вернитесь, когда мы сможем продолжить».

Сравните это с "нормальным" вызовом обычного метода.x = foo(); означает «Этот рабочий процесс не будет продолжаться до тех пор, пока не будет завершен вызов foo; ничего не делайте, только выполните foo до завершения».Мы так привыкли к тому, что синхронно ожидает результата , что даже не думаем об этом.


Этот вопрос указывает на большую проблему дизайна с типом C #система.Неуниверсальный Task логически "асинхронный пустота";то есть рабочий процесс завершается , но не завершается со значением . C # не имеет концепции системы типов для методов, которые никогда не возвращаются нормально, но могут выдавать .Вы можете представить себе специальную версию void, может быть void never, и в таких методах было бы ошибкой возвращать или иметь достижимую конечную точку.

Ваш рабочий процесс логически "никогда не задается" -- это асинхронный рабочий процесс, который обычно не завершается.Если компилятор знал об этом, он мог бы подавить предупреждение (и он мог выдавать предупреждения при синхронных вызовах never void методов, у которых после них был недоступный код). Но компилятор не знает этого, потому что это понятиене в системе типов в первую очередь.По логике это может быть, но я думаю, что у команды C # есть более насущные проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...