Что происходит, когда вы ожидаете асинхронную задачу в C #? - PullRequest
0 голосов
/ 27 ноября 2018

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

public void MyMainMethod()
{
   DoSomethingAsync();
   KeepOnDoingOtherStuff();
}

public async Task DoSomethingAsync()
{
   //Do whatever
   await LongOperation();
   // Rest of the method that is executed when the long operation is 
    //finished.

}

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

Теперь моя проблема в том, что сам мой DoSomethingAsync ожидается.В этом случае:

public async void MyMainMethod()
{
   await DoSomethingAsync();

   //Here is a critical method that I want to execute only when 
     //DoSomethingAsync is finished

   CriticalStuff();
}

public async Task DoSomethingAsync()
{
   //Do whatever
   await LongOperation();
   // Rest of the method that is executed when the long operation is 
    //finished.

}

Теперь я жду своего DoSomethingAsync, так что я уверен, что он не идет дальше, но проблема в том, что DoSomethingAsync () все еще дает руку вызывающей стороне, когда он ожидаетLongOperation (), и мой метод Main возобновляется, чего я не хочу, потому что он выполняет мою критическую вещь.

В асинхронной логике я что-то очень упускаю, что тогда было бы смысл «ждать»метод, который имеет асинхронные методы внутри него?

Я был бы очень признателен за решение моей проблемы.

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Я обсуждаю этот вариант вашего кода:

public async void MyMainMethod()
{
   await DoSomethingAsync();

   //Here is a critical method that I want to execute only when 
     //DoSomethingAsync is finished

   CriticalStuff();
}

public async Task DoSomethingAsync()
{
   //Do whatever
   await LongOperation();
   // Rest of the method that is executed when the long operation is 
    //finished.

}

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

Итак, DoSomethingAsync фактически вызывает некоторое асинхронное поведение и возвращает обратно еще не завершенноеTask до Main.Что Main делает с этим?Это await с этим.await - это то, как этот метод указывает: «Я не могу сделать ничего полезного, если это ожидаемое (обычно Task) не завершено».

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

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

(я проигнорировал историю исключений в приведенном выше описании. Это все счастливые пути)

0 голосов
/ 27 ноября 2018

Я думаю, что несоответствие здесь происходит из-за следующих слов:

для возврата метода к вызывающей стороне, если задача слишком длинная.

await isn 'Т долго , точно.Это примерно асинхронный .Если что-то занимает много времени, но происходит на локальном процессоре, тогда точно: это не совсем подходит для await (хотя вы можете использовать механизм await как удобный способ подтолкнуть вещи крабочий поток, а затем завершить работу потока контекста синхронизации после его завершения).

Тем не менее, лучшим примером является случай, когда задача external ;это может быть вызов базы данных SQL, или redis, или через http, или другому процессу через некоторый уровень ввода-вывода, или ожидание данных сокета.Обратите внимание, что даже общение с физически локальным хранилищем SSD может потребовать длительного ожидания, по крайней мере, измеряемого скоростью процессора.Когда локальный поток не будет делать ничего, кроме блокировки (в ожидании ответа), тогда: во многих случаях есть гораздо лучшие вещи, которые поток может делать.

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


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

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