[c#] ConcurrentBag <>에서 단일 특정 개체를 제거하는 방법은 무엇입니까?

새로운 함께 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);
        }
    }
}