2012-01-16 18 views
7

में अनंत लूप में 100% तक बढ़ रहा है मैं एएसपी.नेट वेब अनुप्रयोग में एक वेब आधारित चैट प्लेटफॉर्म को कार्यान्वित कर रहा हूं, और मैं लंबे मतदान के समान तकनीक का उपयोग करता हूं। मेरा मतलब है कि मैं प्रत्येक वेब अनुरोध को क्लाइंट से विशिष्ट समय अवधि (टाइमआउट) या नए संदेश तक पहुंचने तक रखता हूं, और फिर ग्राहक को प्रतिक्रिया भेजी जाती है।सीपीयू उपयोग थ्रेड

मैं कनेक्ट क्लाइंट को स्मृति (शब्दकोश ऑब्जेक्ट) में रखता हूं और जब कभी क्लाइंट को नया संदेश भेजा जाता है, तो मैं यह संदेश रिसीवर क्लाइंट के संदेश सरणी में लिखता हूं। क्लाइंट को अपने संदेश प्राप्त करने का अनुरोध भेजने की आवश्यकता है, और मैं इस अनुरोध को स्मृति में सरणी में रखता हूं।

मैं श्रवण क्लाइंट अनुरोध के लिए एसिंक्रोनस http हैंडलर का उपयोग कर रहा हूं, मैं स्मृति में सरणी में वेब अनुरोध रख रहा हूं। मैं थ्रेड का उपयोग स्मृति से लगातार नए संदेशों की जांच करने के लिए करता हूं (शब्दकोश में जो प्रत्येक क्लाइंट के लिए बनाया गया है)।

मैं नए संदेशों के लिए जाँच करने के लिए थ्रेड पूल .net धागे का उपयोग करें या टाइम आउट हो गया वेब requests.I इस तरह धागे नहीं:

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

प्रत्येक थ्रेड के QueueCometWaitRequest_WaitCallback विधि में मैं एक अनंत में हूँ, जबकि पाश:

while (true) 
{ 
... 
Thread.Sleep(100); 
} 

इस विधि में, मैं वेब अनुरोध समय बाहर या एक वेब अनुरोध जो भी स्मृति में एक सरणी में रखा जाता है के लिए नए संदेश के लिए जाँच कर रहा हूँ।

सब कुछ अच्छा काम कर रहा था जब तक कि मैंने देखा कि CPU उपयोग समय पर 100% तक पहुंच रहा है। (पहले जुड़े क्लाइंट के कुछ मिनटों में) पहले अनुरोध की शुरुआत में सबकुछ सामान्य लगता है, मेरा मतलब है कि क्लाइंट को प्रतिक्रिया लौटने पर CPU उपयोग 10% से अधिक नहीं है। लेकिन समय में भी 2 ग्राहकों के साथ सीपीयू उपयोग 100% तक बढ़ रहा है। ऐसा लगता है कि ग्राहक अनुरोध के लिए प्रतिक्रिया लिखते समय केवल CPU उपयोग 100% है। यदि कोई क्लाइंट नहीं छोड़ा जाता है तो सब कुछ एक सामान्य (सीपीयू उपयोग लगभग 0%) तक लौटाता है जब तक कि ग्राहक द्वारा नया वेब अनुरोध नहीं किया जाता है।

मुझे धागे को विस्तार से नहीं पता है, लेकिन मैं नए धागे के बारे में संदिग्ध हूं जो मैंने बनाया और असीम रूप से काम करता है। ऐसा लगता है कि ऑपरेटिंग सिस्टम उन्हें समय पर अधिक CPU उपयोग और संसाधन देता है क्योंकि वे हर समय काम कर रहे हैं, और यह थ्रेड। सो (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

तो मूल रूप से आपको प्रत्येक एन-मिलीसेकंड के नए संदेशों की जांच करने की आवश्यकता है? क्या यह सब कुछ है या कुछ और async किया जाना चाहिए? यदि ऐसा है तो बस async 'System.Threading.Timer' /' System.Timers.Timer' का उपयोग करें जो प्रत्येक एन-मिलीसेकंड को ट्रिगर करता है। – sll

+0

क्या यह लगभग आप जो हासिल करने की कोशिश कर रहे हैं? जबकि (सत्य) {थ्रेड। नींद (100); foreach (processRequest में var req) {performProcessRequest (req);} processRequest.Remove (r => r.RequestCompletedOrTimedOut);} –

+0

@sll: मुझे क्लाइंट (नया संदेश) ASAP
पर प्रतिक्रिया वापस करने की आवश्यकता है क्योंकि यह एक चैट है आवेदन, जांच अवधि बहुत लंबी नहीं होनी चाहिए, मुझे लगता है कि अगर मैं टाइमर का उपयोग करता हूं तो इसे 1 सेकंड से छोटा होना चाहिए? – Mehmet

उत्तर

9

प्रत्यक्ष उत्तर के विपरीत सामान्य सामान्य प्रथाओं की टिप्पणी के रूप में - यह थ्रेड लिखने की सलाह नहीं है। नींद (100) आपके अंदर संदेश रिसीवर धागा। 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 उपयोग करता है और केवल सीपीयू की खपत जब ऐसा करने के लिए काम है वहाँ।

विफल रहा है कि आपने एसिंक्रोनस द्वि-दिशात्मक संदेश के लिए किसी तृतीय पक्ष समाधान के बारे में सोचा है? मैंने बड़ी सफलता के साथ RabbitMQ (एएमक्यूपी) का उपयोग किया है।उच्च थ्रूपुट मैसेजिंग को संभालने के लिए नेट अनुप्रयोग। RabbitMQ के लिए एपीआई का मतलब है कि जब कोई संदेश प्राप्त हुआ है तो आपको एक ईवेंट वापस मिल जाएगा जिसे पृष्ठभूमि थ्रेड पर संसाधित किया जा सकता है।

सादर,

+1

आपके उत्तर के लिए धन्यवाद। लेकिन फिर एक और सवाल आता है: मुझे क्लाइंट को प्रतिक्रिया वापस करने की ज़रूरत है, यहां तक ​​कि किसी दिए गए समय अवधि के लिए कोई नया संदेश नहीं है। इस मामले में मैं कैसे इंतजार कर सकता हूँ हैंडल.Set() ;? मेरा मतलब है कि धागे शुरू करने के लिए मैं कैसे जान सकता हूं? – Mehmet

+0

कोई जांच नहीं। बस सोच रहा था - आपको अपने कोड उदाहरण से 100% सीपीयू नहीं मिलना चाहिए। आप कितने धागे बना रहे हैं? (सिर्फ एक उभाड़)। निश्चित रूप से होना चाहिए! यह प्रति अनुरोध एक नहीं है? –

+0

प्रति अनुरोध नहीं, कुल 5 धागे। अनुरोध एक सरणी में हैं – Mehmet

0

मैं (शब्दकोश वस्तु) स्मृति में जुड़ा ग्राहकों रखने

शब्दकोश वस्तुओं सुरक्षित थ्रेड नहीं कर रहे हैं, तो स्थिर इस्तेमाल किया। यदि इसे एक स्थिर सदस्य के रूप में उपयोग करना है तो आपको लॉक स्टेटमेंट बनाना होगा।

यहां लॉग 4नेट लॉगर फैक्ट्री क्लास से लिया गया एक उदाहरण है ... ध्यान दें कि TypeToLoggerMap एक शब्दकोश वस्तु है और जब इसे संदर्भित किया जाता है तो GetLogger विधि, लॉक स्टेटमेंट का उपयोग किया जाता है।

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 का उपयोग कर विचार किया है?

संबंधित मुद्दे