[C# 문법] ConcurrentBag - 소개 및 예제

참조


소개

  • ConcurrentBag는 .NET 4.0에 도입된 스레드로부터 안전한 컬렉션 클래스 중 하나입니다.
  • ConcurrentBag을 사용하면 정렬되지 않은 방식으로 객체를 저장할 수 있습니다.
  • ConcurrentBag를 사용하면 여러 스레드가 객체를 저장할 수 있습니다.
  • 동일한 스레드가 생산자 및 소비자 역할을 하는 시나리오에 최적화 되어 있습니다.

    예를 들어, 두 개의 스레드 Thread1, Thread2 가 있습니다. Thread1.은 4개의 객체 1,2,3,4 를 추가했습니다. Thread2는 세 개의 객체 5,6,7을 추가했습니다. 두 스레드가 데이터를 추가한 후 Thread1은 데이터 검색을 시작합니다. Thread1이 1,2,3,4 객체를 추가함에 따라 이러한 항목은 5,6,7보다 선호도가 높아집니다. Thread1이 4개의 항목을 모두 검색한 후 Thread1은 Thread2에 삽입된 데이터 5,6,7을 검색합니다.


ConcurrentBag 객체 생성

  • 다은은 ConcurrentBag 객체 생성하는 구문입니다.
ConcurrentBag<int> bag = new ConcurrentBag<int>();
  • 기존 컬렉션으로 ConcurrentBag를 초기화 할 수도 있습니다.
List<int> ints = new()
{
    1, 2, 3, 4, 5, 6, 7, 8
};

ConcurrentBag<int> bag = new ConcurrentBag<int>(ints);
int count = bag.Count; //returns 8

새 항목 추가

  • 새 항목을 추가하려면 Add 메서드를 이용하면 됩니다.
ConcurrentBag<int> bag = new ConcurrentBag<int>();
bag.Add(1);
bag.Add(2);
  • 위의 예제에서 두 개의 항목 1, 2를 bag에 추가하였습니다.

여러 항목 추가

  • ConcurrentBag는 AddRange 메서드를 제공하지 않습니다.
  • 각 항목에 대해 수동으로 Add 메서드를 호출해야 합니다.
int[] arr = { 1, 2, 3 };

ConcurrentBag<int> bag = new ConcurrentBag<int>();
foreach(var item in arr)
{
    bag.Add(item);
}

모든 항목 계산

  • Bag에 있는 총 항목 수를 반환하는 Count 속성을 제공합니다.
ConcurrentBag<int> bag = new ConcurrentBag<int>();
bag.Add(1);
bag.Add(2);

int count = bag.Count; // return 2

항목 검색

  • 항목을 검색하기 위해 ConcurrentBag는 두 가지 방법을 제공합니다.
    • TryPeek
    • TryTake
  • TryPeek 메서드는 bag에서 하나의 항목을 반환하지만 bag 에서 항목을 제거하지는 않습니다.
  • 항목 검색에 성공하면 true, 실패하면 false를 반환합니다.
ConcurrentBag<int> bag = new ConcurrentBag<int>();
bag.Add(1);
bag.Add(2);

int item;
bool isSucess = bag.TryPeek(out item); //isSuccess=True, item = 2
isSuccess = bag.TryPeek(out item); //isSuccess=True, item = 2
isSuccess = bag.TryPeek(out item); //isSuccess=True, item = 2
  • TryPeek 메서드는 bag에서 항목을 제거하지 않으므로 동일한 마지막 항목을 반복해서 반환합니다.
  • TryTake 메서드는 bag에서 하나의 항목을 반환하고 bag에서 해당 항목을 제거합니다.
  • 항목을 성적으로 검색하면 true, 실패하면 false를 반환합니다.
ConcurrentBag<int> bag = new ConcurrentBag<int>();
bag.Add(1);
bag.Add(2);

int item;
bool isSuccess = bag.TryTake(out item); //isSuccess=True, item = 2
isSuccess = bag.TryTake(out item); //isSuccess=True, item = 1

모든 항목 검색

  • ConcurrentBag는 IEnumerable 인터페이스를 구현하므로 foreach 루프에서 이를 열겨할 수 있습니다.
  • 열거는 ConcurrentBag에서 스레드로부터 안전합니다.
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace interfaceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            ConcurrentBag<int> bag = new ConcurrentBag<int>();

            Task task1 = Task.Factory.StartNew(() =>
            {
                for(int index = 0; index < 10; index++)
                {
                    bag.Add(index);
                    Thread.Sleep(200);
                }
            });

            Task task2 = Task.Factory.StartNew(() =>
            {
                int i = 0;
                while (i != 4)
                {
                    foreach (var item in bag)
                    {
                        Console.WriteLine(i + "-" + item);
                        Thread.Sleep(200);
                    }
                    i++;
                    Thread.Sleep(200);
                }
            });

            Task.WaitAll(task1, task2);
        }
    }
}
  • 위의 예에서는 두 개의 스레드를 생성했습니다.
  • 한 스레드는 bag 항목을 새롭게 추가합니다.
  • 두 번째 스레드가 foreach 루프를 호출하고 있습니다.
  • 두 스레드가 동시에 작동하고 두 번째 스레드가 foreach 루프를 계속해서 호출합니다.
  • 두 번째 스레드는 열거 중에 새 항목이 추가되는 경우 예외를 throw 하지 않습니다.
0-0
1-1
1-0
2-4
2-3
2-2
2-1
2-0
3-9
3-8
3-7
3-6
3-5
3-4
3-3
3-2
3-1
3-0
728x90

이 글을 공유하기

댓글

Designed by JB FACTORY