C# · Programowanie

Parallel.ForEach() i ConcurrentBag

Jakiś czas temu w pracy miałam ciekawy przypadek. Mianowicie – losowo wywalał się jeden z testów. Powodem był NullReferenceException w logice. Żeby dojść do problemu, trzeba było przeanalizować trochę kodu.

Parallel.ForEach()

Zauważyłam, że w pewnym miejscu została użyta pętla Parallel.ForEach(). Dla uproszczenia załóżmy taką logikę:

List<object> myList = new List<object>();
Parallel.ForEach(Enumerable.Range(1, 10), i =>
{
	var items = GetItems(i);
	myList.AddRange(items);
});

Bardzo fajnie, że zamiast zwykłej pętli foreach() na jednym wątku, można zrównoleglić pracę i użyć Parallel.ForEach(). Przykład z Internetów iterujący po 10 elementach pokazuje, że wydajnościowo się to opłaca:

No i super. To w czym tkwi problem?

List<T> vs ConcurrentBag<T>

Problemem jest nieszczęsna lista obiektów List<object> i operacja dodawanie do niej nowych elementów – a więc metoda AddRange(). Zwykła lista nie jest thread safe. W większości przypadków nie było problemów z dostępem do listy i test przechodził. Ale czasami coś poszło nie tak i lista zawierała nulle. Dalsze operacje właśnie na tych nullach powodowały NullReferenceException.

I tutaj wjeżdża na białym koniu nasze rozwiązanie – ConcurrentBag. Thread safe, nieuporządkowana kolekcja. Wystarczy dodać odpowiedni using System.Collections.Concurrent i śmiga:

ConcurrentBag<object> myList = new ConcurrentBag<object>();
Parallel.ForEach(Enumerable.Range(1, 10), i =>
{
	var items = GetItems(i);
	items.ForEach(item => myList.Add(item));
});

I w ten sposób naprawiłam buga 🙂

Macie jakieś ciekawe bugi, które naprawiliście? Podzielcie się!


Podoba Ci się to, co tworzę? Chcesz dostawać informacje o:
– wydarzeniach, które organizuję lub wspieram (np. konferencje, meetupy, webinary)
– inicjatywach, które organizuję lub wspieram (np. GeekWeekWro, DevAdventCalendar)
– moich prelekcjach, kursach i szkoleniach
– wyróżnionych artykułach z mojego bloga

0% SPAMu, 100% informacji! Krótko i na temat.

2 myśli na temat “Parallel.ForEach() i ConcurrentBag

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie na Google

Komentujesz korzystając z konta Google. Wyloguj /  Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

Połączenie z %s