Jak usunąć wszystkie elementy z ConcurrentBag?


Odpowiedzi:


37

Chociaż może to nie być całkowicie jasne ze względu na potencjalny stan wyścigu, jest to wystarczające:

while (!myBag.IsEmpty) 
{
   myBag.TryTake(out T _);
}

23
To zdecydowanie nie jest atomowe. Tak więc nie powinno być dodawane jako metoda rozszerzająca do ConcurrentBag, jak sądzę, ponieważ wszystkie inne metody są używane przy założeniu dostępu atomowego.
— Anupam

Ponadto, czy tryb TryTake nie może się nie powieść z innych powodów niż to, że jest pusty?
— BrainSlugs83,

21
Jest to bardzo niebezpieczne. Jeśli inny proces stale dodaje elementy, może to być zajęte.
— IvoTops

4
Odpowiedź od @Adam Houldsworth + mój komentarz jest lepsza.
— Chris Marisic,

1
jeśli jest to niebezpieczne rozwiązanie, dlaczego nadal przyjmuje się odpowiedź?
— Barış Akkurt

65

Aktualizacja 10/03/2017: Jak słusznie wskazuje @Lou, przypisanie jest niepodzielne. W tym przypadku utworzenie ConcurrentBagwill nie będzie atomowe, ale umieszczenie tego odniesienia w zmiennej będzie atomowe - czyli zablokowanie lubInterlocked.Exchange otaczanie go nie jest ściśle wymagane.

Dalsze czytanie:

przypisanie odniesienia jest niepodzielne, więc dlaczego potrzebne jest Interlocked.Exchange (ref Object, Object)?

Czy przypisanie odwołania jest bezpieczne dla wątków?


Zawsze możesz zablokować dostęp do samej torby i utworzyć jej nową instancję. Przedmioty w torbie będą wtedy kwalifikowały się do GC, jeśli nic innego ich nie trzyma:

lock (something)
{
    bag = new ConcurrentBag();
}

Lub, jak wskazuje Lukazoid:

var newBag = new ConcurrentBag();
Interlocked.Exchange<ConcurrentBag>(ref bag, newBag);

Łatwy sposób na przechowywanie zawartości, jednak zakłada to, że gdy element chce uzyskać dostęp, również zostaje zablokowany - może to być kosztowne i może zniweczyć dostrojenie wydajności, które zaszło w ConcurrentBag samego siebie.

Jeśli wiesz, że w tej chwili nic innego nie będzie miało dostępu do torby, złóż ją i nie zamykaj :-)


Czy nie byłoby lepszym rozwiązaniem, gdybyś zabrał kopię numeru referencyjnego torby w dowolnym miejscu, w którym ją konsumujesz, a potem możesz to zrobić bag = newbezkarnie?
— Chris Marisic,

1
@ChrisMarisic Tak, jeśli w ogóle możesz uniknąć udostępniania danych, nie masz takich problemów. Pytanie nie miało jednak zbyt dużego kontekstu.
— Adam Houldsworth

10
Interlocked.Exchangemoże być lepszy niż zamek
— Lukazoid

5
Jak Interlocked.Exchangedziała, jeśli w momencie wymiany do torby dodaje się kolejną nitkę? Czy to Addsię blokuje w trakcie Exchange?
— Brandon

2
Przydziały są atomowe w .NET, zarówno blokada, jak i Interlocked.Exchangesą tutaj nadmiarowe (i nie zapewniają bezpieczeństwa wątków).
— Lou

24

Wybrana odpowiedź jest pewnego rodzaju obejściem, więc dodaję własne obejście.

Moim rozwiązaniem było przejrzenie wszystkich dostępnych kolekcji w przestrzeni nazw System.Collections.Concurrent, aby znaleźć taką, w której wyczyszczenie wszystkich elementów z kolekcji było trywialne.

ConcurrentStack klasa ma clear () metodę, która usuwa wszystkie elementy z tej kolekcji. W rzeczywistości jest to jedyna kolekcja w przestrzeni nazw (obecnie), która to robi. Tak, musisz Push(T element)zamiast tego Add(T element), ale szczerze mówiąc, warto zaoszczędzić czas.


1
Pomiędzy kolekcjami jest jednak wiele innych ważnych różnic. Na przykład, jeśli chcesz określić, czy dana pozycja znajduje się w kolekcji, jest to zarówno trywialne, jak i wydajne w przypadku torby, ale nie w przypadku stosu.
— Servy

@Servy: Tak, ale nadal. Nie, właściwie zacząłem pisać listę za / przeciw, ale to naprawdę zależy od twoich wymagań. Na przykład kolekcje współbieżne są dobre w przypadku dostępu wielowątkowego, ale żadna z nich nie pozwala na indeksowanie do kolekcji, co może uniemożliwić korzystanie z nich. Pytanie dotyczyło w szczególności opróżnienia równoczesnego worka (i dlatego go spotkałem), a moim wymaganiem było trywialne czyszczenie kolekcji z zabezpieczeniem nici. Moja odpowiedź była taka, żeby zmienić kolekcje.

2
Używam również równoczesnego stosu zamiast worka. To dziwne, że stos ma Clear, a Bag nie. Głównym celem torby jest przechowywanie wartości, sprawdzanie istnienia i usuwanie wszystkich lub pojedynczych. Tak więc stos współbieżny staje się czymś w rodzaju „nieco ograniczonego rzeczywistego worka współbieżnego”.
— Maxim

@Servy, jak możesz skutecznie określić, czy dany element jest zawarty w ConcurrentBag? Nie widzę żadnej natywnej właściwości ani metody, aby to zrobić. To Containssię nie liczy. Jest to metoda rozszerzająca dla ogólnych IEnumerables i nie jest skuteczna.
— Theodor Zoulias

9

W duchu obejść .. ConcurrentDictionary<T, bool>posiada atomic Clear, ale pozwala też szybko sprawdzić czy klucz istnieje. „Szybko” to oczywiście termin względny, ale w zależności od zastosowania może być szybszy niż wyliczanie dużego stosu.


Niezłe! Należy to uznać za typ kontenera wybrany do takich przypadków. ConcurrentStack podobnie.
— Opóźnienie


-2
int cnt = _queue.Count;
for (; cnt > 0; cnt--)
{
     _queue.TryDequeue(out img);
}

Nie wpada w nieskończoną pętlę i oczyszcza zawartość obecnego czasu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.