Страницы

Поиск по вопросам

пятница, 3 января 2020 г.

Почему PauseToken прерывает Task?

#c_sharp #wpf #async


Пытаюсь разобраться с PauseToken (Namespace: Microsoft.VisualStudio.Workspace).

Не могу понять когда вызываю PauseTokenSource.Pause(); PauseToken уходит в паузу
и одновременно завершает task и я получаю сообщение "Completed".

Но при этом если после PauseTokenSource.Pause(); вызвать PauseTokenSource.Resume();,
то task продолжит работать, но по окончании никаких сообщений не будет.

Два вопроса почему так происходит, и как это можно поправить?

public PauseToken PauseToken;

private async Task DoDoneAsync()
{
    FlagCommandDone = true;

    try
    {
        task = Task.Factory.StartNew(async () =>
            {
                double i = 0;
                while (i < 3)
                {
                    i++;
                    await PauseToken.WaitWhilePausedAsync();
                    Thread.Sleep(5000);
                }
            }
        );
        await task;
    }
    catch (Exception e)
    {
        isError = true;
        message = e.Message;
    }

    if (!isError) message = task.IsCompleted ? "Completed" : "Canceled";

    MessageBox.Show(message);

    FlagCommandDone = false;
}

    


Ответы

Ответ 1



Проблема в Task.Factory.StartNew. Этот метод запускает обыкновенные функции как Task, но для асинхронных он делает не то, что вы ожидаете. Используйте Task.Run вместо него. Давайте вспомним, как выполняются асинхронные функции. Ваш async-делегат с точки зрения внешнего кода не выполняется до конца, а завершается с первым внутренним await'ом, возвращая Task (который, в свою очередь, завершится с окончанием выполнения всей асинхронной функции). Следовательно, ваш task является не заданием выполнения всей асинхронной функции, а лишь заданием получения на неё Task'а! Действительно, сигнатура вашего async-делегата есть Task f(), а сигнатура функции, возвращённой из Task.Factory.StartNew — Task f(). Task.Run обрабатывает эту ситуацию более ожидаемым образом: он получает Task, и делает внутри await, таким образом, вы дожидаетесь «внутреннего» таска, представляющего собой ваш асинхронный делегат. Литература: PFX team, Task.Run vs Task.Factory.StartNew (кажется, русский перевод тут).

Комментариев нет:

Отправить комментарий