2

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

我正在使用 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 在后台使用线程:15 下载 file-01.txt

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

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

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

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

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

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

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

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

4

1 回答 1

1

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

在这篇文章中使用了一个类似的调度器,但是你也必须对你的调度器进行一定程度的定制,因为我可以看到你也在使用 currentthread,这在实现你自己的调度器时可能不是那么容易. 另一方面,您总是可以使用一些有用的ParallelTask ​​Extensions和QueuedtaskScheduler提供了一些可以在这方面使用的有用实现。

于 2012-10-08T06:22:23.960 回答