web-dev-qa-db-fra.com

Comment définir l'affinité de processeur dans .NET?

Pouvons-nous définir deux threads ou deux tâches à exécuter avec une affinité de processeur différente dans une application C #?

J'ai lu sur SetThreadAffinityMask mais je n'ai trouvé aucun exemple d'utilisation.

Sinon, existe-t-il un moyen pour TPL (Task Parallel Library) d’exécuter deux threads/tâches hautement prioritaires pour utiliser 100% de la CPU?

22
mita

Les objets Process et ProcessThread ont une propriété ProcessorAffinity de type IntPtr qui peut être manipulée directement pour lire/modifier l'affinité pour un maximum de 64 processeurs:


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;
...

Vous pouvez également utiliser la propriété IdealProcessor du thread pour permettre au planificateur de préférer exécuter le thread sur un processeur spécifié (sans garantie).

Oui, c'est aussi simple que ça :)

Référence: Propriété MSDN ProcessThread.ProcessorAffinity

43
Phillip

En fait, le système d’exploitation est capable d’équilibrer la charge de vos cœurs/processeurs, mais si vous voulez le faire, utilisez explicitement mentionné via PInvoke . Vous transmettez l'ID du fil (non géré!) Et le masque - le tableau de bits de cœurs.

2
Andrey

L'exemple suivant tiré de MSDN montre comment définir la propriété ProcessorAffinity pour une instance de Notepad sur le premier processeur.

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;
        }
    }
}
1
user3599701

En fait, .NET Framework et Windows gèrent très bien les threads, en les distribuant de manière égale sur chaque processeur. Cependant, la distribution des threads pouvez être manipulé manuellement en utilisant Process et 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===");
        }
    }
}

Maintenant, vérifiez le gestionnaire de tâches, vous pouvez voir que le second processeur prend toutes les charges de travail. La fenêtre du gestionnaire de tâches

1
Fawkes Flammer
Process.GetCurrentProcess().ProcessorAffinity = (System.IntPtr)2; 
0
Amey Vartak