2009-01-20 18 views
15

के लिए .NET2.0 सीरियल पोर्ट .BaseStream उपयोग करने के लिए मैं अतुल्यकालिक करने के लिए .NET2.0 serialport की .BaseStream संपत्ति उपयोग करने का प्रयास कर रहा हूँ रीड और राईट (BeginWrite/EndWrite, BeginRead/EndRead)।कैसे सही ढंग से async आपरेशन

मुझे इसमें कुछ सफलता मिल रही है, लेकिन एक समय के बाद, मुझे लगता है कि (प्रोसेस एक्सप्लोरर का उपयोग करके) हैंडल में हैंडल में बहुत धीरे-धीरे वृद्धि होती है, और कभी-कभी एक अतिरिक्त धागा, जो हैंडल गिनती भी बढ़ाता है।

प्रत्येक बार जब कोई नया धागा दिखाई देता है तो संदर्भ स्विच दर भी बढ़ जाती है।

एप्लिकेशन लगातार (प्रोसेस एक्सप्लोरर से फिर से,) एक पीएलसी डिवाइस के लिए 3 बाइट्स भेजता है, और बदले में 800 या तो बाइट्स हो जाता है, और 57600.

प्रारंभिक CSwitch डेल्टा के एक बॉड दर पर ऐसा नहीं करता है है लगभग 2500, जो वैसे भी बहुत अधिक लगता है। हर बार जब कोई नया धागा दिखाई देता है, तो यह मान बढ़ता है, और सीपीयू लोड तदनुसार बढ़ता है।

मुझे उम्मीद है कि किसी ने ऐसा कुछ किया होगा, और मेरी मदद कर सकता है, या यहां तक ​​कि 'भगवान के नाम में, ऐसा मत करो।'

नीचे दिए गए कोड में, 'this._stream' SerialPort.BaseStream से प्राप्त किया गया है, और CommsResponse एक वर्ग है जिसे मैं IAsyncresult स्टेट ऑब्जेक्ट के रूप में उपयोग करता हूं।

यह कोड एक टीसीपी कनेक्शन के लिए आम है जो मैं धारावाहिक बंदरगाह का उपयोग करने के विकल्प के रूप में करता हूं, (मेरे पास एक कॉमर्स और टीसीपी चैनल से प्राप्त कॉमम्स चैनल बेस क्लास है) और इसमें इनमें से कोई भी समस्या नहीं है। मैं उम्मीद करता हूं कि कॉमरेस्पेन्स क्लास के साथ कुछ भी गलत नहीं है।

कोई भी टिप्पणी कृतज्ञतापूर्वक प्राप्त हुई।

/// <summary> 
    /// Write byte data to the channel. 
    /// </summary> 
    /// <param name="bytes">The byte array to write.</param> 
    private void Write(byte[] bytes) 
    { 
     try 
     { 
      // Write the data to the port asynchronously. 
      this._stream.BeginWrite(bytes, 0, bytes.Length, new AsyncCallback(this.WriteCallback), null); 
     } 
     catch (IOException ex) 
     { 
      // Do stuff. 
     } 
     catch (ObjectDisposedException ex) 
     { 
      // Do stuff. 
     } 
    } 

    /// <summary> 
    /// Asynchronous write callback operation. 
    /// </summary> 
    private void WriteCallback(IAsyncResult ar) 
    { 
     bool writeSuccess = false; 

     try 
     { 
      this._stream.EndWrite(ar); 
      writeSuccess = true; 
     } 
     catch (IOException ex) 
     { 
      // Do stuff. 
     } 

     // If the write operation completed sucessfully, start the read process. 
     if (writeSuccess) { this.Read(); } 
    } 

    /// <summary> 
    /// Read byte data from the channel. 
    /// </summary> 
    private void Read() 
    { 
     try 
     { 
      // Create new comms response state object. 
      CommsResponse response = new CommsResponse(); 

      // Begin the asynchronous read process to get response. 
      this._stream.BeginRead(this._readBuffer, 0, this._readBuffer.Length, new AsyncCallback(this.ReadCallback), response); 
     } 
     catch (IOException ex) 
     { 
      // Do stuff. 
     } 
     catch (ObjectDisposedException ex) 
     { 
      // Do stuff. 
     } 
    } 

    /// <summary> 
    /// Asynchronous read callback operation. 
    /// </summary> 
    private void ReadCallback(IAsyncResult ar) 
    { 
     // Retrieve the comms response object. 
     CommsResponse response = (CommsResponse)ar.AsyncState; 

     try 
     { 
      // Call EndRead to complete call made by BeginRead. 
      // At this point, new data will be in this._readbuffer. 
      int numBytesRead = this._stream.EndRead(ar); 

      if (numBytesRead > 0) 
      { 
       // Create byte array to hold newly received bytes. 
       byte[] rcvdBytes = new byte[numBytesRead]; 

       // Copy received bytes from read buffer to temp byte array 
       Buffer.BlockCopy(this._readBuffer, 0, rcvdBytes, 0, numBytesRead); 

       // Append received bytes to the response data byte list. 
       response.AppendBytes(rcvdBytes); 

       // Check received bytes for a correct response. 
       CheckResult result = response.CheckBytes(); 

       switch (result) 
       { 
        case CheckResult.Incomplete: // Correct response not yet received. 
         if (!this._cancelComm) 
         { 
          this._stream.BeginRead(this._readBuffer, 0, this._readBuffer.Length, 
           new AsyncCallback(this.ReadCallback), response); 
         } 
         break; 

        case CheckResult.Correct: // Raise event if complete response received. 
         this.OnCommResponseEvent(response); 
         break; 

        case CheckResult.Invalid: // Incorrect response 
         // Do stuff. 
         break; 

        default: // Unknown response 
         // Do stuff. 
         break; 
       } 
      } 
      else 
      { 
       // Do stuff. 
      } 
     } 
     catch (IOException ex) 
     { 
      // Do stuff. 
     } 
     catch (ObjectDisposedException ex) 
     { 
      // Do stuff. 
     } 
    } 

