Modelli comuni per applicazioni multithreading con comportamenti non validiCommon patterns for poorly-behaved multithreaded applications

Il visualizzatore di concorrenza consente agli sviluppatori di visualizzare il comportamento di un'applicazione multithreading.The Concurrency Visualizer helps developers to visualize the behavior of a multithreaded application. Questo strumento include una raccolta di modelli comuni per applicazioni multithreading con comportamenti non validi.This tool includes a gallery of common patterns for multithreaded applications that behave badly. La raccolta include modelli visivi tipici e riconoscibili esposti tramite lo strumento, insieme a una spiegazione del comportamento rappresentato da ogni modello, il risultato probabile di tale comportamento e l'approccio più comune per risolverlo.The gallery includes typical and recognizable visual patterns that are exposed through the tool, together with an explanation of the behavior that is represented by each pattern, the likely result of that behavior, and the most common approach to resolve it.

Conflitti di blocco ed esecuzione serializzataLock contention and serialized execution

Conflitti di blocco con conseguente esecuzione serializzataLock contention resulting in serialized execution

In alcuni casi un'applicazione parallelizzata continua a funzionare in modo seriale anche se ha più thread e il computer dispone di un numero sufficiente di core logici.Sometimes a parallelized application stubbornly continues to execute serially even though it has several threads and the computer has a sufficient number of logical cores. Il primo sintomo è costituito da scarse prestazioni multithreading, talvolta addirittura leggermente inferiori rispetto a un'implementazione seriale.The first symptom is poor multithreaded performance, perhaps even a bit slower than a serial implementation. In qualsiasi momento nella visualizzazione Thread non è visibile l'esecuzione di più thread in parallelo, ma di un solo thread.In Threads View, you do not see multiple threads running in parallel; instead, you see that only one thread is executing at any time. A questo punto, se si fa clic su un segmento di sincronizzazione in un thread, è possibile visualizzare uno stack di chiamate per il thread bloccato (stack di chiamate di blocco) e il thread che ha rimosso la condizione di blocco (stack di chiamate di sblocco).At this point, if you click a synchronization segment in a thread, you can see a call stack for the blocked thread (blocking call stack) and the thread that removed the blocking condition (unblocking call stack). Se lo stack di chiamate di sblocco si verifica nel processo che si sta analizzando, viene visualizzato anche un connettore pronto per thread.In addition, if the unblocking call stack occurs in the process that you are analyzing, a Thread-Ready connector is displayed. A questo punto, dagli stack di chiamate di blocco e di sblocco è possibile passare al codice per analizzare in modo più approfondito la causa della serializzazione.From this point, you can navigate to your code from the blocking and unblocking call stacks to investigate the cause of serialization even more.

Come illustrato nella figura seguente, il visualizzatore di concorrenza può esporre questo sintomo anche nella visualizzazione Utilizzo CPU, dove è evidente che, nonostante la presenza di più thread, l'applicazione utilizza un solo core logico.As shown in the following illustration, the Concurrency Visualizer can also expose this symptom in the CPU Utilization View, where, despite the presence of multiple threads, the application consumes only one logical core.

Per altre informazioni, vedere la sezione "Start with the problem" (Partire dal problema) dell'articolo di MSDN Magazine Thread Performance - Resource Contention Concurrency Profiling in Visual Studio 2010 (Prestazioni dei thread: profilatura della concorrenza dei conflitti di risorse in Visual Studio 2010).For more information, see the "Start with the problem section" in the MSDN Magazine article Thread Performance - Resource Contention Concurrency Profiling in Visual Studio 2010.

Conflitti di bloccoLock Contention

Distribuzione ineguale del carico di lavoroUneven workload distribution

Carico di lavoro inegualeUneven workload

Quando si verifica una distribuzione irregolare del lavoro tra diversi thread paralleli in un'applicazione, man mano che ogni thread completa il proprio lavoro viene visualizzato un tipico modello a gradini, come illustrato nella figura precedente.When an irregular distribution of work occurs across several parallel threads in an application, a typical stair-step pattern appears as each thread completes its work, as shown in the previous illustration. Nella maggior parte dei casi il visualizzatore di concorrenza indica orari di inizio molto ravvicinati per ogni thread simultaneo.The Concurrency Visualizer most often shows very close start times for each concurrent thread. Tuttavia, anziché terminare simultaneamente, questi thread di solito terminano in modo irregolare.However, these threads typically end in an irregular manner instead of ending simultaneously. Questo modello indica una distribuzione irregolare del lavoro all'interno di un gruppo di thread paralleli. Ciò potrebbe causare una diminuzione delle prestazioni.This pattern indicates an irregular distribution of work among a group of parallel threads, which could lead to decreased performance. L'approccio migliore a questo problema consiste nel rivalutare l'algoritmo tramite il quale il lavoro viene suddiviso tra i thread paralleli.The best approach to such a problem is to reevaluate the algorithm by which work has been divided among the parallel threads.

Come illustrato nella figura seguente, il visualizzatore di concorrenza può esporre questo sintomo anche nella visualizzazione Utilizzo CPU, dove l'utilizzo della CPU viene rappresentato sotto forma di una scala discendente.As shown in the following illustration, the Concurrency Visualizer can also expose this symptom in the CPU Utilization View as a gradual step-down in CPU utilization.

