【问题标题】:Task ContinueWith calls a method with another taskTask ContinueWith 调用另一个任务的方法
【发布时间】:2013-12-05 02:15:19
【问题描述】:

在一个 winforms 应用程序中,我有一个下载文件解压缩 ZIP 文件的方法。为了让它不冻结我的 UI,我从一个任务中运行了解压缩命令。

当解压任务调用 ContinueWith 以继续并在该 ContinueWith 内我调用另一个方法,然后继续我的应用程序逻辑。我的逻辑中的一种方法也需要在任务中运行。问题是,当我使用第二个任务运行该方法时,它似乎并没有在任务中运行并且我的应用程序冻结了。

这是代码:

Task T = new Task(() =>
{
    System.IO.Compression.ZipFile.ExtractToDirectory(
        Path.Combine(_tempDirectory, "update.zip"),
        Path.Combine(_tempDirectory, "update"));
});

Task T2 = T.ContinueWith((previosTask) =>
{
    continueUpdate();
}, TaskScheduler.FromCurrentSynchronizationContext());

continue 方法然后有一些逻辑并调用另一个方法:

private void continueUpdate()
{
    // some logic
    copyTargetFiles();
}

private void copyTargetFiles()
{
    Task T = new Task(() =>
    {
            string backupPath = Path.Combine(_tempDirectory, "Backup\\Files");
            Directory.CreateDirectory(backupPath);

            string sourceFolder = Shared.GetRegistryKey("Folder");
            Infrastructure.Shared.CopyDirectory(sourceFolder, backupPath);
    });
    T.Start();
}

当它到达 copyTargetFiles 时,应用程序冻结。

有什么建议吗?我做错了什么?

【问题讨论】:

  • 您省略的代码与您的问题高度相关。您提供的代码将不会阻塞 UI 线程。 // some logic 中的任何内容都会阻塞 UI 线程。

标签: c# .net winforms task-parallel-library


【解决方案1】:

您正在通过继续执行特定的调度程序来阻塞您的 UI 线程。

TaskScheduler.FromCurrentSynchronizationContext()

通过指定特定的调度程序上下文,所有嵌套任务(无论是子任务)都将默认使用该调度上下文。在您的代码中,这会导致以copyTargetFiles 开始的Task 在UI 线程上运行。自己调试看看吧!

您应该删除ContinueWith 的第二个参数(上面引用的那个)。

编辑:试试这个额外的修复

private Task copyTargetFiles()
{
    Task T = new Task(() =>
    {
            string backupPath = Path.Combine(_tempDirectory, "Backup\\Files");
            Directory.CreateDirectory(backupPath);

            string sourceFolder = Shared.GetRegistryKey("Folder");
            Infrastructure.Shared.CopyDirectory(sourceFolder, backupPath);
    });
    T.Start(TaskScheduler.Default); //jumps back to the default, unrestricted scheduler context for the file copying

    return T;
}

【讨论】:

  • 删除该参数后,尝试更新 continueUpdate() 中的 UI 元素时会引发异常
  • @developer82 是的,任务完成后继续运行,正常或异常。
  • @developer82 恐怕我无法告诉您您的 UI 访问有什么问题,因为您省略了该代码 (//some logic?)。我已经进行了一些修改。
【解决方案2】:

这是众所周知的行为,Task.Factory.StartNewTask.Start 是邪恶的。他们使用TaskScheduler.Current,这意味着从他们开始的任何任务都将在其父调度程序中调度。

在您的情况下,copyTargetFiles 是从 UI 调用的,当它启动一个新的 Task 时,它也仅在 UI 中安排。

如何解决:

使用Task.Run,它使用指向线程池的TaskScheduler.Default

Task t = Task.Run(() =>
{
        string backupPath = Path.Combine(_tempDirectory, "Backup\\Files");
        Directory.CreateDirectory(backupPath);

        string sourceFolder = Shared.GetRegistryKey("Folder");
        Infrastructure.Shared.CopyDirectory(sourceFolder, backupPath);
});

我推荐你阅读Task.Factory.StartNew is Dangerous,StephenCleary 解释的很好。

【讨论】:

    猜你喜欢
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多