Como posso definir a afinidade do processador no .NET?

Podemos definir dois threads ou duas tarefas para executar com afinidade de processador diferente em um aplicativo C #?

Eu li sobre SetThreadAffinityMask mas não encontrei nenhum exemplo de como isso deve ser usado.

Alternativamente, existe alguma maneira de a TPL (Task Parallel Library) executar dois threads / tarefas com alta prioridade para usar 100% da CPU?

Process objects Process e ProcessThread têm uma propriedade ProcessorAffinity do tipo IntPtr que pode ser manipulada diretamente para ler / alterar a afinidade para até 64 processadores:

using System.Diagnostics; ... Process Proc = Process.GetCurrentProcess(); long AffinityMask = (long)Proc.ProcessorAffinity; AffinityMask &= 0x000F; // use only any of the first 4 available processors Proc.ProcessorAffinity = (IntPtr)AffinityMask; ProcessThread Thread = Proc.Threads[0]; AffinityMask = 0x0002; // use only the second processor, despite availability Thread.ProcessorAffinity = (IntPtr)AffinityMask; ...
using System.Diagnostics; ... Process Proc = Process.GetCurrentProcess(); long AffinityMask = (long)Proc.ProcessorAffinity; AffinityMask &= 0x000F; // use only any of the first 4 available processors Proc.ProcessorAffinity = (IntPtr)AffinityMask; ProcessThread Thread = Proc.Threads[0]; AffinityMask = 0x0002; // use only the second processor, despite availability Thread.ProcessorAffinity = (IntPtr)AffinityMask; ... 

Você também pode usar a propriedade IdealProcessor do thread para permitir que o agendador prefira executar o thread em um processador especificado (sem garantia).

Sim, é assim tão fácil 🙂

Referência: Propriedade MSDN ProcessThread.ProcessorAffinity

Na verdade, o SO é capaz de balancear a carga de seus núcleos / processadores, mas se você quiser usá-lo explicitamente, use o PInvoke . Você passa o id do thread (não gerenciado um!) E mask – o array de bits dos núcleos.

O exemplo a seguir do MSDN mostra como definir a propriedade ProcessorAffinity para uma instância do Notepad de Notepad para o primeiro processador.

 using System; using System.Diagnostics; namespace ProcessThreadIdealProcessor { class Program { static void Main(string[] args) { // Make sure there is an instance of notepad running. Process[] notepads = Process.GetProcessesByName("notepad"); if (notepads.Length == 0) Process.Start("notepad"); ProcessThreadCollection threads; //Process[] notepads; // Retrieve the Notepad processes. notepads = Process.GetProcessesByName("Notepad"); // Get the ProcessThread collection for the first instance threads = notepads[0].Threads; // Set the properties on the first ProcessThread in the collection threads[0].IdealProcessor = 0; threads[0].ProcessorAffinity = (IntPtr)1; } } } 

Na verdade, o .NET Framework e o Windows gerenciam muito bem os encadeamentos, distribuindo-os uniformemente em todos os processadores. No entanto, a distribuição de threads pode ser manipulada manualmente usando Process e ProcessThread .

 using System; using System.Diagnostics; using System.Threading; namespace ThreadTest { class Program { static void Main(string[] args) { //Get the our application's process. Process process = Process.GetCurrentProcess(); //Get the processor count of our machine. int cpuCount = Environment.ProcessorCount; Console.WriteLine("CPU Count : {0}", cpuCount); //Since the application starts with a few threads, we have to //record the offset. int offset = process.Threads.Count; Thread[] threads = new Thread[cpuCount]; Console.WriteLine(process.Threads.Count); LogThreadIds(process); //Create and start a number of threads that equals to //our processor count. for (int i = 0; i < cpuCount; ++i) { Thread t = new Thread(new ThreadStart(Calculation)) { IsBackground = true }; t.Start(); } //Refresh the process information in order to get the newest //thread list. process.Refresh(); Console.WriteLine(process.Threads.Count); LogThreadIds(process); //Set the affinity of newly created threads. for (int i = 0; i < cpuCount; ++i) { //process.Threads[i + offset].ProcessorAffinity = (IntPtr)(1L << i); //The code above distributes threads evenly on all processors. //But now we are making a test, so let's bind all the threads to the //second processor. process.Threads[i + offset].ProcessorAffinity = (IntPtr)(1L << 1); } Console.ReadLine(); } static void Calculation() { //some extreme loads. while (true) { Random rand = new Random(); double a = rand.NextDouble(); a = Math.Sin(Math.Sin(a)); } } static void LogThreadIds(Process proc) { //This will log out all the thread id binded to the process. //It is used to test whether newly added threads are the latest elements //in the collection. Console.WriteLine("===Thread Ids==="); for (int i = 0; i < proc.Threads.Count; ++i) { Console.WriteLine(proc.Threads[i].Id); } Console.WriteLine("===End of Thread Ids==="); } } } 

Agora verifique o gerenciador de tarefas, podemos ver que o segundo processador está tomando todas as cargas de trabalho. A janela do gerenciador de tarefas