来自Task.Continuewith的新任务(在单独的线程上运行)

时间:2012-10-08 05:24:54

标签: .net wpf task-parallel-library

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

我正在使用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这是Thread: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应该开始一个新线程,无论如何!!!

1 个答案:

答案 0 :(得分:1)

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

类似的调度程序使用 in this post ,但是您还需要对调度程序进行一定级别的自定义,因为我可以看到您正在使用当前线程,在实现自己的调度程序时可能并不那么容易。另一方面,您总是可以使用一些有用的ParallelTaskExtensionsQueuedtaskScheduler提供一些可以在这方面使用的有用实现。