Почему невозможно присоединиться к задаче? - PullRequest
0 голосов
/ 26 сентября 2018

Недавно я пришел к проблеме взаимоблокировки, аналогичной описанной здесь: Пример асинхронного ожидания / ожидания, который вызывает взаимоблокировку

Этот вопрос не является дубликатомниже.

Поскольку у меня есть доступ к асинхронной части кода, я смог использовать решение, описанное @ stephen-cleary в его записи в блоге здесь: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Поэтому я добавил ConfigureAwait(false) к первой ожидаемой задаче.

Я не могу использовать второе решение (поместите async везде) из-за количества затронутого кода.

Но япродолжайте спрашивать себя, что если я не могу изменить вызываемый асинхронный код (например, extern API).

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

Вот код:

public static class TaskExtensions
{
    public static void Join(this Task task)
    {
        var currentDispatcher = Dispatcher.CurrentDispatcher;
        while (!task.IsCompleted)
        {
            // Call back the dispatcher to allow other Tasks on current thread to run
            currentDispatcher.Invoke(delegate { }, DispatcherPriority.SystemIdle);
        }
    }
}

Я хочу подчеркнуть, что я не уверен, что правильное имя для этого метода - Join.

Мой вопрос заключается в том, почему Task.Wait() не реализован таким образом или может быть дополнительно использован таким образом

1 Ответ

0 голосов
/ 26 сентября 2018

Этот Join метод просто занят ожиданием завершения задачи с добавленным эквивалентом Application.DoEvents().Многократно обращаясь к диспетчеру, вы в сущности внедрили вложенный насос сообщений, поддерживающий пользовательский интерфейс.

Это действительно плохая идея, потому что она загружает ЦП на 100%.

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

Вы говорите, что вы действительно хотите избежать асинхронности всего кода, потому что это потребует много работы.Может быть, вы можете с умом использовать шаблон await Task.Run(() => OldSynchronousCode());, чтобы избежать большой работы, чтобы сделать это.Поскольку это выполняется в потоке пользовательского интерфейса, частота таких вызовов должна быть очень низкой.Это означает, что накладные расходы, вызванные этим, также очень низки, и это не проблема.

...