Domanda

Diciamo che ho avuto un programma in C# che ha fatto qualcosa di computazionalmente costosi, come la codifica di un elenco di file WAV in Mp3.Di solito vorrei codificare i file uno alla volta, ma diciamo che volevo un programma per capire quante core della CPU che ho avuto e che lo spin up di una codifica thread su ogni core.Così, quando ho eseguito il programma su un quad core CPU, il programma è saltato fuori è un quad core CPU, figure ci sono quattro core a lavorare, quindi genera quattro fili per la codifica, ognuno dei quali è in esecuzione su di una propria CPU.Come posso fare questo?

E questo sarebbe diverso se il core, che si distribuiscono su più Cpu fisiche?Come se avessi avuto una macchina con due quad core su di esso, ci sono considerazioni particolari o sono le otto core in due stampi uguali Windows?

È stato utile?

Soluzione

Non preoccupatevi di fare che.

Utilizzare invece il Pool Di Thread.Il pool di thread è un meccanismo (in realtà una classe) del quadro che è possibile eseguire una query per un nuovo thread.

Quando si chiede un nuovo thread si darà una nuova o accodare il lavoro fino a quando un thread averlo liberato.In che modo il quadro è preposto a decidere se si dovrebbe creare più thread o non a seconda del numero di presentare le Cpu.

Edit:Inoltre, come è stato già accennato, il sistema operativo si occupa di distribuire i fili tra le varie Cpu.

Altri suggerimenti

Non è necessariamente così semplice come l'utilizzo del pool di thread.

