ConcurrentBag에서 모든 항목을 제거하는 방법은 무엇입니까?


답변:


37

잠재적 인 경쟁 조건으로 인해 완전히 명확하지 않을 수도 있지만 다음으로 충분합니다.

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

23
이것은 확실히 원자 적이 지 않습니다. 따라서 ConcurrentBag의 확장 메서드로 추가해서는 안됩니다. 다른 모든 메서드는 원자 액세스를 가정하여 사용되기 때문입니다.
Anupam 2013 년

또한 TryTake가 비어있는 것 외에 다른 이유로 실패 할 수 없습니까?
BrainSlugs83 2014 년

21
이것은 매우 위험합니다. 다른 프로세스가 항목을 계속 추가하는 경우이 작업은 계속 바쁠 수 있습니다.
IvoTops 2014 년

4
@Adam Houldsworth + 내 의견의 답변이 더 좋습니다.
Chris Marisic

1
이것이 위험한 해결책이라면 왜 여전히 대답이 허용됩니까?
Barış Akkurt 19

65

2017 년 10 월 3 일 업데이트 : @Lou가 올바르게 지적했듯이 할당은 원자 적입니다. 이때, 생성은 ConcurrentBag원자되지 않지만 그 변수에 대한 참조를 퍼팅 것이다 원자 수 - 그래서 잠금 또는 Interlocked.Exchange주위가 반드시 필요한 것은 아니다.

더 읽을 거리 :

참조 할당은 원자 적이므로 Interlocked.Exchange (ref Object, Object)가 필요한 이유는 무엇입니까?

참조 할당은 스레드 세이프입니까?


항상 가방 자체에 대한 액세스를 잠그고 새 인스턴스를 만들 수 있습니다. 가방에 들어있는 항목은 다른 항목이 없으면 GC 대상이됩니다.

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

또는 Lukazoid가 지적한대로 :

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

그러나 내용을 비닝하는 쉬운 방법은 항목이 액세스를 원할 때마다 잠금을 얻는다고 가정합니다. 이것은 비용이 많이 들고 ConcurrentBag자체에 들어간 성능 조정을 무효화 할 수 있습니다 .

이 시점에서 다른 사람이 가방에 접근 할 수 없다는 것을 알고 있다면 날개를 달고기도하고 잠그지 마십시오. :-)


가방을 소비하는 곳에서 가방의 참조 사본을 가져가는 것이 더 나은 해결책이 bag = new아닐까요?
Chris Marisic

1
@ChrisMarisic 예, 데이터 공유를 전혀 피할 수 있다면 이러한 문제가 발생하지 않습니다. 그러나 질문에는 많은 맥락이 없었습니다.
Adam Houldsworth

10
Interlocked.Exchange잠금보다 더있을 수 있습니다
Lukazoid

5
Interlocked.Exchange교환시 다른 스레드가 가방에 추가되면 어떻게 작동합니까? 그 Add동안 잠겨 Exchange있습니까?
Brandon

2
어시 그먼트는 .NET에서 원자 적이며 잠금 및 Interlocked.Exchange여기서 중복됩니다 (스레드 안전성을 제공하지 않음).
Lou

24

선택한 답변은 일종의 해결 방법이므로 자체 해결 방법을 추가하고 있습니다.

내 솔루션은 System.Collections.Concurrent 네임 스페이스 에서 사용 가능한 모든 컬렉션을 확인하여 컬렉션에서 모든 요소를 ​​지우는 것이 사소한 곳을 찾는 것이 었습니다.

ConcurrentStack의 클래스가 가지고 클리어 () 컬렉션의 모든 요소를 제거하는 방법. 사실, 네임 스페이스의 유일한 컬렉션입니다 (현재). 예, Push(T element)대신 해야 Add(T element)하지만 솔직히 시간을 절약 할 가치가 있습니다.


1
그는 컬렉션 사이에 다른 많은 중요한 차이점이 있습니다. 예를 들어, 특정 항목이 컬렉션에 있는지 확인해야하는 경우 가방을 사용하면 간단하고 효율적이지만 스택에서는 사용할 수 없습니다.
Servy

@Servy : 그래도 그래도. 아니요, 사실 저는 장단점 목록을 작성하기 시작했지만 실제로 요구 사항이 무엇인지에 따라 다릅니다. 예를 들어 동시 컬렉션은 멀티 스레드 액세스에 적합하지만 컬렉션에 색인을 생성 할 수있는 것은 없으므로 사용을 방해 할 수 있습니다. 질문은 특히 동시 백을 지우는 것에 관한 것이었고 (이것이 내가 그것을 발견 한 이유입니다) 스레드 안전성으로 컬렉션을 사소하게 지우는 것이 내 요구 사항이었습니다. 내 대답은 컬렉션을 바꾸는 것이 었습니다.

2
나는 또한 가방 대신 동시 스택을 사용합니다. 스택에 Clear와 Bag이없는 것이 이상합니다. 가방의 주요 목적은 값을 저장하고, 존재를 확인하고, 전부 또는 단일을 제거하는 것입니다. 따라서 동시 스택은 "약간 제한된 실제 동시 백"과 유사합니다.
Maxim

@Servy 주어진 항목이 포함되어 있는지 어떻게 효율적으로 결정할 수 ConcurrentBag있습니까? 이를 수행하는 기본 속성이나 방법을 볼 수 없습니다. 는 Contains계산하지 않습니다. 제네릭 IEnumerable의 확장 메서드이며 효율적이지 않습니다.
Theodor Zoulias

9

해결 방법의 정신으로 .. ConcurrentDictionary<T, bool>원자 지우기가 있지만 키가 있는지 신속하게 확인할 수도 있습니다. 'Quickly'는 물론 상대적인 용어이지만 사용량에 따라 큰 스택을 열거하는 것보다 빠를 수 있습니다.


잘 했어! 이는 그러한 인스턴스에 대해 선택된 컨테이너 유형으로 간주되어야합니다. ConcurrentStack도 비슷합니다.
지연 시간


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

무한 루프에 빠지지 않고 현재 시간의 내용을 지 웁니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.