我是否需要担心阻止任务?

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

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

ThreadPool会检测其中一个线程是否阻塞,并提示它将另一个线程添加到池中。 因此,如果你阻止很多,性能最有可能不会很糟糕,因为ThreadPool会试图让你的CPU核心保持忙碌。

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

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

如果您需要性能最佳的代码,则需要担心它。

处理它的最佳方法是使用.Net 4.5“等待”风格的I / O.

如果你没有.Net 4.5,你将不得不使用较旧的I / O风格 (它也可以使用,但更难使用)。

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

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

LongRunning向TPL LongRunning信号, 使用线程LongRunning线程 – 它创建一个非线程池线程来满足请求(例如new Thread(...) )。 这不是你应该为IO做的。 您应该使用异步IO。 例如:

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

这样可以确保在可能的情况下使用重叠的IO – 它使用IO线程池。

如果要将任务与旧版APM API一起使用,可以使用FromAsync:

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

如果您需要处理遗留事件异步API,可以使用TaskCompletionSource:

 TaskCompletionSource tcs = new TaskCompletionSource(); WebClient[] webClients = new WebClient[urls.Length]; object m_lock = new object(); int count = 0; List results = new List(); 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;