我有一台配有8核处理器的计算机,我怀疑我的计算机需要使用8-最大功能的最大线程数(软件,不是处理器的线程)。核心。
我正在同时创建160个线程,因此我的处理器的每个核心将处理大约20个线程,这是正确的吗?
我的问题是:
答案 0 :(得分:8)
我同时创建了160个线程,因此我的处理器的每个核心都将处理大约20个线程,这是正确的吗?
不完全。每个核心一次只能处理一个线程。当操作系统决定线程有足够的聚光灯时,它会将其切换为另一个线程。如果你可以在8个线程中完成相同的工作,那么你将获得相同的吞吐量以及避免不必要的上下文切换所带来的节省。
处理器核心的20个线程是一个很好的数字?
没有。每个核心一个线程就是现场。超线程核心数量大约为2,大约 - 工作效果各不相同。
独立运行的线程数,它将被核心数除以?
没有。这是由操作系统决定的,在决策过程中往往会采取许多不同的方法。此外,阻塞的线程不会在任何地方执行。实际上,其中一些线程可能比其他线程占用更多的CPU时间。
如何根据我的处理器知道更多的线程数?
使用比线程更高级别的构造。这意味着将线程池用于简单的工作项Parallel.For
和家庭用于"同步"并行{和Task
用于复杂的异步工作任务(包括线程池片段)。手动创建线程的确有很多很好的理由 - 除非你真的知道自己在做什么,以及为什么在专用线程上拥有它很重要。
关键点是这仅适用于CPU工作。您可以轻松地让一个线程同时处理一百个单独的异步任务。在对异步API使用await
时,这非常容易使用。只要CPU实际执行CPU工作,每个CPU的单个线程就可以轻松获得100%的利用率。如果它没有,你想要使用异步I / O--浪费线程没有意义(伴随着它们在内存中的成本,转换开销,过度调度调度程序,垃圾收集......) 等待
典型的例子是处理一些数据库工作的异步Web服务:
string GetUserName(Guid userId)
{
return Db.GetUser(userId).Name;
}
此同步方法将在处理数据库请求时占用请求线程。如果您的数据库请求需要一秒钟,并且您同时有2000个请求,则您需要2000个线程来处理请求。但是,DB请求只是异步I / O - 该线程基本上等待DB的响应返回。线程浪费了等待。
相反,您可以使用异步API:
async Task<string> GetUserName(Guid userId)
{
var user = await Db.GetUserAsync(userId);
return user.Name;
}
代码几乎完全相同,但await
构造实际上并没有阻止请求线程 - 它基本上说是&#34;好的,我已经完成了,你可以使用这个线程别的。当我准备继续时,我会帮你回电话。&#34;。这种模式意味着你从不需要比CPU内核更多的线程 - 如果CPU是100%,那么添加更多线程来处理负载是没有意义的。如果不是,那就意味着某个线程没有做任何CPU工作 - 这很好,它将在另一件工作到来时使用。现在,您有8个线程处理相同的 2000个请求,而不是让2000个线程处理2000个请求。
答案 1 :(得分:1)
最佳计数是每个虚拟核心一个(HT核心计为2个虚拟核心)。
但是你不应该通过自我使用Parallel.ForEach
example taken from msdn来实现这个逻辑,如果有很多延迟,例如阅读文件或等待,还有其他选项look here。网络流量我建议使用异步功能(see example 2, also from msdn):
using System;
using System.Drawing; // requires system.Drawing.dll
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class SimpleForEach
{
static void Main()
{
// A simple source for demonstration purposes. Modify this path as necessary.
string[] files = System.IO.Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures", "*.jpg");
string newDir = @"C:\Users\Public\Pictures\Sample Pictures\Modified";
System.IO.Directory.CreateDirectory(newDir);
// Method signature: Parallel.ForEach(IEnumerable<TSource> source, Action<TSource> body)
Parallel.ForEach(files, currentFile =>
{
// The more computational work you do here, the greater
// the speedup compared to a sequential foreach loop.
string filename = System.IO.Path.GetFileName(currentFile);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(currentFile);
bitmap.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
bitmap.Save(System.IO.Path.Combine(newDir, filename));
// Peek behind the scenes to see how work is parallelized.
// But be aware: Thread contention for the Console slows down parallel loops!!!
Console.WriteLine("Processing {0} on thread {1}", filename,
Thread.CurrentThread.ManagedThreadId);
} //close lambda expression
); //close method invocation
// Keep the console window open in debug mode.
Console.WriteLine("Processing complete. Press any key to exit.");
Console.ReadKey();
}
}
示例2:
// Add a using directive and a reference for System.Net.Http.
using System.Net.Http;
// Add the following using directive.
using System.Threading;
namespace ProcessTasksAsTheyFinish
{
public partial class MainWindow : Window
{
// Declare a System.Threading.CancellationTokenSource.
CancellationTokenSource cts;
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
resultsTextBox.Clear();
// Instantiate the CancellationTokenSource.
cts = new CancellationTokenSource();
try
{
await AccessTheWebAsync(cts.Token);
resultsTextBox.Text += "\r\nDownloads complete.";
}
catch (OperationCanceledException)
{
resultsTextBox.Text += "\r\nDownloads canceled.\r\n";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownloads failed.\r\n";
}
cts = null;
}
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
async Task AccessTheWebAsync(CancellationToken ct)
{
HttpClient client = new HttpClient();
// Make a list of web addresses.
List<string> urlList = SetUpURLList();
// ***Create a query that, when executed, returns a collection of tasks.
IEnumerable<Task<int>> downloadTasksQuery =
from url in urlList select ProcessURL(url, client, ct);
// ***Use ToList to execute the query and start the tasks.
List<Task<int>> downloadTasks = downloadTasksQuery.ToList();
// ***Add a loop to process the tasks one at a time until none remain.
while (downloadTasks.Count > 0)
{
// Identify the first task that completes.
Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);
// ***Remove the selected task from the list so that you don't
// process it more than once.
downloadTasks.Remove(firstFinishedTask);
// Await the completed task.
int length = await firstFinishedTask;
resultsTextBox.Text += String.Format("\r\nLength of the download: {0}", length);
}
}
private List<string> SetUpURLList()
{
List<string> urls = new List<string>
{
"http://msdn.microsoft.com",
"http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
"http://msdn.microsoft.com/en-us/library/hh290136.aspx",
"http://msdn.microsoft.com/en-us/library/dd470362.aspx",
"http://msdn.microsoft.com/en-us/library/aa578028.aspx",
"http://msdn.microsoft.com/en-us/library/ms404677.aspx",
"http://msdn.microsoft.com/en-us/library/ff730837.aspx"
};
return urls;
}
async Task<int> ProcessURL(string url, HttpClient client, CancellationToken ct)
{
// GetAsync returns a Task<HttpResponseMessage>.
HttpResponseMessage response = await client.GetAsync(url, ct);
// Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
return urlContents.Length;
}
}
}