对于特定处理器,同时线程 运行 的更好数量是多少?
What is the better number of threads running simultaneous for specific processor?
我有一台带有 8 核处理器的计算机,我对我的计算机需要使用您的最大潜力的最大线程数(软件,不是处理器线程。)有疑问8 核。
我正在同时创建 160 个线程,所以我的处理器的每个内核将处理大约 20 个线程,对吗?
我的问题是:
- 处理器核心 20 个线程是否合适?
- 独立于线程数运行,它会被内核数平均分吗?
- 如何知道哪个线程数适合我的处理器?
最好的计数是每个虚拟核心一个(具有 HT 的核心计为 2 个虚拟核心)。
但是你不应该通过自己使用来实现这个逻辑 Parallel.ForEach
example taken from msdn, also there are other options look here also if there is alot of delays involved like reading a file or waiting for network traffic i would recommend using async functions (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;
}
}
}
I'm creating 160 threads simultaneous, so each core of my processor will process about ~20 threads, is it correct?
不完全是。每个核心一次只能处理一个线程。当 OS 决定线程有足够的聚光灯时,它将把它切换到另一个线程。如果您可以在 8 个线程中完成相同的工作,那么您将拥有相同的吞吐量以及避免不必要的上下文切换所带来的节省。
20 threads by core of processor is a good number?
没有。每个核心一个线程是现场。超线程核心大约有两个 - 工作效果各不相同。
Independent the number of threads running, its will be divided equality by the number of cores?
没有。这是由操作系统决定的,操作系统在其决策中往往会考虑很多不同的事情。此外,阻塞的线程不会在任何地方执行。实际上,其中一些线程很可能比其他线程占用更多 CPU 时间。
How to know whats the better number of threads according with my processor?
使用比线程更高级别的结构。这意味着将线程池用于简单的工作项,Parallel.For
和系列用于 "synchronous" 并行,异步 Task
s 用于复杂的异步工作任务(包括线程池片段)。手动创建线程确实没有太多好的理由 - 除非你真的知道你在做什么,以及为什么将它放在专用线程上很重要。
关键是这仅适用于 CPU 作品。您可以轻松地让一个线程同时处理一百个独立的异步任务。当对异步 API 使用 await
时,这尤其容易处理。每个 CPU 的单线程可以轻松获得 100% 的利用率 只要它确实 CPU 工作 。如果没有,无论如何你都想使用异步 I/O - 浪费线程是没有意义的(伴随着它们的内存成本,切换开销,调度程序任务过多,垃圾收集......)而 正在等待.
典型示例是处理某些数据库工作的异步 Web 服务:
string GetUserName(Guid userId)
{
return Db.GetUser(userId).Name;
}
这种同步方法在处理数据库请求时会占用请求线程。如果您的数据库请求需要一秒钟,并且您同时有 2000 个请求,那么您将需要 2000 个线程来处理这些请求。然而,数据库请求只是异步的 I/O - 线程基本上是在等待来自数据库的响应返回。线程浪费等待。
相反,您可以使用异步 API:
async Task<string> GetUserName(Guid userId)
{
var user = await Db.GetUserAsync(userId);
return user.Name;
}
代码几乎相同,但 await
结构实际上并没有阻塞请求线程——它基本上是 "Okay, I'm done, you can use this thread for something else. I'll ping you back when I'm ready to continue."。这种模式意味着您 永远不会 需要比 CPU 内核更多的线程 - 如果 CPU 处于 100%,则添加更多线程来处理负载是没有意义的.如果不是,则意味着某个线程没有执行任何 CPU 工作 - 这很好,当另一项工作出现时将使用它。现在,不是让 2000 个线程处理 2000 个请求,而是有 8 个线程处理 相同 2000 个请求。
我有一台带有 8 核处理器的计算机,我对我的计算机需要使用您的最大潜力的最大线程数(软件,不是处理器线程。)有疑问8 核。
我正在同时创建 160 个线程,所以我的处理器的每个内核将处理大约 20 个线程,对吗?
我的问题是:
- 处理器核心 20 个线程是否合适?
- 独立于线程数运行,它会被内核数平均分吗?
- 如何知道哪个线程数适合我的处理器?
最好的计数是每个虚拟核心一个(具有 HT 的核心计为 2 个虚拟核心)。
但是你不应该通过自己使用来实现这个逻辑 Parallel.ForEach
example taken from msdn, also there are other options look here also if there is alot of delays involved like reading a file or waiting for network traffic i would recommend using async functions (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;
}
}
}
I'm creating 160 threads simultaneous, so each core of my processor will process about ~20 threads, is it correct?
不完全是。每个核心一次只能处理一个线程。当 OS 决定线程有足够的聚光灯时,它将把它切换到另一个线程。如果您可以在 8 个线程中完成相同的工作,那么您将拥有相同的吞吐量以及避免不必要的上下文切换所带来的节省。
20 threads by core of processor is a good number?
没有。每个核心一个线程是现场。超线程核心大约有两个 - 工作效果各不相同。
Independent the number of threads running, its will be divided equality by the number of cores?
没有。这是由操作系统决定的,操作系统在其决策中往往会考虑很多不同的事情。此外,阻塞的线程不会在任何地方执行。实际上,其中一些线程很可能比其他线程占用更多 CPU 时间。
How to know whats the better number of threads according with my processor?
使用比线程更高级别的结构。这意味着将线程池用于简单的工作项,Parallel.For
和系列用于 "synchronous" 并行,异步 Task
s 用于复杂的异步工作任务(包括线程池片段)。手动创建线程确实没有太多好的理由 - 除非你真的知道你在做什么,以及为什么将它放在专用线程上很重要。
关键是这仅适用于 CPU 作品。您可以轻松地让一个线程同时处理一百个独立的异步任务。当对异步 API 使用 await
时,这尤其容易处理。每个 CPU 的单线程可以轻松获得 100% 的利用率 只要它确实 CPU 工作 。如果没有,无论如何你都想使用异步 I/O - 浪费线程是没有意义的(伴随着它们的内存成本,切换开销,调度程序任务过多,垃圾收集......)而 正在等待.
典型示例是处理某些数据库工作的异步 Web 服务:
string GetUserName(Guid userId)
{
return Db.GetUser(userId).Name;
}
这种同步方法在处理数据库请求时会占用请求线程。如果您的数据库请求需要一秒钟,并且您同时有 2000 个请求,那么您将需要 2000 个线程来处理这些请求。然而,数据库请求只是异步的 I/O - 线程基本上是在等待来自数据库的响应返回。线程浪费等待。
相反,您可以使用异步 API:
async Task<string> GetUserName(Guid userId)
{
var user = await Db.GetUserAsync(userId);
return user.Name;
}
代码几乎相同,但 await
结构实际上并没有阻塞请求线程——它基本上是 "Okay, I'm done, you can use this thread for something else. I'll ping you back when I'm ready to continue."。这种模式意味着您 永远不会 需要比 CPU 内核更多的线程 - 如果 CPU 处于 100%,则添加更多线程来处理负载是没有意义的.如果不是,则意味着某个线程没有执行任何 CPU 工作 - 这很好,当另一项工作出现时将使用它。现在,不是让 2000 个线程处理 2000 个请求,而是有 8 个线程处理 相同 2000 个请求。