我需要担心在.NET中阻止任务多少钱?即.NET任务调度程序如何处理线程池中的线程阻塞和超额订阅?
E.g。如果我在任务中有一些IO,我是否应该始终使用LongRunning
提示创建它?或者任务调度程序启发式更好地处理它?在C ++中有一个Oversubscribe
提示可以很好地工作,但我没有在.NET中找到任何等价物。
答案 0 :(得分: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,那么您可能仍会从这些文章中学到很多东西。
答案 1 :(得分:2)
ThreadPool会检测其中一个线程是否阻塞,并提示它将另一个线程添加到池中。所以,如果你阻塞了很多,性能很可能不会很糟糕,因为ThreadPool会试图让你的CPU内核忙碌。
但是有许多被阻塞的线程可能是一个性能问题,因为它会增加内存消耗并导致更多的上下文切换。
此外,此行为可能会导致IO性能下降。对于旋转磁盘(HDD),同时访问多个文件会导致大量搜索,这会严重影响性能。
答案 2 :(得分: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:
Task<int> bytesRead = Task<int>.Factory.FromAsync(
stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null);
await bytesRead;
如果您需要处理遗留事件异步API,可以使用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;