[c#] 잠금 문은 얼마나 비쌉니까?

저는 다중 스레딩과 병렬 처리를 실험 해 왔으며 처리 속도에 대한 기본적인 계산 및 통계 분석을 수행하기 위해 카운터가 필요했습니다. 내 클래스의 동시 사용 문제를 피하기 위해 내 클래스의 개인 변수에 잠금 문을 사용했습니다.

private object mutex = new object();

public void Count(int amount)
{
 lock(mutex)
 {
  done += amount;
 }
}

하지만 궁금한 게 있는데 … 변수를 잠그는 데 얼마나 비쌉니까? 성능에 부정적인 영향은 무엇입니까?



답변

여기 비용에 관한 기사 가 있습니다. 짧은 대답은 50ns입니다.


답변

기술적 대답은 이것이 정량화가 불가능하다는 것입니다. 이는 CPU 메모리 후기 입 버퍼의 상태와 프리 페 처가 수집 한 데이터의 양을 버리고 다시 읽어야하는 정도에 따라 크게 달라집니다. 둘 다 매우 비 결정적입니다. 나는 큰 실망을 피하는 봉투 뒤의 근사치로 150 CPU 사이클을 사용합니다.

실용적인 대답은 잠금을 건너 뛸 수 있다고 생각할 때 코드를 디버깅하는 데 소모되는 시간보다 훨씬 저렴하다는 것입니다.

어려운 숫자를 얻으려면 측정해야합니다. Visual Studio에는 확장으로 사용할 수 있는 매끄러운 동시성 분석기가 있습니다.


답변

추가 읽기 :

일반적인 동기화 기본 요소에 관심이 있고 고유 한 시나리오와 스레드 수에 따라 모니터, C # 잠금 문 동작, 속성 및 비용을 파헤 치고있는 몇 가지 기사를 소개하고 싶습니다. 특히 여러 시나리오에서 처리 할 수있는 작업의 양을 이해하기 위해 CPU 낭비 및 처리량 기간에 관심이 있습니다.

https://www.codeproject.com/Articles/1236238/Unified-Concurrency-I-Introduction
https://www.codeproject.com/Articles/1237518/Unified-Concurrency-II-benchmarking-methodologies
https : // www. codeproject.com/Articles/1242156/Unified-Concurrency-III-cross-benchmarking

원래 답변 :

이런!

THE ANSWER는 본질적으로 잘못된 것으로 여기에 표시된 정답 인 것 같습니다! 답변 작성자에게 정중하게 링크 된 기사를 끝까지 읽어달라고 요청하고 싶습니다.

2003 년 기사 의 저자는 듀얼 코어 머신에서만 측정했으며 첫 번째 측정 사례에서는 단일 스레드로만 잠금측정 했으며 그 결과는 잠금 액세스 당 약 50ns였습니다.

동시 환경의 잠금에 대해서는 아무 것도 말하지 않습니다. 그래서 우리는 기사를 계속 읽어야합니다. 그리고 후반부에 저자는 2 개와 3 개의 스레드로 잠금 시나리오를 측정하고 있었는데, 이는 오늘날 프로세서의 동시성 수준에 가까워졌습니다.

그래서 저자는 듀얼 코어에 두 개의 스레드를 사용하면 잠금 비용이 120ns이고 스레드가 3 개인 경우 180ns가된다고 말합니다. 따라서 동시에 잠금에 액세스하는 스레드 수에 분명히 의존하는 것 같습니다.

따라서 간단합니다. 잠금이 쓸모 없게되는 단일 스레드가 아니면 50ns가 아닙니다.

고려해야 할 또 다른 문제는 평균 시간으로 측정된다는 것입니다 !

반복 시간을 측정하면 대부분이 빠르기 때문에 1ms에서 20ms 사이의 시간이있을 수 있지만 프로세서 시간을 기다리는 스레드는 거의 없으며 밀리 초의 긴 지연도 발생합니다.

이것은 높은 처리량과 낮은 대기 시간이 필요한 모든 종류의 응용 프로그램에 나쁜 소식입니다.

마지막으로 고려해야 할 문제는 잠금 내부에 작업 속도가 느려질 수 있다는 것입니다. 코드 블록이 잠금 내부에서 실행되는 시간이 길수록 경합이 높아지고 지연이 하늘 높이 올라갑니다.

2003 년부터 이미 10 년 이상이 지났습니다. 즉, 완전히 동시에 실행되도록 특별히 설계된 몇 세대의 프로세서이며 잠금으로 인해 성능이 상당히 저하됩니다.


답변

이것은 성능에 대한 쿼리에 응답하지 않습니다,하지만 난 .NET 프레임 워크가 제공한다는 것을 말할 수있는 Interlocked.Add당신이 당신을 추가 할 수 있습니다 방법 amount당신에 done수동으로 다른 개체에 고정하지 않고 회원.


답변

lock (Monitor.Enter / Exit)는 Waithandle 또는 Mutex와 같은 대안보다 매우 저렴하고 저렴합니다.

그러나 (약간) 느리다면 잘못된 결과를 가진 빠른 프로그램을 원하십니까?


답변

잠금 장치가없는 대안에 비해 타이트 루프의 잠금 비용은 엄청납니다. 여러 번 반복 할 수 있고 잠금보다 더 효율적입니다. 이것이 잠금 해제 대기열이 매우 효율적인 이유입니다.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LockPerformanceConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var stopwatch = new Stopwatch();
            const int LoopCount = (int) (100 * 1e6);
            int counter = 0;

            for (int repetition = 0; repetition < 5; repetition++)
            {
                stopwatch.Reset();
                stopwatch.Start();
                for (int i = 0; i < LoopCount; i++)
                    lock (stopwatch)
                        counter = i;
                stopwatch.Stop();
                Console.WriteLine("With lock: {0}", stopwatch.ElapsedMilliseconds);

                stopwatch.Reset();
                stopwatch.Start();
                for (int i = 0; i < LoopCount; i++)
                    counter = i;
                stopwatch.Stop();
                Console.WriteLine("Without lock: {0}", stopwatch.ElapsedMilliseconds);
            }

            Console.ReadKey();
        }
    }
}

산출:

With lock: 2013
Without lock: 211
With lock: 2002
Without lock: 210
With lock: 1989
Without lock: 210
With lock: 1987
Without lock: 207
With lock: 1988
Without lock: 208


답변

“비용”을 정의하는 몇 가지 방법이 있습니다. 잠금을 얻고 해제하는 실제 오버 헤드가 있습니다. Jake가 쓴 것처럼이 작업이 수백만 번 수행되지 않는 한 무시할 수 있습니다.

더 관련성이있는 것은 이것이 실행 흐름에 미치는 영향입니다. 이 코드는 한 번에 하나의 스레드에서만 입력 할 수 있습니다. 이 작업을 정기적으로 수행하는 5 개의 스레드가있는 경우 그중 4 개는 잠금이 해제 될 때까지 기다린 다음 해당 잠금이 해제 된 후 해당 코드를 입력하도록 예약 된 첫 번째 스레드가됩니다. 따라서 알고리즘이 크게 저하 될 것입니다. 얼마나 많이 알고리즘과 연산이 호출 되는가에 따라 달라집니다. 경쟁 조건을 도입하지 않고는 실제로 피할 수는 없지만 잠긴 코드에 대한 호출 수를 최소화하여 개선 할 수 있습니다.