【问题标题】:Why does PauseToken break the task?为什么 PauseToken 会中断任务?
【发布时间】:2018-06-06 02:51:22
【问题描述】:

我正在努力理解Microsoft.VisualStudio.Workspace.PauseToken

当我调用PauseTokenSource.Pause()时,方法暂停,任务完成,我可以看到“Completed”消息。

之后我打电话给PauseTokenSource.Resume(),任务继续。 但是这个过程完成后我没有消息。

两个问题:

  1. 为什么会这样?
  2. 我该如何解决?

我希望PauseToken 在工作期间不要中断任务。我不想在暂停后收到消息。我想在进程真正结束时收到消息。

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;
}

编辑:

task = Task.Factory.StartNew(async () =>
{
    double i = 0;
    while (i < 3)
    {
        i++;
        CurrentStatus = i.ToString();
        var a = (int)(double)((i / 3.0) * 100.0);
        MessageBox.Show(PauseToken.IsPaused.ToString());
        await PauseToken.WaitWhilePausedAsync();
        CancellationToken.ThrowIfCancellationRequested();
        Thread.Sleep(5000);
        CurrentProgress = a;
    }
}
, CancellationToken);

【问题讨论】:

    标签: c# wpf async-await


    【解决方案1】:

    您的代码的问题在于,当调用的方法返回时,StartNew() 创建的任务被视为完成。当然,它是一个带有awaitasync 方法,只要在不完整的任务上执行第一个await,该方法就会返回。

    所以,您的 DoDoneAsync() 方法实际上在您认为开始的整个完成之前完成。它本质上只是等到您的StartNew() 方法到达它的第一个await

    如果没有一个好的Minimal, Complete, and Verifiable code example 可以可靠地重现您的问题,就不可能确定什么可以解决您的程序。但是,我认为主要是停止尝试将阻塞代码与异步代码混合。相反,只需将StartNew() 调用的匿名方法分解为它自己的命名方法,使其正确异步,然后直接调用它。

    例如:

    private async Task DoDoneAsync()
    {
        FlagCommandDone = true;
    
        try
        {
            await DoDoneLoopAsync();
        }
        catch (Exception e)
        {
            isError = true;
            message = e.Message;
        }
    
        if (!isError) message = task.IsCompleted ? "Completed" : "Canceled";
    
        MessageBox.Show(message);
    
        FlagCommandDone = false;
    }
    
    private async Task DoDoneLoopAsync()
    {
        double i = 0;
        while (i < 3)
        {
            i++;
            await PauseToken.WaitWhilePausedAsync();
            await Task.Delay(5000);
        }
    }
    

    【讨论】:

    • 嗯……有点不懂。为什么 DoDoneLoopAsync 有效?如果await PauseToken.WaitWhilePausedAsync 将被编译,则意味着整个方法都将被编译,因为第一个await 将被执行。我哪里错了?
    • 我看到了。这都是关于 Task.Factory.StartNew。但我需要它,因为我想使用 ProgresBar。我需要新线程。我还需要 CancellationToken。我更新了帖子,添加了 ProgressBar 和 CancellationToken 的属性。我可以在任务中使用标准的 PauseToken 还是我需要在没有等待的情况下编写自己的令牌?
    • 您发布的代码中没有任何内容表明需要新线程,也没有使用ProgressBar,当然ProgressBar 也没有任何暗示 需要一个新线程或使用TaskFactory.StartNew()。以上回答了你提出的问题。如果您有其他问题,例如弄清楚如何将上述内容应用于更广泛的场景,您可以将其作为新问题发布。确保在该问题中提供良好的minimal reproducible example,清楚完整地显示您正在尝试做什么以及您遇到的具体问题。
    • 很抱歉,我不喜欢您的解决方案,但无论如何,谢谢。找到了解决办法。
    • 适合自己。正如他们所说,“你可以把马牵到水边,但你不能让它喝水”。如果您希望您的代码保持低劣,那是您的特权。
    【解决方案2】:

    我需要使用Task.Run() 而不是Task.Factory.StartNew()

    Task.Run 与 Task.Factory.StartNew 是 here

    感谢VladD

    【讨论】:

      猜你喜欢
      • 2015-04-21
      • 1970-01-01
      • 1970-01-01
      • 2018-04-23
      • 2017-03-18
      • 2022-08-16
      • 2019-04-29
      • 2019-09-02
      • 2020-06-22
      相关资源
      最近更新 更多