【问题标题】:new Task from Task.Continuewith (to run on separate thread)来自 Task.Continuewith 的新任务(在单独的线程上运行)
【发布时间】:2012-10-08 05:24:54
【问题描述】:

提前感谢您的时间和帮助。

我正在使用 WPF 应用程序中的 TPL 从远程服务器下载文件。 我有一个在 UI 线程上运行的“传输管理器”方法,我从中创建后台任务以单独下载文件。我在后台任务上附加了后续任务以更新 UI。

问题是:对于第一个文件,下载任务按预期在新线程上开始。但对于所有后续下载,它使用与锁定应用程序的 UI 相同的线程。

我已经完成了我的作业,阅读了相关材料,因此我无法理解这种行为,确定我做错了什么以及如何解决它。任何帮助,提示,指针,解释表示赞赏。 谢谢。

我正在附加示例代码和调试模式下的输出窗口文本。

private void btnNew_Click(object sender, RoutedEventArgs e)
{
// do some work and prepare transfer state object(my custom object)
...
..
  iTaskFactory = new TaskFactory
          (TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent,
           TaskContinuationOptions.None);

// call transfer manager
this.ManageTransfer(null, iDownloadState);
}

private void ManageTransfer(Task antecedent, TransferState ts)
{
  if(antecedent == null)
  // this is the first invocation of the task from GetNew / Upload methods
  {
    ts.IsActive = true;
    // some code....
  }
  else if(antecedent.IsFaulted)       // check exception on previous task executed
  // if there is a fault, then retry the page again
  {

    // do some error logging....
    //retry transferring the same page again
    pageToTranfer = ts.PagesTransferred + 1;
  }
  else
  // if the page was successfully transferred
  {
    //increment transfer count
    ts.PagesTransferred += 1;

    // update UI.... (as running on UI Thread)

    // if all pages are transferred, then exit method. No further tasks to queue
    if(ts.PagesTransferred == ts.Pages)
    {          
      return;
    }

    pageToTranfer = ts.PagesTransferred + 1;
  }

  Task transferTask;     // should run in background thread
                         // **Problem is that afer first execution**, 
                         // **this also runs on UI Thread!!**
  Task continuationTask; // should run in UI thread

    localFile = "someName.txt";  //..... work out next file to transfer
    serverFile = "someName.txt"; //..... work out next file to transfer

  time = DateTime.Now.ToString("hh:mm:ss.ffff"); //.ToShortTimeString();    
  Debug.WriteLine(time + "starting download :" + pageToTranfer.ToString() 
                  + " This is Thread: " 
                  + Thread.CurrentThread.ManagedThreadId.ToString());

  transferTask = iTaskFactory.StartNew(() => Download(serverFile, localFile));

  continuationTask = transferTask.ContinueWith((t1Task) => ManageTransfer(t1Task, ts)
                     , TaskScheduler.FromCurrentSynchronizationContext());

}

public bool Download(string aCloudPath, string aLocalPath)
{

  time = DateTime.Now.ToString("hh:mm:ss.ffff"); //.ToShortTimeString();
  Debug.WriteLine(time + " in background for downloading " 
                 + aCloudPath + " using thread:" 
                 + Thread.CurrentThread.ManagedThreadId.ToString());

  // code to transfer file... no access to UI or any shared variable

  return true;
}

输出窗口:

10:37:53.2629 开始下载:1 这是线程:8

10:37:55.2720 在后台使用 thread:15 下载 file-01.txt

10:37:56.4120 开始下载:2 这是线程:8

10:38:00.4143 在后台使用 thread:8 下载 file-02.txt

10:38:01.2413 开始下载:3 这是线程:8

10:38:05.2445 在后台使用 thread:8 下载 file-03.txt

10:38:05.8606 开始下载:4 这是线程:8

10:38:09.8618 在后台使用 thread:8 下载 file-04.txt

如您所见,第一次下载功能按预期在后台运行。但之后它继续在 UI Thread 中运行! 我期望 ManagerTranfer 在同一个线程中运行,并在不同的线程中运行下载功能。

我也尝试过使用简单的任务(即没有 TaskFactory),但行为是相同的。我已经设置了TaskCreationOptions.LongRunning,所以TPL无论如何都应该启动一个新线程!!!

【问题讨论】:

  • 已修复。开始时,我删除了我的自定义 TaskFactory 并在我的下载任务上设置了 TaskScheduler.Default。
  • scheduler.Default 通常是线程池,但是如果你在另一个使用 FromCurrentSynchronizationContext 启动的任务中,那么这个默认调度器就是 UI 线程。
  • @Tormod 我相信你错了。 TaskScheduler.Default 永远是线程池,TaskScheduler.Current 改变你描述的方式。
  • @svick 啊,我相信你是对的。谢谢

标签: .net wpf task-parallel-library


【解决方案1】:

您使用的调度程序是在 currentSync 上下文中运行任务的调度程序,该调度程序将依次在 UI 线程上运行您的任务以及在同一调度程序上调度的其他任务。为了在单独的线程上运行您的任务,您应该使用另一个调度器,它实现了 taskscheduler 类并相应地创建线程。

使用了类似的调度程序 in this post,但是你也必须对调度程序进行一定程度的自定义,因为我可以看到你也在使用 currentthread,这实现自己的调度程序时可能并不容易。另一方面,您总是可以使用一些有用的ParallelTaskExtensionsQueuedtaskScheduler 提供了一些可以在这方面使用的有用实现。

【讨论】:

  • 谢谢法伊兹。你确实帮助我找到了正确的方向。我没有在我的下载任务上设置调度程序上下文。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多