задача ожидания против задачи. GetAwaiter - PullRequest
0 голосов
/ 16 мая 2018

Почему следующий пример не работает (оба текста изменяются одновременно):

Task.Run(async () =>
        {
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
            {
                await Task.Delay(2000);
                textnew1.Text = "Dispatched";
            });
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
            {
                await Task.Delay(2000);
                textnew2.Text = "BackgroundTask";
            });
        });

И этот работает (первый текст меняется, а второй следует через две секунды):

Task.Run(async () =>
        {
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                Task.Delay(2000).GetAwaiter().GetResult();
                textnew1.Text = "Dispatched";
            });
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                Task.Delay(2000).GetAwaiter().GetResult();
                textnew2.Text = "BackgroundTask";
            });
        });

Почему Task.Delay не ожидается в первом коде?В чем разница между await Task.Delay и Task.Delay().GetAwaiter().GetResult()?

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Как правильно объясняет Ответ Скотта , причина, по которой ваша асинхронная версия движется, даже если вы ожидаете задержек, заключается в том, что Displatcher.RunAsync принимает делегата void. Что касается подходящего решения, я настоятельно рекомендую избегать использования всех async лямбд в вашем коде. Task.Run действительно понимает, как обрабатывать Task возвращаемые методы, но вы все еще делаете много вещей себе намного сложнее, структурируя свой код так, как вы это делаете, в частности, вы не используете тот факт, что async методы захватить контекст синхронизации, чтобы вам не приходилось вручную маршировать код в поток пользовательского интерфейса.

Вы можете переписать ответ как:

await Task.Delay(2000);
textnew1.Text = "Dispatched";
await Task.Delay(2000);
textnew2.Text = "BackgroundTask";

Если у вас есть какая-то долго выполняемая работа без привязки к процессору, связанная с процессором, и обновление пользовательского интерфейса, которое нужно выполнить после завершения, вместо того, чтобы помещать while вещь в Task.Run лямбду с вызовами диспетчера просто используйте Task.Run, чтобы специально вызывать работу без привязки к ЦП, а затем делать все необходимое для запуска в контексте пользовательского интерфейса после его ожидания:

await Task.Delay(2000);
textnew1.Text = "Dispatched";
await Task.Run(() => SomeBackroundWork());
textnew2.Text = "BackgroundTask";
0 голосов
/ 16 мая 2018

У вас есть async void, ваш первый пример кода эквивалентен

Task.Run(async () =>
        {
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new DispatchedHandler(FirstTask));
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new DispatchedHandler(SecondTask));
        });

private async void FirstTask()
{
    await Task.Delay(2000);
    textnew1.Text = "Dispatched";
}
private async void SecondTask()
{
    await Task.Delay(2000);
    textnew2.Text = "BackgroundTask";
}

Поскольку подпись DispatchedHandler public delegate void DispatchedHandler(), вы не можете вернуть задачу с ней.Когда вы выполняете async void, RunAsync думает, что задача завершена, как только будет нажата await Task.Delay().

...