10

Desidero memorizzare le informazioni di contesto di registrazione in TLS in modo che sia possibile impostare un valore nel punto di ingresso e avere il valore disponibile in tutti gli stack risultanti. Funziona bene, ma uso anche TPL e ThreadPool. Il problema diventa quindi come migrare i dati TLS negli altri thread. Posso fare tutto da solo, ma poi perdo metodi carini come Parallel. Per.Come gestire Thread Local Storage (TLS) quando si utilizza TPL?

C'è un modo per copiare TLS quando si utilizza TPL? Ciò si applica anche a C# quando ottiene la funzione Attendi.

Grazie, Erick

risposta

5

Tipicamente, questo è gestita tramite utilizzando un sovraccarico di Parallel.For che già prevede dati locali filettatura.

Questo sovraccarico consente di fornire un delegato di inizializzazione e finalizzazione, che diventa effettivamente un'inizializzazione per thread per i dati locali del thread e una funzione di riduzione alla fine di "unire" i risultati insieme (che viene eseguito una volta per filo). I wrote about this in detail here.

La forma di base è quello di fare qualcosa di simile:

object sync = new object(); 
double result = 0; 

Parallel.For(0, collection.Count, 
    // Initialize thread local data: 
    () => new MyThreadSpecificData(), 
    // Process each item 
    (i, pls, currentThreadLocalData) => 
    { 
     // Generate a NEW version of your local state data 
     MyThreadSpecificData newResults = ProcessItem(collection, i, currentThreadLocalData); 
     return newResults; 
    }, 
    // Aggregate results 
    threadLocalData => 
    { 
     // This requires synchronization, as it happens once per thread, 
     // but potentially simultaneously 
     lock(sync) 
      result += threadLocalData.Results; 
    }); 
+0

Grazie Reed - questo fa quello che volevo, tuttavia ho trovato un modo diverso per affrontare il problema. Tuttavia, questa è roba eccellente che userò presto. –

+0

Mi chiedo perché hanno incluso un brutto sovraccarico? A quel ritmo sarebbe più pulito solo per inizializzare i dati locali del thread e deinitializzarli nel delegato principale. A meno che non lo abbiano perf-ottimizzato ..? –

+0

@ TimLovell-Smith I dati locali del thread vengono riutilizzati in più chiamate delegate, pertanto non possono essere inizializzati/finalizzati all'interno di un singolo delegato. (Questo è il punto;)) –

4

ho trovato un'altra soluzione al problema che non richiede il codice. Sono stato in grado di utilizzare CallContext per allegare i dati a un "thread logico". Questi dati vengono trasferiti dalla thread iniziale ai thread generati da TPL e ThreadPool.

http://www.wintellect.com/CS/blogs/jeffreyr/archive/2010/09/27/logical-call-context-flowing-data-across-threads-appdomains-and-processes.aspx

+5

Solo FYI - Questo meccanismo è molto, molto più lento di usare TLS, dato che serializza i dati attraverso ogni chiamata di contesto ... –

0

V'è, ovviamente, ancora un'altra alternativa: Scrivere una classe TaskLocal (T), come abbiamo fatto noi, che fonda la memorizzazione sulla corrente Task, piuttosto che il thread corrente. Onestamente, non ho idea del motivo per cui Microsoft non ha fatto questo come parte della loro implementazione iniziale delle attività.

Nota importante Implementazione: Poiché il codice attività che chiama await può essere divisa, e riprendere come diversa TaskId, è anche bisogno di fare quello che abbiamo fatto anche, e implementare un metodo in TaskLocal (T) che mappa le nuove TaskIds a quelli precedenti, quindi salva il TaskId originale all'inizio dell'attività e mappalo dopo ogni chiamata in attesa.

+0

Un esempio di codice che dimostra questo otterrebbe un +1 da me :-) – JoshBerke

+0

Vedrò cosa posso fare ... (: – Thought

+0

Sarebbe fantastico! – JoshBerke

Problemi correlati