Carico di lavoro inegualeUneven workload

OversubscriptionOversubscription

OversubscriptionOversubscription

In caso di oversubscription, il numero di thread attivi in un processo è maggiore del numero di core logici disponibili nel sistema.In the case of oversubscription, the number of active threads in a process is larger than the number of available logical cores on the system. L'illustrazione precedente mostra i risultati dell'oversubscription con una significativa rappresentazione per bande della precedenza in tutti i thread attivi.The previous illustration shows the results of oversubscription, with significant preemption banding in all active threads. La legenda, poi, indica che una percentuale elevata di tempo (l'84% in questo esempio) viene impiegata nella precedenza.In addition, the legend shows a large percentage of time is spent in Preemption (84 percent in this example). Questo può indicare che il processo richiede al sistema di eseguire più thread simultanei rispetto al numero di core logici.This may indicate that the process is asking the system to execute more concurrent threads than the number of logical cores. Tuttavia, questo potrebbe indicare anche che altri processi nel sistema stanno usando le risorse che dovrebbero invece essere disponibili per il processo in questione.However, this may also indicate that other processes on the system are using resources that were assumed to be available to this process.

Quando si valuta questo problema è opportuno considerare quanto segue:You should consider the following when you evaluate this problem:

  • Potrebbe essersi verificata l'oversubscription di tutto il sistema.The overall system may be oversubscribed. Prendere in considerazione la possibilità che altri processi nel sistema abbiano assunto la precedenza sui thread in questione.Consider that other processes on the system may be preempting your threads. Quando si sofferma il mouse su un segmento di precedenza nella visualizzazione Thread, un tooltip identifica il thread e il processo che ha assunto la precedenza su di esso.When you pause over a preemption segment in the threads view, a tooltip will identify the thread and the process that preempted the thread. Quest'ultimo può non essere l'unico ad essere stato eseguito durante l'intero periodo di esecuzione del processo che interessa, ma rappresenta un indizio di ciò che ha creato la pressione di precedenza su di esso.This process is not necessarily the one that executed during the whole time that your process was preempted, but it provides a hint about what created the preemption pressure against your process.

  • Valutare in che modo il processo determina il numero di thread appropriato per l'esecuzione durante questa fase di lavoro.Evaluate how your process determines the appropriate number of threads for execution during this phase of work. Se il processo calcola direttamente il numero di thread paralleli attivi, è consigliabile considerare la possibilità di modificare l'algoritmo corrispondente per tener conto in modo più efficiente del numero di core logici disponibili nel sistema.If your process directly calculates the number of active parallel threads, consider modifying that algorithm to better account for the number of available logical cores on the system. Se si usa il runtime di concorrenza, la Task Parallel Library o PLINQ, il calcolo del numero di thread viene eseguito da queste librerie.If you use the Concurrency Runtime, the Task Parallel Library, or PLINQ, these libraries perform the work of calculating the number of threads.

I/O inefficienteInefficient I/O

I/O inefficienteInefficient I/O

Un uso eccessivo o improprio delle operazioni di I/O è una causa comune dell'inefficienza delle applicazioni.Overuse or misuse of I/O is a common cause of inefficiencies in applications. Osservare l'illustrazione precedente.Consider the previous illustration. Il profilo cronologia visibile indica che il 44% della durata visibile dei thread viene utilizzata da operazioni di I/O.The Visible Timeline Profile shows that 44 percent of the visible thread time is consumed by I/O. La cronologia mostra un gran numero di operazioni di I/O, il che indica che l'applicazione sottoposta a profilatura è spesso bloccata da queste.The timeline shows large amounts of I/O, which indicates that the profiled application is frequently blocked by I/O. Per vedere i dettagli relativi al tipo di operazioni I/O e ai punti in corrispondenza dei quali il programma si blocca, fare zoom avanti sulle aree problematiche, esaminare il profilo cronologia visibile e quindi fare clic su un blocco I/O specifico per visualizzare gli stack di chiamate correnti.To see details about the kinds of I/O and where your program is blocked, zoom into problematic regions, examine the Visible Timeline Profile, and then click a specific I/O block to see current call stacks.

Serie di istruzioni di bloccoLock convoys

Serie di istruzioni di bloccoLock convoys

Le serie di istruzioni di blocco si verificano quando l'applicazione acquisisce blocchi in base al principio del primo arrivato e la frequenza di arrivo in corrispondenza del blocco è maggiore della frequenza di acquisizione.Lock convoys occur when the application acquires locks in a first-come, first-served order, and when the arrival rate at the lock is higher than the acquisition rate. A causa della combinazione di queste due condizioni le richieste per il blocco iniziano ad accumularsi.The combination of these two conditions causes requests for the lock to start backing up. Per opporsi a questo problema è possibile fare uso di blocchi "non equi", ovvero blocchi che danno accesso al primo thread che li trova in stato sbloccato.One way to combat this problem is to use "unfair" locks, or locks that give access to the first thread to find them in unlocked states. L'illustrazione precedente mostra questo tipo di comportamento delle serie di istruzioni.The previous illustration shows this convoy behavior. Per risolvere il problema, ridurre i conflitti tra gli oggetti di sincronizzazione e usare blocchi non equi.To solve the problem, try reducing contention for the synchronization objects and try using unfair locks.

Vedere ancheSee also

Visualizzazione ThreadThreads View