새로운 함께 ConcurrentBag<T>
.NET 4, 당신은 어떻게 할 때 단지 그것에서 어떤 특정 개체를 제거 할 TryTake()
및 TryPeek()
사용할 수 있습니까?
내가 사용하는 생각하고 TryTake()
내가이라면 단지 목록에 결과 개체 다시 추가 하지 않는 그것을 제거 할,하지만 난 뭔가를 누락 될 수 있습니다 같은 느낌. 이것이 올바른 방법입니까?
답변
짧은 대답 : 쉬운 방법으로는 할 수 없습니다.
ConcurrentBag는 각 스레드에 대한 스레드 로컬 큐를 유지하며 자신의 큐가 비워지면 다른 스레드의 큐만 확인합니다. 항목을 제거했다가 다시 넣으면 제거하는 다음 항목이 다시 동일한 항목이 될 수 있습니다. 항목을 반복적으로 제거했다가 다시 넣으면 모든 항목을 반복 할 수 있다는 보장은 없습니다.
두 가지 대안 :
- 제거 할 항목을 찾을 때까지 모든 항목을 제거하고 기억 한 다음 나중에 다른 항목을 다시 넣으십시오. 두 스레드가 동시에이 작업을 시도하면 문제가 발생합니다.
- ConcurrentDictionary 와 같은 더 적합한 데이터 구조를 사용하십시오 .
답변
당신은 할 수 없습니다. 가방인데 주문되지 않았습니다. 다시 넣으면 끝없는 루프에 갇히게 될 것입니다.
당신은 세트를 원합니다. ConcurrentDictionary로 하나를 에뮬레이션 할 수 있습니다. 또는 잠금으로 자신을 보호하는 HashSet.
답변
ConcurrentBag는 항목을 추가하고 여러 스레드에서 열거 할 수있는 목록을 처리하는 데 유용하며 이름이 제안하는대로 결국 버릴 수 있습니다. 🙂
Mark Byers가 말했듯 이 제거하려는 항목을 포함하지 않는 새 ConcurrentBag를 다시 빌드 할 수 있지만 잠금을 사용하여 여러 스레드 히트로부터이를 보호해야합니다. 이것은 한 줄짜리입니다.
myBag = new ConcurrentBag<Entry>(myBag.Except(new[] { removedEntry }));
이것은 작동하며 ConcurrentBag가 설계된 정신과 일치합니다.
답변
Mark는 ConcurrentDictionary 에서 정확합니다. 가 원하는 방식으로 작동 . ConcurrentBag 를 계속 사용하고 싶다면 효율적이지 않은 다음과 같은 방법을 사용하십시오 .
var stringToMatch = "test";
var temp = new List<string>();
var x = new ConcurrentBag<string>();
for (int i = 0; i < 10; i++)
{
x.Add(string.Format("adding{0}", i));
}
string y;
while (!x.IsEmpty)
{
x.TryTake(out y);
if(string.Equals(y, stringToMatch, StringComparison.CurrentCultureIgnoreCase))
{
break;
}
temp.Add(y);
}
foreach (var item in temp)
{
x.Add(item);
}
답변
언급했듯이 TryTake()
유일한 옵션입니다. 이것은 또한 MSDN 의 예입니다 . Reflector는 다른 숨겨진 내부 방법도 표시하지 않습니다.
답변
public static void Remove<T>(this ConcurrentBag<T> bag, T item)
{
while (bag.Count > 0)
{
T result;
bag.TryTake(out result);
if (result.Equals(item))
{
break;
}
bag.Add(result);
}
}
답변
이것은 내 프로젝트에서 사용중인 확장 클래스입니다. ConcurrentBag에서 단일 항목을 제거 할 수 있으며 가방에서 항목 목록을 제거 할 수도 있습니다.
public static class ConcurrentBag
{
static Object locker = new object();
public static void Clear<T>(this ConcurrentBag<T> bag)
{
bag = new ConcurrentBag<T>();
}
public static void Remove<T>(this ConcurrentBag<T> bag, List<T> itemlist)
{
try
{
lock (locker)
{
List<T> removelist = bag.ToList();
Parallel.ForEach(itemlist, currentitem => {
removelist.Remove(currentitem);
});
bag = new ConcurrentBag<T>();
Parallel.ForEach(removelist, currentitem =>
{
bag.Add(currentitem);
});
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public static void Remove<T>(this ConcurrentBag<T> bag, T removeitem)
{
try
{
lock (locker)
{
List<T> removelist = bag.ToList();
removelist.Remove(removeitem);
bag = new ConcurrentBag<T>();
Parallel.ForEach(removelist, currentitem =>
{
bag.Add(currentitem);
});
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}