2012-03-16 19 views
10

के साथ सॉकेट.ReceiveAsync को प्रतिस्थापित करना मेरे पास एक ऐसा एप्लिकेशन है जो एक ही समय में कुछ सौ टीसीपी कनेक्शन बनाता है, और उनसे डेटा की लगातार स्ट्रीम प्राप्त करता है।नेटवर्कस्ट्रीम.ReadAsync (प्रतीक्षा करने योग्य)

private void startReceive() 
    { 
     SocketAsyncEventArgs e = new SocketAsyncEventArgs(); 
     e.Completed += receiveCompleted; 
     e.SetBuffer(new byte[1024], 0, 1024); 
     if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); } 
    } 

    void receiveCompleted(object sender, SocketAsyncEventArgs e) 
    { 
     ProcessData(e); 

     if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); } 
    } 

मेरे प्रयास कुछ इस तरह करने के लिए नेतृत्व:

private async void StartReceive() 
    { 
     byte[] Buff = new byte[1024]; 
     int recv = 0; 
     while (Socket.Connected) 
     { 
      recv = await NetworkStream.ReadAsync(Buff, 0, 1024); 
      ProcessData(Buff,recv); 
     } 
    } 

मुद्दा मैं विधि StartReceive() बुला ब्लॉक कर देगा था, और साथ StartSend() method called after StartReceive() . Creating a new task for StartReceive() would just end up with 300-ish threads, and it seems to do so just by calling StartReceive को नहीं मिल() 'वैसे भी।

क्या है, जबकि एक NetworkStream का उपयोग कर तो यह थ्रेड पूल कि Socket.SendAsync() और Socket.ReceiveAsync() धागे/कार्य के सैकड़ों करने के लिए होने से बचाने के प्रयोग कर रहे हैं उपयोग कर रहा है अपने मौजूदा कोड पर नए async और await कीवर्ड को लागू करने का सही तरीका होगा?

के साथ I/O पूरा होने वाले बंदरगाहों पर networkstream का उपयोग करने का कोई प्रदर्शन लाभ है?

+0

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

+0

वैसे मुख्य मुद्दा यह है कि नेटवर्कस्ट्रीम का इंतजार कर रहे संस्करण। रीडएसिंक एप्लिकेशन को प्रति कनेक्शन एक थ्रेड बनाने का कारण बनता है। Socket.ReceiveAsync का उपयोग करने के रूप में सभी 300 कनेक्शन के लिए 30 धागे के तहत होवर लगता है। – Josh

उत्तर

25

आप एक बार यहां पर दो बातें बदल रहे हैं: अतुल्यकालिक शैली (SocketAsyncEventArgsTask/async करने के लिए) और अमूर्त के स्तर (NetworkStream-Socket)।

चूंकि आप पहले से ही Socket के साथ सहज हैं, इसलिए मैं केवल एसिंक्रोनस शैली को बदलने की सलाह देता हूं, और सीधे Socket कक्षा का उपयोग करना जारी रखता हूं।

Async सीटीपी Socket कोई async नहीं देता है - संगत तरीकों (जो अजीब है; मुझे लगता है कि उन्हें गलती से छोड़ दिया गया था और .NET 4.5 में जोड़ा जाएगा)।

यह नहीं करता है, तो आप का उपयोग कठिन अपने स्वयं के ReceiveAsyncTask विस्तार विधि (और अन्य कार्यों के लिए इसी तरह के रैपर) बनाने के लिए है कि मेरे AsyncEx library:

public static Task<int> ReceiveAsyncTask(this Socket socket, 
    byte[] buffer, int offset, int size) 
{ 
    return AsyncFactory<int>.FromApm(socket.BeginReceive, socket.EndReceive, 
     buffer, offset, size, SocketFlags.None); 
} 

एक बार जब आप करते हैं कि, अपने StartReceive जैसे लिखा जा सकता है:

private async Task StartReceive() 
{ 
    try 
    { 
    var buffer = new byte[1024]; 
    while (true) 
    { 
     var bytesReceived = await socket.ReceiveAsyncTask(buffer, 0, 1024) 
      .ConfigureAwait(false); 
     ProcessData(buffer, bytesReceived); 
    } 
    } 
    catch (Exception ex) 
    { 
    // Handle errors here 
    } 
} 

अब, पता करने के लिए कई छोटे अंक:

  • await एक नया धागा नहीं फैलता है। मैंने an async/await intro on my blog लिखा, जैसा कि कई अन्य हैं। async/await समेकन की अनुमति देता है, लेकिन यह आवश्यक नहीं है कि मल्टीथ्रेडिंग का अर्थ हो।
  • सैकड़ों धागे समस्याग्रस्त हो सकते हैं। सैकड़ों कार्य, हालांकि, कोई समस्या नहीं है; थ्रेड पूल और बीसीएल कई, कई कार्यों को संभालने के लिए डिज़ाइन किए गए हैं।
  • async/await एसिंक्रोनस प्रोसेसिंग का एक नया रूप नहीं है; यह सिर्फ आसान तरीका से एक्सप्रेस असीमित प्रक्रिया है। यह अभी भी नीचे आईओसीपी का उपयोग करता है।async/await निम्न स्तर के तरीकों की तुलना में थोड़ा कम प्रदर्शन है; इसकी अपील लेखन और एसिंक्रोनस विधियों को लिखने में आसानी है।
  • एक बहुत ही व्यस्त प्रणाली async/await पर स्विच होने पर कुछ बढ़ी हुई जीसी दबाव देख सकती है। समांतर टीम wrote up some example socket-specific awaitables पर स्टीफन टब जो उस मुद्दे के साथ मदद कर सकते हैं। (मैं पहले सीधा पैटर्न का उपयोग करने की सलाह देता हूं, और यदि आपको यह आवश्यक लगता है तो केवल प्रदर्शन-बढ़ाए गए दृष्टिकोण का उपयोग करना; फिर भी, यह जानना अच्छा होता है कि यदि आप इसे समाप्त करने की आवश्यकता है तो यह पता है)।
  • Async विधियों को Task वापस नहीं करना चाहिए जबतक कि आप वास्तव में उन्हें void वापस करने की आवश्यकता नहीं है। Task प्रतीक्षा योग्य है, इसलिए आपकी विधि संगत है (और अधिक आसानी से टेस्ट करने योग्य); void "आग और भूलें" की तरह अधिक है।
  • आप थ्रेड पूल थ्रेड पर निष्पादित करने के लिए शेष async विधि को बताने के लिए ConfigureAwait(false) पर कॉल कर सकते हैं। मैं उपरोक्त मेरे उदाहरण में इसका उपयोग करता हूं ताकि ProcessData को थ्रेड पूल थ्रेड में निष्पादित किया जा सके, जैसे SocketAsyncEventArgs का उपयोग करते समय।
  • Socket.Connected बेकार है। You need to send data to detect if the connection is still valid.
+0

इस उपयोगी जानकारी के लिए धन्यवाद। और मुझे पता है, मैं बस सॉकेट का उपयोग कर रहा था। त्वरित लिखने के लिए कनेक्ट किया गया। – Josh

+0

क्या इसे .NET 4.5 में कार्यान्वित किया गया है? – Isaac

+1

@Isaac: नहीं। मुझे लगता है कि बीसीएल टीम ने फैसला किया है कि यह 'सॉकेट' प्रकार के लिए बहुत अधिक एपीआई का नेतृत्व करेगा। –

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