2012-04-22 14 views
5

मैं क्यूटी में टीसीपी सर्वर लिख रहा हूं जो बड़ी फाइलों की सेवा करेगा।धीमी क्यूटीसीपी सर्वर एक साथ कई ग्राहकों के साथ

  1. मैं QTcpServer subclassed और reimplemented incomingConnection (int)
  2. incomingConnection में, मैं "किरण" वर्ग
  3. QTcpSocket
  4. "किरण" उपयोग कर रहा है, जिनमें से उदाहरण बना रहा हूं गए हैं: आवेदन तर्क इस प्रकार है incomingConnection से setSocketDescriptor साथ प्रारंभ
  5. जब ग्राहक से डेटा आती, मैं वापस readyRead() स्लॉट के भीतर से प्रारंभिक प्रतिक्रिया भेज रहा है, और फिर मैं किरण के स्लॉट bytesWritten() के लिए सॉकेट के संकेत bytesWritten (qint64) को जोड़ने कर रहा हूँ
Streamer.h: 
... 
private: 
    QFile *m_file; 
    char m_readBuffer[64 * 1024]; 
    QTcpSocket *m_socket; 
... 

Streamer.cpp 
... 
void Streamer::bytesWritten() { 
    if (m_socket->bytesToWrite() <= 0) { 
     const int bytesRead = m_file->read(m_readBuffer, 64 * 1024); 
     m_socket->write(m_readBuffer, bytesRead); 
    } 
} 
... 

तो बुनियादी तौर पर मैं केवल नए डेटा जब सभी लंबित डेटा पूरी तरह से लिखा है लिख रहा हूँ: ५३६९१३६३२१०

bytesWritten तरह दिखता है। मुझे लगता है कि ऐसा करने का सबसे असीमित तरीका है।

और सबकुछ सही काम करता है, सिवाय इसके कि यह बहुत धीमी है जब कई सारे ग्राहक हैं।

के बारे में 5 ग्राहकों के साथ - मैं गति के साथ कि सर्वर लगभग 1 MB/s (मेरे घर इंटरनेट कनेक्शन की अधिकतम)

से डाउनलोड कर रहा हूँ 140 के बारे में ग्राहकों के साथ - डाउनलोड गति के आसपास 100-200 KB/s ।

सर्वर का इंटरनेट कनेक्शन 10 जीबीपीएस है और 140 ग्राहकों के साथ इसका उपयोग लगभग 100 एमबीपीएस है, इसलिए मुझे नहीं लगता कि यह समस्या है।

140 ग्राहकों के साथ सर्वर स्मृति उपयोग - 2GB के 100 MB उपलब्ध

सर्वर के CPU उपयोग - अधिकतम 20%

मैं बंदरगाह 800

उपयोग कर रहा हूँ जब पोर्ट 800 पर 140 ग्राहक थे और इसके माध्यम से गति 100-200 केबी/एस की तरह थी, मैंने पोर्ट 801 पर अलग प्रतिलिपि चलाई है और बिना किसी समस्या के 1 एमबी/एस पर डाउनलोड कर रहा था।

मेरा अनुमान है कि किसी भी तरह, क्यूटी की घटना प्रेषण (या सॉकेट नोटिफ़ायर?) उन सभी घटनाओं को संभालने में बहुत धीमी है।

मैं कोशिश की है:

  1. -O3
  2. स्थापित कर रहा है libglib2 साथ पूरे क्यूटी और मेरे एप्लिकेशन संकलन।0-dev और retpiling Qt (क्योंकि QCoreAplication QEventDispatcherGlib या QEventDispatcherUNIX का उपयोग करता है, इसलिए मैं देखना चाहता था कि कोई अंतर है या नहीं)
  3. कुछ थ्रेड और इनकमिंग कनेक्शन (int) में स्ट्रीमर-> moveToThread() का उपयोग करके कितने क्लाइंट हैं वर्तमान में विशेष सूत्र में - कि किसी भी परिवर्तन नहीं किया है (हालांकि मैं 'पाया है कि गति भी बहुत कुछ परिवर्तनीय थे) का उपयोग कर
  4. Spawning कार्यकर्ता प्रक्रियाओं

कोड:

main.cpp: 
#include <sched.h> 

int startWorker(void *argv) { 
    int argc = 1; 
    QCoreApplication a(argc, (char **)argv); 

    Worker worker; 
    worker.Start(); 

    return a.exec(); 
} 

in main(): 
... 
long stack[16 * 1024]; 
clone(startWorker, (char *)stack + sizeof(stack) - 64, CLONE_FILES, (void *)argv); 

और फिर शुरू करने एक क्यूएलओसी मुख्य प्रक्रिया में अलसेवर और कार्यकर्ता प्रक्रियाओं में आने वाली कनेक्शन (int सॉकेटडिस्क्रिप्टर) से सॉकेट डिस्क्रिप्टर पास करना। यह सही ढंग से काम किया, लेकिन गति डाउनलोड अभी भी धीमी थी।

भी करने की कोशिश की:

  1. कांटा() - incomingConnection() में प्रक्रिया ing - कि लगभग सर्वर :)
  2. प्रत्येक ग्राहक के लिए अलग थ्रेड बनाना मार डाला - गति के लिए 50-100 KB/s गिरा
  3. QRunnable साथ QThreadPool का उपयोग करना - कोई फर्क नहीं

मैं क्यूटी 4.8.1

उपयोग कर रहा हूँ 10 मैं विचारों से बाहर भाग गया।

