Ожидание задачи условно - PullRequest
       59

Ожидание задачи условно

0 голосов
/ 27 января 2020

Для метода async, который возвращает Task<bool>, мне нужно выполнить некоторые действия после его завершения. Метод asyn c выглядит следующим образом:

async Task<bool> EntryExists(string entry)
{
  return await Task.Run(() => call_that_returns_bool());
}

Я вызываю его и прикрепляю к нему задачу продолжения для выполнения последующих действий:

EntryExists(my_entry).ContinueWith(t =>
{
  if(t.Result) ...
});

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

var T = EntryExists(my_entry).ContinueWith(t =>
{
  if(t.Result) ...
});

if(wait) T.Wait(); //wait is my parameter

При выполнении этого код навсегда застревает в T.Wait (), когда параметр wait равен true, как если бы T никогда не срабатывал. Затем я попробовал следующее:

var T = EntryExists(my_entry).ContinueWith(t =>
{
  if(t.Result) ...
});

T.Start();
if(wait) T.Wait();

После чего он говорит мне, что

Запуск не может быть вызван для задачи продолжения

Я знаю, что мне чего-то не хватает по основам c, но после кодирования в течение последних 15 часов мой мозг мало помогает. Может кто-нибудь указать, что мне нужно делать?

1 Ответ

1 голос
/ 27 января 2020

Вы не должны блокировать асин c код . Короче говоря, вы, скорее всего, заблокируете поток, к которому должен возвращаться метод asyn c (в данном случае, поскольку это поток пользовательского интерфейса). Решение состоит в том, чтобы использовать asyn c -wait на всем пути, а не пытаться запустить его синхронно. Если вам абсолютно необходимо представить синхронный метод, то по крайней мере предоставьте как можно более простую оболочку, а не смешивайте ContinueWith и asyn c -await.

Ваш внешний вызов может быть переписан как:

async Task<{something}> MakeCallAndContinue()
{
    try
    {
        await EntryExists(my_entry);
        // additional continuation code
    }
    catch (Exception e)
    {
        // handle in some way
    }
}
var task = MakeCallAndContinue();
if (wait) await task;

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

Вы не сможете использовать вышеприведенное в своей команде WPF как - потому что это асин c. Тем не менее, вы можете иметь asyn c WPF-обработчики команд, как объяснено здесь . Если вы хотите сделать это синхронно, то вам нужно было бы позвонить .Wait(), но, как объясняет Стивен Клири в моей первой ссылке, вы должны использовать ConfigureAwait(false) для всех ожидаемых задач до конца, чтобы предотвратить одну из них. от попытки возврата к занятому потоку пользовательского интерфейса и взаимоблокировки.

...