2013-04-11 33 views
12

我已经看到许多类似这样的其他问题,但没有找到我的答案。如何强制Task.Factory.StartNew后台线程?

我的问题是,我是用下面的流程创建线程:

private void btn_Click(object sender, EventArgs e) 
{ 
    service.GetCount(
     (count, ex) => 
     { 
      if (ex != null) 
       return; 

      for (int i = 0; i < count; i++) 
      { 
       service.Get(onItemReceived, i); 
      } 
     } 
    ); 
} 

public void GetCount(Action<int, Exception> callback) 
{ 
    var callingThread = TaskScheduler.FromCurrentSynchronizationContext(); 

    Func<int> action =() => 
    { 
     return client.GetCount(); // Synchronous method, could take a long time 
    }; 

    Action<Task<int>> completeAction = (task) => 
    { 
     Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception; 

     if (callback != null) 
      callback(task.Result, ex); 
    }; 

    Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread); 
} 

public void Get(Action<object, Exception> callback, int index) 
{ 
    var callingThread = TaskScheduler.FromCurrentSynchronizationContext(); 

    Func<object> action =() => 
    { 
     return client.Get(index); // Synchronous method, could take a long time 
    }; 

    Action<Task<object>> completeAction = (task) => 
    { 
     Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception; 

     if (callback != null) 
      callback(task.Result, ex); 
    }; 

    Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread); 
} 

这样,我的每一个服务的异步方法会回调,他们最初被称为上线(通常是UI线程)。所以我模拟了await/async关键字如何工作(我不能使用.NET 4.5)。

这种模式的问题是,在第一次调用“ContinueWith”后,我得到莫名其妙的锁定到UI线程。所以在这种情况下,如果我尝试为每个进程产生一个同步函数获取,它们将执行一个1而不是并行执行,即使我尝试指定TaskCreationOptions.LongRunning 。

这从来没有发生过,我第一次打电话给Task.Factory.StartNew,它只发生在第一个回调内的后续调用

+0

可能重复[如何保证使用Task.StartNew方法时创建新线程](https://stackoverflow.com/questions/8039936/how-to-guarantee-a-new-thread-is-创建时使用任务启动新方法) – 2017-09-05 12:53:47

回答

23

为了强制推出一个新的线程,你应该在调用Task.Factory.StartNew指定TaskScheduler.Default如下:

Task.Factory.StartNew(action, 
         CancellationToken.None, 
         TaskCreationOptions.None, 
         TaskScheduler.Default).ContinueWith(completeAction); 

在我的测试,你并不需要指定TaskCreationOptions .LongRunning为了强制后台线程,尽管它不应该受到伤害。

+0

'LongRunning'强制创建一个全新的*非线程池线程*。 – Servy 2013-04-11 19:38:43

+2

@Servy - 它不强制任何东西,它是调度程序的_hint_。 – 2013-04-11 19:43:40

+0

@HenkHolterman理论上,是的,这是正确的。实际上,在当前的实现中,它会导致创建一个新的线程。尽管我同意最好假设它不可能,但你应该假设将一个任务标记为长时间运行,而实际上不会消耗额外的资源。 – Servy 2013-04-11 19:45:35