2011-11-17 15 views
8

Mam tabelę z danymi zawierającą podsumowania wpisów, a moje oprogramowanie musi przejść przez usługę sieci Web, aby uzyskać szczegółowe informacje, a następnie zapisać te dane z powrotem w bazie danych. Zapętlanie przez tabelę synchronicznie podczas wywoływania usługi sieciowej i czekanie na odpowiedź jest zbyt wolne (są tysiące wpisów), więc chciałbym wziąć wyniki (10 lub więcej w tym samym czasie) i wyłaczyć je tak, aby wykonywało 10 operacje w tym samym czasie.Najlepszy sposób zarządzania pulą wątków w kolejce do bazy danych

Moje doświadczenie z wątkami C# jest ograniczone do najmniejszego, więc jakie jest najlepsze podejście? Czy .NET ma jakiś system kolejki wątków, którego mogę użyć, aby upewnić się, że wyniki zostaną poprawnie obsłużone i po kolei?

+2

Jakiej wersji .Net używasz? Istnieją duże ulepszenia w programowaniu wielowątkowym w .Net 4. – svick

+0

Powinno to uwzględnić. Obecnie kierujemy się na 3.5, ale mogę przejść 4.0 bez większych problemów. –

Odpowiedz

5

W zależności od wersji .NET Framework masz dwie całkiem dobre opcje.

Możesz użyć ThreadPool.QueueUserWorkItem w dowolnej wersji.

int pending = table.Rows.Count; 
var finished = new ManualResetEvent(false); 
foreach (DataRow row in table.Rows) 
{ 
    DataRow capture = row; // Required to close over the loop variable correctly. 
    ThreadPool.QueueUserWorkItem(
    (state) => 
    { 
     try 
     { 
     ProcessDataRow(capture); 
     } 
     finally 
     { 
     if (Interlocked.Decrement(ref pending) == 0) 
     { 
      finished.Set(); // Signal completion of all work items. 
     } 
     } 
    }, null); 
} 
finished.WaitOne(); // Wait for all work items to complete. 

Jeśli używasz .NET Framework 4.0 można użyć Task Parallel Library.

var tasks = new List<Task>(); 
foreach (DataRow row in table.Rows) 
{ 
    DataRow capture = row; // Required to close over the loop variable correctly. 
    tasks.Add(
    Task.Factory.StartNew(
    () => 
     { 
     ProcessDataRow(capture);   
     })); 
} 
Task.WaitAll(tasks.ToArray()); // Wait for all work items to complete. 

Istnieje wiele innych rozsądnych sposobów, aby to zrobić. Podkreślam powyższe schematy, ponieważ są one łatwe i działają dobrze. Wobec braku konkretnych szczegółów nie mogę powiedzieć na pewno, że albo będzie idealnie pasować do twojej sytuacji, ale powinny być dobrym punktem wyjścia.

Aktualizacja:

miałem krótki okres aktywności mózgowej poniżej normy. Jeśli masz dostępną TPL, możesz również użyć metody Parallel.ForEach jako prostszej metody niż wszystkie powyższe, wymienione powyżej.

Parallel.ForEach(table.Rows, 
    (DataRow row) => 
    { 
    ProcessDataRow(row); 
    }); 
+0

Nawiasem mówiąc, w rzeczywistości możesz korzystać z licencji TPL w wersji 3.5, jeśli pobierzesz backport Reactive Extensions ze strony Microsoftu. –

+0

Niesamowite rzeczy - wielkie dzięki dla wszystkich. Wygląda na to, że istnieje kilka sposobów na skórze tego kota! –

+0

Tylko jedna rzecz (i wiem, pójdę RTFM!), Ale jak to skalować? Będę wykonywać tysiące tych wierszy i na pewno nie chcę zaczynać jednocześnie tysięcy wątków. Zakładam (mam nadzieję?) jest wbudowany jakiś limit, więc nie powoduje to zatrzymania komputera użytkownika. –

5

Czy .NET ma jakiś system kolejkowania wątków, z którego mogę korzystać, aby upewnić się, że wyniki zostaną poprawnie przetworzone i uporządkowane?

To było coś, co dodano w .NET 4. Domyślnie klasa BlockingCollection<T> działa jako kolejka wątków dla scenariuszy producent/konsument.

Ułatwia tworzenie wielu elementów, które "konsumują" z kolekcji i procesu, z jednym lub więcej elementami dodającymi do kolekcji.

+0

Bardzo ładne, na pewno to sprawdzę. Dzięki! –

+0

Co z kolejką równoczesną? http://msdn.microsoft.com/en-us/library/dd267265.aspx? – Dykam

+0

@Dykam 'BlockingCollection ', domyślnie, opakowuje 'ConcurrentQueue '. Chociaż możesz użyć CQ bezpośrednio, jeśli chcesz pracować w scenariuszu producenta/konsumenta, tak jak to opisano, BC czyni to znacznie prostszym. –

Powiązane problemy