programing

동시 가방 대 목록

minimums 2023. 6. 17. 08:54
반응형

동시 가방목록

목록(내 유형)만 사용하는 것에 비해 동시에 가방(내 유형)을 사용하는 것의 이점은 무엇입니까?CB의 MSDN 페이지에는 다음과 같이 나와 있습니다.

ConcurrentBag(Of T)는 동일한 스레드가 백에 저장된 데이터를 생성하고 소비하는 시나리오에 최적화된 스레드 세이프 백 구현입니다.

그렇다면 이점은 무엇일까요?Concurrency 네임스페이스에서 다른 컬렉션 유형의 이점을 이해할 수 있지만, 이는 저를 어리둥절하게 했습니다.

내부적으로 ConcurrentBag는 여러 개의 서로 다른 목록(각 쓰기 스레드에 하나씩)을 사용하여 구현됩니다.

당신이 인용한 문장은 가방에서 읽을 때 해당 스레드에 대해 작성된 목록의 우선순위를 지정한다는 것을 의미합니다.즉, 다른 스레드의 목록에서 경합이 발생하기 전에 먼저 해당 스레드의 목록을 확인합니다.

이렇게 하면 여러 스레드가 읽고 쓸 때 잠금 경합을 최소화할 수 있습니다.읽기 스레드에 목록이 없거나 목록이 비어 있으면 다른 스레드에 할당된 목록을 잠가야 합니다.그러나 여러 개의 스레드가 모두 자신의 목록에서 읽고 쓰는 경우 잠금 경합이 발생하지 않습니다.

여기서 가장 큰 장점은ConcurrentBag<T>여러 스레드에서 액세스하는 것이 안전합니다.LisT<T>아닙니다.스레드 안전 액세스가 시나리오에 중요한 경우 다음과 같은 유형이 있습니다.ConcurrentBag<T>보다 당신에게 유리할 수 있습니다.List<T>수동 잠금이 질문에 대답하기 전에 귀하의 시나리오에 대해 좀 더 알아야 합니다.

또한.List<T>주문형 컬렉션입니다.ConcurrentBag<T>아닙니다.

TLDR: 로컬 잠금이 더 빠르지만 차이는 무시할 수 있습니다(또는 테스트를 설정했습니다).

성능 분석:

private static IEnumerable<string> UseConcurrentBag(int count)
    {
        Func<string> getString = () => "42";

        var list = new ConcurrentBag<string>();
        Parallel.For(0, count, o => list.Add(getString()));
        return list;
    }

    private static IEnumerable<string> UseLocalLock(int count)
    {
        Func<string> getString = () => "42";
        var resultCollection = new List<string>();
        object localLockObject = new object();
        Parallel.For(0, count, () => new List<string>(), (word, state, localList) =>
        {
            localList.Add(getString());
            return localList;
        },
            (finalResult) => { lock (localLockObject) resultCollection.AddRange(finalResult); }
            );

        return resultCollection;
    }

    private static void Test()
    {
        var s = string.Empty;
        var start1 = DateTime.Now;
        var list = UseConcurrentBag(5000000);
        if (list != null)
        {
            var end1 = DateTime.Now;
            s += " 1: " + end1.Subtract(start1);
        }

        var start2 = DateTime.Now;
        var list1 = UseLocalLock(5000000);
        if (list1 != null)
        {
            var end2 = DateTime.Now;
            s += " 2: " + end2.Subtract(start2);
        }

        if (!s.Contains("sdfsd"))
        {
        }
    }

5M 레코드를 사용하여 ConcurrentBag를 3회 실행하면 오류가 발생할 수

" 1: 00:00:00.4550455 2: 00:00:00.4090409"
" 1: 00:00:00.4190419 2: 00:00:00.4730473"
" 1: 00:00:00.4780478 2: 00:00:00.3870387"

동시 실행 3회 실행(5M 레코드의 로컬 잠금 대비):

" 1: 00:00:00.5070507 2: 00:00:00.3660366"
" 1: 00:00:00.4470447 2: 00:00:00.2470247"
" 1: 00:00:00.4420442 2: 00:00:00.2430243"

5,000만 개의 레코드로

" 1: 00:00:04.7354735 2: 00:00:04.7554755"
" 1: 00:00:04.2094209 2: 00:00:03.2413241"

로컬 잠금이 조금 더 빠릅니다.

업데이트: (Xeon X5650 @ 2.67GHz 64비트 Win76 코어) 'local lock'이 훨씬 더 나은 성능을 발휘하는 것 같습니다.

5천만 개의 레코드로.

1: 00:00:09.7739773 2: 00:00:06.8076807
1: 00:00:08.8858885 2: 00:00:04.6184618
1: 00:00:12.5532552 2: 00:00:06.4866486

다른 동시 수집과 달리ConcurrentBag<T>단일 프로세서 사용에 최적화되어 있습니다.
와는과 다르게 .List<T>,ConcurrentBag<T>여러 스레드에서 동시에 사용할 수 있습니다.

"여러 스레드가 컨테이너에 액세스하고 각 스레드가 데이터를 생성 및/또는 소비할 수 있는" 경우, 이는 분명히 병렬 시나리오를 위한 것입니다.

언급URL : https://stackoverflow.com/questions/2950955/concurrentbagmytype-vs-listmytype

반응형