저는 다중 스레딩과 병렬 처리를 실험 해 왔으며 처리 속도에 대한 기본적인 계산 및 통계 분석을 수행하기 위해 카운터가 필요했습니다. 내 클래스의 동시 사용 문제를 피하기 위해 내 클래스의 개인 변수에 잠금 문을 사용했습니다.
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 개는 잠금이 해제 될 때까지 기다린 다음 해당 잠금이 해제 된 후 해당 코드를 입력하도록 예약 된 첫 번째 스레드가됩니다. 따라서 알고리즘이 크게 저하 될 것입니다. 얼마나 많이 알고리즘과 연산이 호출 되는가에 따라 달라집니다. 경쟁 조건을 도입하지 않고는 실제로 피할 수는 없지만 잠긴 코드에 대한 호출 수를 최소화하여 개선 할 수 있습니다.