10

Chcę przechowywać informacje kontekstowe rejestrowania w TLS, tak aby można było ustawić wartość w punkcie wejścia i mieć tę wartość dostępną we wszystkich wynikowych stosach. To działa dobrze, ale również korzystam z TPL i ThreadPool. Problemem staje się wtedy migracja danych TLS do innych wątków. Mogę to zrobić sam, ale potem tracę dobre metody, takie jak Parallel.Do użytku.Jak zarządzać wątku lokalnego magazynu (TLS) podczas korzystania z TPL?

Czy istnieje sposób na skopiowanie TLS podczas korzystania z licencji TPL? Dotyczy to również C#, gdy pojawi się funkcja oczekująca.

Dzięki Erick

Odpowiedz

5

Zazwyczaj jest obsługiwane za pomocą przeciążenie Parallel.For już przewiduje gwintu lokalnych danych.

To przeciążenie umożliwia podanie inicjatora i delegata finalizacji, co w praktyce staje się inicjalizacją dla wątku dla lokalnych danych wątku, a funkcja redukcji na końcu "scalania" wyników razem (co jest wykonywane raz na wątek). I wrote about this in detail here.

Podstawową formą jest zrobić coś takiego:

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

Dzięki Reedowi - robi to, co chciałem, jednak znalazłem inny sposób rozwiązania tego problemu. Niemniej jednak jest to znakomita rzecz, której będę wkrótce używał. –

+0

Zastanawiam się, dlaczego zawierały tak brzydkie przeciążenie? W takim tempie byłoby czystsze zainicjowanie danych lokalnych dla wątków i deinicjalizacja w głównym delegacie. Chyba że mają zoptymalizowaną perfekcję ...? –

+0

@ TimLovell-Smith Dane lokalne wątku są ponownie wykorzystywane w wielu połączeniach delegowanych, więc nie można ich zainicjować/sfinalizować w jednym uczestniku. (To jest sedno;)) –

4

znalazłem inne rozwiązanie problemu, który nie wymaga kodu. Byłem w stanie użyć CallContext do przyłączenia danych do "logicznego wątku". Te dane są przesyłane z wątku początkowego do wątków generowanych przez TPL, jak również ThreadPool.

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

+5

Po prostu FYI - ten mechanizm jest znacznie, dużo wolniejszy niż przy użyciu TLS, ponieważ serializuje dane przez każde wywołanie kontekstowe ... –

0

Jest oczywiście jeszcze inna alternatywa: Napisz TaskLocal (t) klasy, podobnie jak my, że opiera się na przechowywanie bieżącego zadania, zamiast bieżącego wątku. Szczerze mówiąc, nie mam pojęcia, dlaczego Microsoft nie zrobił tego w ramach ich początkowej implementacji zadań.

Ważne Realizacja UWAGA: Ponieważ kod Zadanie, które wywołuje czekają można podzielić i wznowić jako innym TaskId, trzeba także zrobić to, co my również zrobiliśmy, i wdrożyć metodę w TaskLocal (T), który mapuje nowe TaskIds do poprzednich, następnie zapisz oryginalny TaskId na początku zadania i zamapuj go po każdym oczekiwaniu na połączenie.

+0

Próba kodu demonstrująca to dostałaby +1 ode mnie :-) – JoshBerke

+0

Zobaczę, co mogę zrobić ... (: – Thought

+0

To byłoby świetnie! – JoshBerke

Powiązane problemy