Per impostazione predefinita, il pool di thread alloca più thread per ogni CPU.Dal momento che ogni thread che viene coinvolto nel lavoro che si sta facendo ha un costo (task switching overhead, l'utilizzo della CPU è molto limitato L1, L2 e forse L3 cache, ecc...), il numero ottimale di thread da utilizzare è <= il numero di CPU - a meno che ogni thread di richiesta di servizi da parte di altre macchine, come altamente scalabile servizio web.In alcuni casi, in particolare quelli che coinvolgono più hard disk la lettura e la scrittura di attività della CPU, si può effettivamente essere meglio con 1 filo di più thread.

Per la maggior parte delle applicazioni, e certamente per i file WAV e MP3 codifica, si dovrebbe limitare il numero di thread di lavoro per il numero di CPU.Ecco alcuni di codice C# per trovare il numero di CPU:

int processors = 1;
string processorsStr = System.Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS");
if (processorsStr != null)
    processors = int.Parse(processorsStr);

Purtroppo, non è così semplice come limitare se stessi per il numero di CPU.Devi anche prendere in considerazione le prestazioni del controller del disco rigido(s) e disco(s).

L'unico modo si può veramente trovare il numero ottimale di thread è la prova un errore.Questo è particolarmente vero quando si utilizza dischi rigidi, servizi web e così via.Con i dischi rigidi, si potrebbe essere meglio non utilizzando tutti e quattro processers su di voi processore quad CPU.D'altra parte, con alcuni servizi web, si potrebbe essere meglio fare 10 o anche 100 richieste per CPU.

Nel caso di thread gestiti, la complessità di questa operazione è di un grado superiore a quello del thread nativi.Questo perché CLR thread non sono direttamente legati a un nativo OS thread.In altre parole, il CLR è in grado di passare un gestito filettatura thread nativi nativi thread, come si vede in forma.La funzione Thread.BeginThreadAffinity è fornito di posto un thread gestito in lock-passo con un sistema operativo nativo thread.A quel punto, si potrebbe sperimentare l'utilizzo delle API native per dare sottostante thread nativi affinità del processore.Come tutti suggerisce qui, questa non è una buona idea.In realtà non c'è documentazione suggerendo che il thread può ricevere un minor tempo di elaborazione se sono limitata a un singolo processore.

Potete anche esplorare il Sistema.Diagnostica.Processo classe.Vi si possono trovare una funzione per enumerare un processo di' thread come una collezione di ProcessThread oggetti.Questa classe ha un metodo per impostare ProcessorAffinity o anche un preferito processore -- non sono sicuro di quello che è.

Disclaimer:Ho avuto un problema simile in cui ho pensato che la CPU(s) sono stati utilizzati sotto e ricercato un sacco di questa roba;tuttavia, sulla base di tutto quello che ho letto, è apparso che non era una buona idea, come evidenziato dai commenti postati qui.Tuttavia, è ancora interessante ed una esperienza di apprendimento per l'esperimento.

Anche se sono d'accordo con la maggior parte delle risposte qui, penso che valga la pena di aggiungere una nuova considerazione:La tecnologia Speedstep.

Durante l'esecuzione di una CPU single threaded lavoro su un sistema multi-core, nel mio caso un Xeon E5-2430 con 6 real core (12 con HT) in windows server 2012, il lavoro si è diffuso tra tutti i 12 core, utilizzando circa 8.33% di ogni anima e di non innescare un aumento di velocità.La CPU è rimasta a 1.2 GHz.

Quando ho impostato il thread affinità per uno specifico core, è utilizzato ~100% di quel nucleo, causando la CPU al massimo a 2,5 GHz, più che raddoppiando le prestazioni.

Questo è il programma che ho usato, che solo loop di aumentare di una variabile.Quando viene chiamato con -a, verrà impostare l'affinità per core 1.L'affinità parte è basata su questo post.

using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;

namespace Esquenta
{
    class Program
    {
        private static int numThreads = 1;
        static bool affinity = false;
        static void Main(string[] args)
        {
            if (args.Contains("-a"))
            {
                affinity = true;
            }
            if (args.Length < 1 || !int.TryParse(args[0], out numThreads))
            {
                numThreads = 1;
            }
            Console.WriteLine("numThreads:" + numThreads);
            for (int j = 0; j < numThreads; j++)
            {
                var param = new ParameterizedThreadStart(EsquentaP);
                var thread = new Thread(param);
                thread.Start(j);
            }

        }

        static void EsquentaP(object numero_obj)
        {
            int i = 0;
            DateTime ultimo = DateTime.Now;
            if(affinity)
            {
                Thread.BeginThreadAffinity();
                CurrentThread.ProcessorAffinity = new IntPtr(1);
            }
            try
            {
                while (true)
                {
                    i++;
                    if (i == int.MaxValue)
                    {
                        i = 0;
                        var lps = int.MaxValue / (DateTime.Now - ultimo).TotalSeconds / 1000000;
                        Console.WriteLine("Thread " + numero_obj + " " + lps.ToString("0.000") + " M loops/s");
                        ultimo = DateTime.Now;
                    }
                }
            }
            finally
            {
                Thread.EndThreadAffinity();
            }
        }

        [DllImport("kernel32.dll")]
        public static extern int GetCurrentThreadId();

        [DllImport("kernel32.dll")]
        public static extern int GetCurrentProcessorNumber();
        private static ProcessThread CurrentThread
        {
            get
            {
                int id = GetCurrentThreadId();
                return Process.GetCurrentProcess().Threads.Cast<ProcessThread>().Single(x => x.Id == id);
            }
        }
    }
}

E i risultati:

results

La velocità del processore, come illustrato da Task manager, simile a quello che CPU-Z riporta:

enter image description here

Non si dovrebbe avere a preoccuparsi di farlo da soli.Ho multithreading .NET applicazioni in esecuzione sul dual-quad macchine, e non importa quanto i fili sono avviati, sia per via ThreadPool o manualmente, vedo una bella anche la distribuzione del lavoro tra tutti i core.

Si può sicuramente farlo scrivendo una routine all'interno del vostro programma.

Tuttavia non si dovrebbe cercare di farlo, dato che il Sistema Operativo è il candidato migliore per gestire queste cose.Voglio dire, in modalità utente programma non dovrebbe provare a farlo.

Tuttavia, a volte, può essere fatto (per davvero avanzato utente) per ottenere il bilanciamento del carico e anche per scoprire il vero multi thread multi core problema (dati racing/coerenza della cache...) come diversi thread sarebbe veramente l'esecuzione su un processore diverso.

Detto questo, se si vuole ancora ottenere lo possiamo fare nel seguente modo.Sto fornendo il pseudo-codice(sistema operativo Windows), tuttavia essi potrebbero facilmente essere fatto su Linux.

#define MAX_CORE 256
processor_mask[MAX_CORE] = {0};
core_number = 0;

Call GetLogicalProcessorInformation();
// From Here we calculate the core_number and also we populate the process_mask[] array
// which would be used later on to set to run different threads on different CORES.


for(j = 0; j < THREAD_POOL_SIZE; j++)
Call SetThreadAffinityMask(hThread[j],processor_mask[j]);
//hThread is the array of handles of thread.
//Now if your number of threads are higher than the actual number of cores,
// you can use reset the counters(j) once you reach to the "core_number".

Dopo questa routine viene chiamata, il thread dovrebbe sempre essere in esecuzione nel modo seguente:

Thread1-> Core1
Thread2-> Core2
Thread3-> Core3
Thread4-> Core4
Thread5-> Core5
Thread6-> Core6
Thread7-> Core7
Thread8-> Core8

Thread9-> Core1
Thread10-> Core2
...............

Per ulteriori informazioni, si prega di fare riferimento al manuale/MSDN per saperne di più su questi concetti.

Dove ogni filo va è generalmente gestita dal sistema operativo stesso...quindi generare 4 thread su un 4 core del sistema e il sistema operativo a decidere quale sia il core per eseguire ciascuna, che di solito 1 filo su ciascun core.

È il sistema operativo ha il compito di dividere le discussioni tra le diverse anime, e fare in modo che quando automaticamente quando il thread utilizzando un sacco di tempo di CPU.Non ti preoccupare di questo.Per scoprire come numero di core del tuo utente, provare Environment.ProcessorCount in C#.

si può fare questo, come unico sistema operativo ha i privilegi per farlo.Se si deciderà.....quindi sarà difficile per le applicazioni di codice.Perché allora è necessario anche prendersi cura per inter-processore di comunicazione.sezioni critiche.per ogni applicazione, è necessario creare la tua semafori o mutex......per il sistema operativo che fornisce una soluzione comune lo stesso.......

Uno dei motivi per cui non dovrebbe (come è stato detto) tenta di assegnare questo genere di cose di te, è che semplicemente non hanno abbastanza informazioni per farlo correttamente, in particolare verso il futuro con NUMA, etc.

Se si dispone di un thread di lettura-to-run, e c'è un nocciolo di inattività, il kernel sarà eseguire il filo, non ti preoccupare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top