[c#] 목록에 추가하는 Parallel.ForEach

네트워크를 통해 원격 사이트에 연결하고 일반 목록을 반환하는 여러 기능을 실행하려고합니다. 하지만 동시에 실행하고 싶습니다.

예를 들면 :

public static List<SearchResult> Search(string title)
{
    //Initialize a new temp list to hold all search results
    List<SearchResult> results = new List<SearchResult>();

    //Loop all providers simultaneously
    Parallel.ForEach(Providers, currentProvider =>
    {
        List<SearchResult> tmpResults = currentProvider.SearchTitle((title));

        //Add results from current provider
        results.AddRange(tmpResults);
    });

    //Return all combined results
    return results;
}

내가보기에 ‘결과’에 대한 여러 삽입이 동시에 발생할 수 있습니다. 이로 인해 애플리케이션이 중단 될 수 있습니다.

이것을 어떻게 피할 수 있습니까?



답변

//In the class scope:
Object lockMe = new Object();

//In the function
lock (lockMe)
{
     results.AddRange(tmpResults);
}

기본적으로 잠금은 하나의 스레드 만 해당 중요 섹션에 동시에 액세스 할 수 있음을 의미합니다.


답변

동시 컬렉션을 사용할 수 있습니다 .

System.Collections.Concurrent네임 스페이스에서 해당 유형의 장소에서 사용되어야합니다 여러 스레드 안전 컬렉션 클래스 제공 System.CollectionsSystem.Collections.Generic복수의 thread가 동시에 컬렉션에 액세스 할 때마다 네임 스페이스를.

예를 들어 ConcurrentBag항목이 추가 될 순서를 보장 할 수 없기 때문에 사용할 수 있습니다.

스레드로부터 안전하고 순서가 지정되지 않은 개체 컬렉션을 나타냅니다.


답변

코드를 선호하는 사람들을 위해 :

public static ConcurrentBag<SearchResult> Search(string title)
{
    var results = new ConcurrentBag<SearchResult>();
    Parallel.ForEach(Providers, currentProvider =>
    {
        results.Add(currentProvider.SearchTitle((title)));
    });

    return results;
}


답변

동시 컬렉션은 .Net 4의 새로운 기능입니다. 새로운 병렬 기능과 함께 작동하도록 설계되었습니다.

.NET Framework 4의 동시 컬렉션을 참조하세요 .

.NET 4 이전에는 여러 스레드가 단일 공유 컬렉션에 액세스 할 수있는 경우 고유 한 동기화 메커니즘을 제공해야했습니다. 컬렉션을 잠 가야했습니다 …

… System.Collections.Concurrent의 [새로운] 클래스와 인터페이스 [.NET 4에 추가됨]는 스레드 간의 공유 데이터와 관련된 […] 다중 스레드 프로그래밍 문제에 대한 일관된 구현을 제공합니다.


답변

이것은 PLINQ AsParallelSelectMany다음을 사용하여 간결하게 표현할 수 있습니다 .

public static List<SearchResult> Search(string title)
{
    return Providers.AsParallel()
                    .SelectMany(p => p.SearchTitle(title))
                    .ToList();
}


답변