2012-04-16 1 views
21

한 번에 하나씩이 아니라 ConcurrentBag에 여러 항목을 한 번에 추가 할 수있는 방법이 있습니까? ConcurrentBag에 AddRange() 메서드가 표시되지 않지만 Concat() 메서드가 있습니다. 그러나, 나를 위해 작동하지 않습니다 :ConcurrentBag - 여러 항목 추가?

ConcurrentBag<T> objectList = new ConcurrentBag<T>(); 

timeChunks.ForEach(timeChunk => 
{ 
    List<T> newList = Foo.SomeMethod<T>(x => x.SomeReadTime > timeChunk.StartTime); 
    objectList.Concat<T>(newList); 
}); 

Parallel.ForEach()에 있어야 사용이 코드,하지만 그래서 그것을 해결 할 수있는 위로 변경되었습니다. 변수 newList에는 실제로 객체가 있지만 objectList.Concat <> 행 다음에 objectList는 항상 0 개의 객체가 있습니다. Concat <> 그런 식으로 작동하지 않습니까? Add() 메서드를 사용하여 ConcurrentBag에 항목을 한 번에 하나씩 추가해야합니까?

답변

5

예 :

Concat 아마도 Enumerable 확장 중 하나입니다. ConcurrentBag에 아무 것도 추가하지 않으면 원래 가방을 포함하고있는 펑키 한 오브젝트와 거기에 추가하려고했던 모든 것을 반환합니다.

Concat의 결과가 더 이상 ConcurrentBag이 아니므로주의하시기 바랍니다. 이것은 일반적인 LINQ 프레임 워크의 일부로, 변경 불가능한 시퀀스를 결합 할 수 있습니다. 물론이 프레임 워크는 피연산자의 동시 속성을 결과로 확장하지 않으므로 결과 객체는 다중 스레드 액세스에 적합하지 않습니다.

(이것은 IEnumerable<T> 인터페이스를 노출하기 때문에 기본적으로는 ConcatConcurrentBag에 적용된다.)

19

Concat는 LINQ 의해 제공된 확장 방법. 소스 컬렉션과 그 뒤에 지정된 컬렉션이 열거 될 수있는 또 다른 IEnumerable을 반환하는 불변 조작입니다. 어떠한 방식 으로든 소스 콜렉션을 변경하지는 않습니다.

귀하의 물품을 한 번에 하나씩 ConcurrentBag에 추가해야합니다.

3

데이터 덩어리를 병렬로 처리하려고하는 비슷한 문제가 발생했습니다. 하나의 큰 덩어리가 송신 측의 데이터에 액세스 할 때 사용하는 웹 서비스를 시간 초과했기 때문에 비슷한 문제가 발생했습니다.하지만 느리게 실행되는 것을 원하지 않았습니다. 각 청크를 순차적으로 처리하여 레코드로 데이터 레코드를 처리하는 것은 더 느 렸습니다. 호출 한 서비스가 대량 요청을 처리 할 수 ​​있었기 때문에 가능한 한 많은 시간을 사용하지 않고 제출하는 것이 좋습니다.

블라드 (Vlad)가 말했듯이, 동시 형 가방을 객체 유형의 목록에 연결하면 동시 가방이 반환되지 않으므로 콩코드가 작동하지 않습니다! (내가 할 수 없다는 것을 깨닫는 데는 시간이 걸렸습니다.)

List<T>을 생성 한 다음 ConcurrentBag<List<T>>을 생성하십시오. 각 병렬 반복에서 동시 병합에 새 목록을 추가합니다. 병렬 루프가 완료되면 ConcurrentBag을 반복하고 가능한 중복을 제거하려면 concat (또는 중복을 제거하려는 경우)을 첫 번째 List<T>에 연결하여 모든 것을 하나의 목록으로 "병합"합니다.

+0

끝내려면 SelectMany를 사용하십시오. –

17

(나는 이것이 오래된 게시물 인 것을 알고, 나는 약간의 것을 추가 할 것을 생각했다).

다른 사람들의 의견입니다. 예, 하나씩 추가해야합니다.내 경우, 나는 것들을 조금 청소기를 만들 수있는 작은 확장 메서드를 추가했지만 후드 아래는 같은 일을 수행합니다 다음

public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd) 
    { 
     foreach (var element in toAdd) 
     { 
      @this.Add(element); 
     } 
    } 

그리고 : 나는 또한 AsParallel를 사용하여 보았다

ConcurrentBag<int> ccBag = new ConcurrentBag<int>(); 
    var listOfThings = new List<int>() { 1, 2, 4, 5, 6, 7, 8, 9 }; 
    ccBag.AddRange(listOfThings); 

을 확장 메서드 내에서 추가 할 수 있지만 다양한 크기의 문자열 목록을 추가 할 때 일부 테스트를 실행 한 후에는 기존 for 루프와 달리 AsParallel을 사용하는 것이 더 느립니다.

public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd) 
    { 
     toAdd.AsParallel().ForAll(t => @this.Add(t)); 
    }