2013-02-26 36 views
3

我需要担心.NET中的阻塞任务需要多少钱?即.NET任务调度程序如何处理线程池中线程的阻塞和超额订阅?我是否需要担心阻塞任务?

E.g.如果我在任务中有一些IO,我应该始终使用LongRunning提示创建它吗?或者任务调度器启发式处理它更好吗?在C++中有一个Oversubscribe提示,它可以很好地工作,但我还没有在.NET中找到任何等价物。

回答

2

ThreadPool会检测它的某个线程是否阻塞,并提示它将另一个线程添加到池中。所以,如果你阻塞了很多,性能很可能不会太糟糕,因为ThreadPool会尽量保持你的CPU核心忙碌。

但是有很多被阻塞的线程可能是一个性能问题,因为它增加了内存消耗并且可能导致更多的上下文切换。

此外,此行为可能会导致IO性能下降。使用旋转磁盘(HDD)时,同时访问多个文件会导致大量搜索,这可能会大幅影响性能。

2

如果您想要最高性能的代码,您确实需要担心。

处理它的最好方法是使用the .Net 4.5 "await" style of I/O

如果你没有.Net 4.5,你将不得不使用the older style of I/O(它同样适用,但更难使用)。

这些文章中描述的非阻塞I/O是迄今为止执行多线程I/O的最佳方式。

如果你不使用I/O,那么你仍然可以从这些文章中学到很多东西。

+0

我在尽可能地使用await。但我需要调用一些遗留API,我不知道它们可能会做什么,IO,Thread.Sleep无论什么... – ronag 2013-02-26 09:59:26

+0

@ronag如果性能对您很重要,您应该考虑将这些遗留API重写为长期异步。 – svick 2013-02-26 18:22:12

+0

@svick:在这种情况下不可能,也许不值得。我只需要知道整个线程池是否可以被阻塞,或者如果需要的话它会自动将新线程注入到池中。 – ronag 2013-02-26 18:57:16

1

LongRunning信号到TPL 使用线程池线程 - 它创建了一个非线程池线程来实现请求(例如new Thread(...))。这是而不是你应该为IO做什么。你应该使用异步IO。例如:

using(var response = (HttpWebResponse)await WebRequest.Create(url).GetResponseAsync()) 
    return response.StatusCode == HttpStatusCode.OK; 

这确保尽可能具有重叠IO使用 - 使用所述IO线程池。

如果你想使用一个任务与传统APM API,你可以使用FromAsync:如果你需要处理遗留事件的异步API

Task<int> bytesRead = Task<int>.Factory.FromAsync( 
    stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null); 
await bytesRead; 

,您可以使用TaskCompletionSource:

TaskCompletionSource<string[]> tcs = new TaskCompletionSource<string[]>(); 
WebClient[] webClients = new WebClient[urls.Length]; 
object m_lock = new object(); 
int count = 0; 
List<string> results = new List<string>(); 

for (int i = 0; i < urls.Length; i++) 
{ 
    webClients[i] = new WebClient(); 

    // Specify the callback for the DownloadStringCompleted 
    // event that will be raised by this WebClient instance. 
    webClients[i].DownloadStringCompleted += (obj, args) => 
    { 
     // Argument validation and exception handling omitted for brevity. 

     // Split the string into an array of words, 
     // then count the number of elements that match 
     // the search term. 
     string[] words = args.Result.Split(' '); 
     string NAME = name.ToUpper(); 
     int nameCount = (from word in words.AsParallel() 
         where word.ToUpper().Contains(NAME) 
         select word) 
         .Count(); 

     // Associate the results with the url, and add new string to the array that 
     // the underlying Task object will return in its Result property. 
     results.Add(String.Format("{0} has {1} instances of {2}", args.UserState, nameCount, name)); 

     // If this is the last async operation to complete, 
     // then set the Result property on the underlying Task. 
     lock (m_lock) 
     { 
      count++; 
      if (count == urls.Length) 
      { 
       tcs.TrySetResult(results.ToArray()); 
      } 
     } 
    }; 

    // Call DownloadStringAsync for each URL. 
    Uri address = null; 
    address = new Uri(urls[i]); 
    webClients[i].DownloadStringAsync(address, address); 

} // end for 

await tcs.Task; 
+0

我在尽可能使用await。但我需要调用一些遗留API,我不知道它们可能会做什么,IO,Thread.Sleep无论什么... – ronag 2013-02-26 18:55:58

+0

您可以放心,没有框架API会调用Thread。睡眠的价值大于1 ... – 2013-02-27 13:07:38

+0

我已经通过回答一些与“传统”apis一起工作的例子进行了更新。 – 2013-02-27 13:15:36

相关问题