2012-01-16 5 views
7

ASP.NET 웹 응용 프로그램에서 웹 기반 채팅 플랫폼을 구현하고 있으며 긴 폴링과 유사한 기술을 사용합니다. 내 말은 클라이언트의 각 웹 요청을 특정 시간 (시간 초과) 동안 또는 새 메시지가 도착할 때까지 유지 한 다음 클라이언트에 응답을 보내는 것을 의미합니다.스레드의 무한 루프에서 CPU 사용이 최대 100 %까지 증가합니다.

나는 연결된 클라이언트를 메모리에두고 (사전 객체) 새로운 메시지가 클라이언트로 전송 될 때이 메시지를 수신자 클라이언트의 메시지 배열에 씁니다. 클라이언트가 자신의 메시지를 가져 오기 위해 요청을 보내야하며이 요청을 메모리의 배열에 보관합니다.

청취 클라이언트 요청을 위해 비동기 http 처리기를 사용하고 있습니다. 웹 요청을 메모리에 보관하고 있습니다. 스레드를 사용하여 새 메시지를 메모리에서 계속 확인합니다 (각 클라이언트에 대해 생성 된 사전에 있음).

나는 새로운 메시지를 확인하는 .NET 스레드 풀 스레드를 사용하지 않거나 웹 requests.I는 다음과 같이 스레드를 만들 시간 초과 :

System.Threading.Thread t = new Thread(new ThreadStart(QueueCometWaitRequest_WaitCallback)); 
t.IsBackground = false; 
t.Start(); 

각 스레드의 QueueCometWaitRequest_WaitCallback 방법에서 나는 무한의 루프 동안입니다 :

이 방법에서는 웹 요청 시간 초과 또는 메모리의 배열에 보관 된 각 웹 요청에 대한 새 메시지를 확인합니다.

CPU 사용량이 최대 100 %에 도달 할 때까지 모든 것이 잘 작동하고있었습니다. (처음 연결된 클라이언트가 연결된 후 몇 분 안에) 첫 번째 요청이 시작될 때 모든 것이 정상적인 것처럼 보입니다. 클라이언트에 대한 응답을 반환하는 동안 CPU 사용량이 10 %를 넘지는 않습니다. 하지만 시간이 지남에 따라 2 개의 클라이언트에서도 CPU 사용량이 최대 100 %까지 증가합니다. 그것은 클라이언트 요청에 대한 응답에 쓰는 경우에만 CPU 사용량이 100 % 인 것 같습니다. 클라이언트가 없으면 클라이언트가 새 웹 요청을 완료 할 때까지 모든 것이 정상 (CPU 사용률은 약 0 %)으로 돌아갑니다.

스레드를 자세히 알지는 못하지만, 내가 만든 새 스레드에 대해서는 의심 스럽습니다. 운영 체제가 항상 작동하기 때문에 CPU 사용량과 리소스가 더 많아지고 Thread.Sleep (100)가 작동하지 않는 것과 같습니다. 여기

는 QueueCometWaitRequest_WaitCallback() 방법이다 : 나는 상황을 설명 할 수있는 희망

void QueueCometWaitRequest_WaitCallback() 
{ 
    while (true) 
    { 
     if (processRequest.Length == 0) 
     { 
      Thread.Sleep(100); 
     } 
     else 
     { 
      for (int i = 0; i < processRequest.Length; i++) 
      { 
       Thread.Sleep(100); 

       // below I am checking for new message or request time out 
       ................. 
       ................. 

       // If new message or time out I write to response 
      } 
     }  
    } 
} 

, 나는

(다른 방법으로 구현 등)뿐만 아니라 어떤 제안에 열려입니다 당신이 만약 이 문제를 도와 드리겠습니다. 감사합니다. 감사합니다.

+1

기본적으로 N 밀리 초마다 새 메시지를 확인해야합니까? 그것은 전부 또는 다른 것이 비동기로 수행되어야합니까? 그렇다면 비동기'System.Threading.Timer' /'System.Timers.Timer'를 사용하십시오. 각 N-milliseconds를 트리거합니다. – sll

+0