क्या यह क्यूटी से संबंधित है या शायद सर्वर कॉन्फ़िगरेशन के साथ कुछ है?

या शायद मुझे अलग-अलग भाषा/ढांचे/सर्वर का उपयोग करना चाहिए? मुझे टीसीपी सर्वर की आवश्यकता है जो फाइलों की सेवा करेगा, लेकिन मुझे पैकेट के बीच कुछ विशिष्ट कार्य करने की भी आवश्यकता है, इसलिए मुझे उस हिस्से को स्वयं लागू करने की आवश्यकता है।

+1

सर्वर डिस्क उपयोग के बारे में कैसे? क्या यह बाधा हो सकती है? –

+0

यह काफी संभव है। ऐसा लगता है कि सर्वर हार्डवेयर दोषपूर्ण हो सकता है। मैं सोमवार को निश्चित रहूंगा, और मैं आपको बता दूंगा। धन्यवाद! – AdrianEddy

+0

बाधा निश्चित रूप से डिस्क आईओ संचालन है। 80 से अधिक खुली फाइलें सर्वर लोड> 1 में परिणाम देती हैं और लगभग 150 केबी/एस की गति डाउनलोड करती हैं। क्या मेरे प्रोग्राम में कुछ भी बदल सकता है, या मुझे सर्वर कॉन्फ़िगरेशन/हार्डवेयर के साथ खेलना है? – AdrianEddy

उत्तर

3

आपकी डिस्क पढ़ती है संचालन अवरुद्ध कर रहे हैं, वे किसी भी प्रसंस्करण को रोक देंगे, जिसमें नए नेटवर्क कनेक्शन और ऐसे हैंडलिंग शामिल हैं। आपकी डिस्क में सीमित I/O थ्रूपुट भी है, और आप इसे संतृप्त कर सकते हैं। आप शायद नहीं चाहते कि आपकी डिस्क आपके शेष एप्लिकेशन को रोक दे। मुझे नहीं लगता कि यहां क्यूटी के साथ कुछ भी गलत है - जब तक आप एक प्रोफाइलर नहीं चलाते और दिखाते हैं कि क्यूटी की सीपीयू खपत अत्यधिक है, या किसी भी तरह क्यूटी घटना घटनाओं पर विवाद को बंद कर देता है (वे केवल वे हैं जो यहां मायने रखेंगे)।

  1. इनकमिंग कनेक्शन स्वीकार कर रहा है:

    आप इस प्रकार, QObjects भर में अपने प्रसंस्करण विभाजन होना चाहिए।

  2. सॉकेट से लेखन और पढ़ने को संभालना।

  3. आने वाले नेटवर्क डेटा को प्रोसेस करना और किसी भी गैर-फ़ाइल उत्तरों को जारी करना।

  4. डिस्क से पढ़ने और नेटवर्क पर लिखना।

बेशक # 1 और # 2 मौजूदा क्यूटी कक्षाएं हैं।

आपको # 3 और # 4 लिखना है। आप शायद # 1 और # 2 को उनके बीच साझा किए गए एक थ्रेड में स्थानांतरित कर सकते हैं। # 3 और # 4 को कई धागे के चारों ओर फैलाया जाना चाहिए। प्रत्येक सक्रिय कनेक्शन के लिए # 3 का एक उदाहरण बनाया जाना चाहिए।फिर, जब फ़ाइल डेटा भेजने के लिए समय आता है, # 3 तुरंत # 4 को चालू करता है। # 4 के लिए उपलब्ध धागे की संख्या समायोज्य होनी चाहिए, आपको शायद यह पता चल जाएगा कि किसी विशेष वर्कलोड के लिए इसके लिए इष्टतम सेटिंग है। आप राउंड-रॉबिन फैशन में अपने धागे में # 3 और # 4 को तुरंत चालू कर सकते हैं। चूंकि डिस्क का उपयोग अवरुद्ध हो रहा है, इसलिए # 4 के लिए उपयोग किए गए थ्रेड अनन्य होना चाहिए और किसी अन्य चीज़ के लिए उपयोग नहीं किया जाना चाहिए।

लिखने वाले बफर में शेष डेटा से कम होने पर # 4 ऑब्जेक्ट डिस्क को पढ़ना चाहिए। यह राशि शायद शून्य नहीं होनी चाहिए - यदि आप संभव हो तो उन नेटवर्क इंटरफेस को व्यस्त रखना चाहते हैं, और भेजने के लिए डेटा से बाहर निकलना उन्हें निष्क्रिय करने का एक निश्चित तरीका है।

तो मैं देख रहा हूँ कम से कम निम्नलिखित ट्यूनेबल पैरामीटर है कि आप के लिए बेंचमार्क की आवश्यकता होगी पर:

  1. minNetworkWatermark - सॉकेट संचारित बफर में न्यूनतम जल स्तर। जब आप लिखने के लिए कई बाइट्स से कम होते हैं तो आप डिस्क से पढ़ते हैं और सॉकेट पर लिखते हैं।

  2. minReadSize - न्यूनतम डिस्क पढ़ने का आकार। एक फ़ाइल पढ़ी जाएगी qMax (minNetworkWatermark - सॉकेट-> बाइट्स टूवाइट(), minReadSize)।

  3. numDiskThreads - # 4 ऑब्जेक्ट्स को थ्रेड की संख्या में स्थानांतरित किया गया है।

  4. numNetworkThreads - # 3 ऑब्जेक्ट्स को थ्रेड की संख्या में स्थानांतरित किया गया है।

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

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