2011-08-19 4 views
1

그래서 나는 입력 데이터를 제공하는 많은 스레드를 가지고 있는데, 이는 도착 순서에 따라 하나의 스레드에 의해 처리되어야합니다. 현재 모든 입력 항목은 대기열에 삽입되고 대기열에 대한 읽기/쓰기는 C# lock 문으로 보호됩니다. 그러나 시간이 지남에 따라 응용 프로그램의 CPU 사용량이 허용 할 수없는 수준으로 올라가고 프로필러는 대부분의 CPU 시간이 잠금 문 자체에 소비되고 있다고 말합니다. 자물쇠 대신 많은 작가와 독자를 지원하는보다 효율적인 동기화 방법이 있습니까?많은 작성자를위한 가장 효율적인 잠금 단일 판독기 동시성 모델?

답변

3

작가들이 자물쇠로 서로 경쟁하고있는 것처럼 들립니다. 각 작성자가 고유 한 대기열을 갖고 있고 독자가 Peek method을 사용하여 각 대기열의 첫 번째 메시지를 제거하지 않고 읽는 모델을 생각해보십시오. 그런 다음 독자는 대기열 간 반복을 유지하고 각 대기열의 첫 번째 항목 세트 중 첫 번째 항목을 엿보고 첫 번째 항목을 제거 및 처리 할 수 ​​있습니다. 현재 아키텍처보다 느려지지만 작성자 간의 잠금 경합을 제거해야합니다.

같은 예제이다 보일 수 있습니다 그것은 당신의 응용 프로그램에 큰 변화 될 수

public class TimestampedItem<T> : IComparable<TimestampedItem<T>> 
{ 
    public DateTime TimeStamp { get; set; } 
    public T Data { get; set; } 
    public int CompareTo(TimestampedItem<T> other) 
    { 
     return TimeStamp.CompareTo(other.TimeStamp); 
    } 
} 

public void ReadFirstFromEachQueue<T>(IEnumerable<Queue<TimestampedItem<T>>> queues) 
{ 
    while (true) 
    { 
     var firstItems = new List<TimestampedItem<T>>(queues.Select(q => { lock (q) { return q.Peek(); } })); 
      ProcessItem(firstItems.OrderBy(tsi => tsi.TimeStamp).First()); 
     } 
    } 
} 
1

,하지만 당신은 (예를 MSMQ에 대한) 응용 프로그램에 외부 대기열을 고려할 수 있습니다 다음, 당신이 할 수 귀하 작가 스레드가 대기열에 자신의 마음에 내용을 쓰고 있습니다. 그러면 독자가 준비가 완료되면 항목을 꺼낼 수 있습니다. CPU 시간의 대부분이 대기열 주변의 잠금 장치에있는 경우 (실제로 대기열에있는 항목에 대한 작업을 잠그지 않은 것으로 가정), 대기열을 응용 프로그램에 넣으면 실제로 도움이 될 수 있습니다. 이상적으로는 쓰기와 읽기를 분리 된 프로세스로 분리 할 수도 있습니다.

또 다른 한가지는 잠그고있는 객체가 앱의 다른 부분을 잠그는 데 사용되지 않는다는 것입니다. 모니터 (lock 문 뒤에있는 것)는 아마도 가장 가벼운 가중치 스레드 동기화 방법 일 수 있으므로 아이템을 처리하는 동일한 프로세스에서 잠금을 피하기 위해 사물을 다시 설계하는 것이 가장 좋습니다.

1

당신이 다음 대신 정상 Queue의, ConcurrentCollections의 일부입니다 ConcurrentQueue을 사용하고 큐에 데이터를 읽기/쓰기 할 때 잠금 제거 할 수 4.0 당신이 .NET 버전을 사용하는 경우 ConcurrentCollections은 당신은 당신이 할 수있는 4.0를 사용하지 않는 경우 ..

을/동시 읽기를 처리 잠금 무료로 코드를 작성하는 데 사용할 수 있도록 설계하는 것은 다른 잠금이 굽없는 경우, 당신은 달성 할 수있는 유일한 고정하는 것입니다 메모를 Monitor.TryEnter를 사용하는 대신 lock로 그 lock 자체는 Monitor.EnterMonitor.Exit의 조합입니다, 샘플 구현은 다음과 같습니다 :

private readonly object _syncObject = new object(); 

private bool TryUpdate(object someData) 
{ 
    if (Monitor.TryEnter(_syncObject)) 
    { 
     try 
     { 
      //Update the data here. 

      return true; 
     } 
     finally 
     { 
      Monitor.Exit(_SyncObject); 
     } 
    } 

    return false; 
} 
+0

Monitor.Enter보다 Monitor.TryEnter의 장점은 무엇입니까? – GWLlosa

+0

첫 번째 "Monitor.TryEnter'는 입력을 기다리는 것을 차단하지 않으며,'lock'이 사용 중이면 그 행에서 사용 가능한 상태가 될 때까지 기다리지 않고 false를 반환합니다. –

관련 문제