대략 달성하고자하는 목표입니까? while (true) {Thread.Sleep (100); –

+0

@sll : 클라이언트 (새 메시지)에 응답을 반환해야합니다.
이것은 채팅이기 때문에 (예 : processRequest에서 var req) {performProcessRequest (req) 응용 프로그램, 검사 기간이 너무 길어서는 안됩니다, 나는 타이머를 사용하는 경우 1 초보다 작을 필요가 있다고 생각합니까? – Mehmet

답변

9

직접 답장과 달리 일반 모범 사례 의견과 마찬가지로 - Thread.Sleep (100)을 직접 작성하는 것은 좋지 않습니다. 메시지 수신자 스레드. 더 나은 방법은 앞서 언급 한 또는 ManualResetEvent 대기 핸들처럼 Thread.Join을 사용하는 것입니다.

private ManualResetEvent waitHandle; 
private object syncRoot = new object(); 
private bool isRunning = false; 

void CreateThread() 
{ 
    this.waitHandle = new ManualResetEvent(false); 

    isRunning = true; // Set to false to kill the thread 
    System.Threading.Thread t = new Thread(new ThreadStart(QueueCometWaitRequest_WaitCallback));   
    t.IsBackground = false; 
    t.Start(); 
} 

void PushData() 
{ 
    // On incoming data, push data into the processRequest queue and set the waithandle 
    lock(syncRoot) 
    { 
     processRequest.Add(/* ... your data object to process. Assumes this is a queue */); 
     waitHandle.Set(); // Signal to the thread there is data to process 
    } 
} 

void QueueCometWaitRequest_WaitCallback() 
{  
    while (isRunning)  
    {  
     // Waits here using 0% CPU until the waitHandle.Set is called above 
     this.waitHandle.WaitOne(); 

     // Ensures no-one sets waithandle while data is being processed and 
     // subsequently reset 
     lock(syncRoot) 
     { 
      for (int i = 0; i < processRequest.Length; i++)   
      {       
       // Process the message. 
       // What's the type of processRequest? Im assuming a queue or something  
      }  

      // Reset the Waithandle for the next requestto process 
      this.waitHandle.Reset(); 
     } 
    }   
} 

이 기다리는 동안 스레드가 0 %의 CPU를 사용하도록 것이고, 할 일이있을 때에 만이 CPU를 소모 : 예를 들어, 다음과 같은 코드 수 있습니다.

비동기 양방향 메시징에 대한 타사 솔루션에 대해 생각해 보지 않으셨습니까? 나는 큰 성공과 함께 RabbitMQ (AMQP)을 사용했습니다.NET 응용 프로그램을 사용하여 높은 처리량 메시징을 처리 할 수 ​​있습니다. RabbitMQ 용 API는 백그라운드 스레드에서 처리 할 수있는 메시지를 받았을 때 이벤트를 다시 얻는다는 것을 의미합니다.

안부,

+1

답장을 보내 주셔서 감사합니다. 그러나 다른 질문이옵니다. 주어진 시간 동안 새로운 메시지가 없더라도 클라이언트에게 응답을 보내야합니다. 이 경우 어떻게 waitHandle.Set();을 할 수 있습니까? 스레드를 시작하는 방법을 알 수 있습니까? – Mehmet

+0

probs 없음. 생각 해봤는데 - 코드 예제에서 100 % CPU를 얻지 않아야합니다. 얼마나 많은 스레드를 만들고 있습니까? (그냥 직감). 물론 하나 여야합니다! 요청 당 하나도 아닙니다. –

+0

요청 당 하나가 아니며 총 5 개 스레드입니다. 요청은 배열에 있습니다 – Mehmet

0

나는 정적으로 사용 된 경우

사전 객체가 스레드 안전하지 않습니다 (사전 개체) 메모리에 연결된 클라이언트를 유지한다. 정적 멤버로 사용하는 경우 Lock 문을 만들어야합니다.

다음은 Log4Net LoggerFactory 클래스에서 해제 된 예제입니다. TypeToLoggerMap은 사전 객체이며 GetLogger 메소드를 참조하면 Lock 문이 사용됩니다.

public static class LoggerFactory 
{ 
    public static ILogger GetLogger(Ninject.Activation.IContext context) 
    { 
     return GetLogger(context.Request.Target == null ? typeof(ILogger) : context.Request.Target.Member.DeclaringType); 
    } 

    private static readonly Dictionary<Type, ILogger> TypeToLoggerMap = new Dictionary<Type, ILogger>(); 

    private static ILogger GetLogger(Type type) 
    { 
     lock (TypeToLoggerMap) 
     { 
      if (TypeToLoggerMap.ContainsKey(type)) 
       return TypeToLoggerMap[type]; 

      ILogger logger = new Logger(type); 
      TypeToLoggerMap.Add(type, logger); 

      return logger; 
     } 
    } 
} 

이 문서를 확인해보십시오. 여기에서 사전 개체에 대한 위의 정보를 발견했습니다. 보조 노트로

https://www.toptal.com/dot-net/hunting-high-cpu-usage-in-dot-net

, 당신은 당신의 프로젝트에 대한 SignalR을 사용하여 고려가?

관련 문제