C #에서 BlockingCollection을 사용하는 방법

여러 스레드가 큐를 읽고 쓰는 시나리오를 고려하십시오. 더 구체적으로 말하면, 동일한 시점에 여러 생산자가 데이터를 저장하고 여러 소비자가 공통 데이터 저장소에서 데이터를 검색 할 수 있습니다. 따라서이 데이터에 대한 액세스를 동기화하려면 적절한 동기화 메커니즘이 필요합니다.

BlockingCollection 클래스가 구출되는 정확한 위치입니다. 다른 많은 방법이 있지만이 클래스는 데이터에 대한 액세스를 동기화하는 가장 효율적인 방법 중 하나를 제공합니다. BlockingCollection 클래스는 System.Collections.Concurrent 네임 스페이스에 속합니다.

BlockingCollection이란 무엇입니까?

BlockingCollection은 여러 스레드가 동시에 데이터를 추가 및 제거하도록 할 수있는 스레드로부터 안전한 컬렉션입니다. BlockingCollection 클래스를 통해 .Net으로 표시됩니다. 이 클래스를 사용하여 생산자-소비자 패턴을 구현할 수 있습니다.

생산자-소비자 패턴에는 두 개의 서로 다른 스레드에서 실행되는 두 개의 개별 구성 요소가 있습니다. 여기에는 대기열로 푸시되는 일부 데이터를 생성하는 생산자 구성 요소와 대기열에 저장된 데이터를 소비하는 소비자가 포함됩니다. BlockingCollection을 사용하는 경우 제한된 용량과 사용하려는 컬렉션 유형을 지정할 수 있습니다.

BlockingCollection 형식은 IProducerConsumerCollection 형식의 인스턴스에 대한 래퍼 역할을합니다. 즉, IProducerConsumerCollection 인터페이스를 구현하는 다른 컬렉션에 대한 래퍼 역할을합니다. 예를 들어 ConcurrentBag, ConcurrentQueue 및 ConcurrentStack 클래스는 모두 IProducerConsumerCollection 인터페이스를 구현하므로 BlockingCollection과 함께 사용할 수 있습니다.

IProducerConsumerCollection 인터페이스에는 스레드로부터 안전한 컬렉션 작업에 사용할 수있는 메서드 선언이 포함되어 있습니다. MSDN은 "생산자 / 소비자 사용을위한 스레드로부터 안전한 컬렉션을 조작하는 메서드를 정의합니다.이 인터페이스는 생산자 / 소비자 컬렉션에 대한 통합 표현을 제공하므로 System.Collections.Concurrent.BlockingCollection과 같은 상위 수준 추상화에서 컬렉션을 다음과 같이 사용할 수 있습니다. 기본 저장 메커니즘입니다. "

다음 코드 조각은 문자열의 BlockingCollection 인스턴스를 만드는 방법을 보여줍니다.

var blockingCollection = new BlockingCollection();

BlockingCollection을 사용하는 경우 Add 메서드 또는 TryAdd 메서드를 사용하여 컬렉션에 데이터를 추가 할 수 있습니다. 이제이 두 가지 방법의 차이점을 이해하겠습니다.

BlockingCollection data = new BlockingCollection(boundedCapacity: 3);

data.Add(1);

data.Add(2);

data.Add(3);

data.Add(4); //This would block until an item is removed from the collection.

위에 제공된 코드 조각에 표시된대로 BlockingCollection의 인스턴스를 만들 때 boundedCapacity를 지정하는 방법에 유의하십시오. 컬렉션 인스턴스의 제한된 크기를 나타 내기 위해 지정됩니다.

TryAdd 메서드를 사용하여 BlockingCollection 인스턴스에 항목을 추가 할 수도 있습니다. 이 방법에서는 시간 초과 값을 사용할 수 있습니다. 지정된 시간 내에 추가 작업이 실패하면 TryAdd 메서드는 false를 반환합니다. 다음 코드 조각은 TryAdd 메서드를 활용하여 BlockingCollection의 인스턴스에 항목을 추가하는 방법을 보여줍니다.

BlockingCollection data = new BlockingCollection(boundedCapacity: 3);

data.Add(1);

data.Add(2);

data.Add(3);

if (data.TryAdd(4, TimeSpan.FromMilliseconds(100)))

{

   Console.WriteLine("A new item was successfully added to the collection.");

}

else

{

   Console.WriteLine("Failed to add a new item to the collection.");

}

BlockingCollection에서 항목을 제거하려면 Take 또는 TryTake 메서드를 사용할 수 있습니다. Take 메서드는 컬렉션에 항목이 없으면 차단되고 새 항목이 컬렉션에 추가되는 즉시 차단이 해제됩니다. TryTake 메서드를 사용하여 BlockingCollection의 인스턴스에서 항목을 제거 할 수도 있습니다. 컬렉션에 항목이 추가 될 때까지 메서드가 차단되도록 (지정된 시간이 경과 할 때까지)이 메서드로 시간 제한 값을 지정할 수 있습니다. 이 시간 (시간 초과 지정) 동안 컬렉션에서 항목을 제거 할 수없는 경우 TryTake 메서드는 false를 반환합니다.

다음 코드 조각은 TryTake 메서드를 사용하여 BlockingCollection 유형의 인스턴스에서 항목을 제거하는 방법을 보여줍니다.

int item;

while (data.TryTake(out item, TimeSpan.FromMilliseconds(100)))

{

   Console.WriteLine(item);

}

참조 할 수있는 전체 코드 목록은 다음과 같습니다. 이 프로그램은 BlockingCollection을 사용하여 컬렉션에서 항목을 추가 및 제거하는 방법을 보여줍니다.

 class Program

   {

       private static BlockingCollection data = new BlockingCollection();

       private static void Producer()

       {

           for (int ctr = 0; ctr < 10; ctr++)

           {

               data.Add(ctr);

               Thread.Sleep(100);

           }

       }

       private static void Consumer()

       {

           foreach (var item in data.GetConsumingEnumerable())

           {

               Console.WriteLine(item);

           }

       }

       static void Main(string[] args)

       {

           var producer = Task.Factory.StartNew(() => Producer());

           var consumer = Task.Factory.StartNew(() => Consumer());

           Console.Read();

       }

   }