उत्तर

5

कुछ सुझाव:

जब से तुम केवल 3 बाइट्स भेज रहे हैं, तो आप एक तुल्यकालिक लिखें ऑपरेशन हो सकता था। देरी एक मुद्दा नहीं होगा।

भी हर समय एक नया AsyncCallback नहीं बनाते हैं। एक बनाएं और एक AsyncCallback लिखें और प्रत्येक प्रारंभ कॉल में इसका उपयोग करें।

+1

आपके उत्तर के लिए धन्यवाद। कॉलबैक के निर्माण के बारे में अच्छा सुझाव। मैंने कोशिश की है, लेकिन हैंडल/थ्रेड/संदर्भ स्विच दर अभी भी बढ़ती है, हालांकि यह धीमी दर से बढ़ने लगती है, इसलिए एक सुधार। – Andy

4

BeginWrite के लिए बिल्कुल कोई आवश्यकता नहीं है। आप केवल 3 बाइट भेजते हैं, वे आसानी से ट्रांसमिट बफर में फिट होंगे, और आप हमेशा सुनिश्चित हैं कि जब आप अगला सेट भेजते हैं तो बफर खाली होता है।

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

BeginRead() के बजाय डेटा पुनर्प्राप्त करने का प्रयास करना निश्चित रूप से कुछ है जो आपको करना चाहिए। पुश के बजाए खींचें, जब आप हमेशा सक्रिय होते हैं तो आप थ्रेडपूल थ्रेड का उपयोग करेंगे।

+0

मैं BeginWrite के संबंध में बिंदु लेता हूं, यह वास्तव में आवश्यक नहीं है। BeginRead प्रत्येक बाइट के लिए ट्रिगर नहीं करता है, लेकिन यह अक्सर बार-बार ट्रिगर करता है। हो सकता है कि मैं डेटा को प्राप्त कर सकूं और कक्षा को लगातार बनाए रखने के लिए बाइट्स को अपनी स्ट्रीम में पास कर सकूं? मैं भी 'रिलीज' संस्करण का परीक्षण कर रहा हूं, बीटीडब्ल्यू। – Andy

+0

@ हंस: एंडी ने कहा, 'BeginRead' /' EndRead' आसानी से एकाधिक बाइट प्रति कॉल (टाइमआउट सेटिंग के आधार पर) को संभालता है। और एसआईओ.पी.रियलपोर्ट डेटा डेटा और डेटा का पता लगाने के लिए हर समय थ्रेडपूल थ्रेड को अवरुद्ध करता है, इसलिए आप निम्न संसाधन उपयोग की कल्पना कर रहे हैं। हकीकत में, पहचान-गतिविधि-फिर-पढ़ने के समाधान के मुकाबले 'BeginRead' /' EndRead' के लिए कम कर्नेल कॉल की आवश्यकता होती है। –

0

क्या सीरियल पोर्ट से डेटा आने और सीधे इसे फ़ाइल में भेजना संभव है? एक बॉड दरों (1 मेगाबाउड) में इस गैर-स्टॉप डेटा को संभालना मुश्किल है।

0

डिवाइस से प्रतिक्रिया हमेशा एक निश्चित आकार है? यदि ऐसा है, तो SerialPort.Read का उपयोग करने का प्रयास करें और पैकेट आकार पास करें। यह अवरुद्ध होगा, इसलिए DataReceived के साथ इसे गठबंधन करें।अभी तक बेहतर, यदि प्रतिक्रिया हमेशा एक ही चरित्र (रों) के साथ समाप्त होता है, और इस को समाप्त हुए हस्ताक्षर पैकेट में अद्वितीय होने की गारंटी है, NewLine गुण सेट और ReadLine का उपयोग करें। यह आपको भविष्य के पैकेट आकार के परिवर्तनों के खिलाफ टीकाकरण करेगा।

+0

दुर्भावनापूर्ण रूप से पैकेट आकार परिवर्तनीय हैं। – Andy

+0

बमर। तो आपको कैसे पता चलेगा कि आपको पूर्ण पैकेट कब प्राप्त हुआ है? – mtrw

+0

पैकेट में हेडर और टर्मिनेटर बाइट्स हैं, जिसमें पैकेट की लंबाई और इसके भीतर एन्कोड किए गए चेकसम शामिल हैं। – Andy

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