2010-02-06 11 views
12

मैं एक सी # Winforms आवेदन के विकास कर रहा हूँ, आवेदन के हिस्से के एक वेबसर्वर AsyncUpload उपयोग करने के लिए फ़ाइलों को अपलोड किया जाएगा (इसे का उपयोग, एक porgress कॉलबैक उपयोग करने की आवश्यकता के कारण), में सी # कार्यक्रमसी #: एक समारोह कॉल को अवरुद्ध करने तक की स्थिति उत्पन्न होने

मैं पाश अपलोड कर रहा है समारोह

for(int i=0;i < 10 ; i++) 
{ 
    Uploadfun(); 
} 

कॉल के लिए एक सरल हो गया और मज़ा कुछ जादू करता है:

Uploadfun() 
    { 
    // Logic comes here 

    // webClient.UploadFileAsync runs a 2nd thread to perform upload .. 
    webClient.UploadFileAsync(uri, "PUT", fileNameOnHD); 

} 

और एक कॉलबैक डब्ल्यू कहा जाता हो जाता है कि मुर्गी Async अपलोड

Upload_Completed_callback() 
{ 
    //Callback event 
} 

किया जाता है संपादित

तर्क अनुक्रम:

  1. मज़ा बुलाया जाता है (पाश से)
  2. मज़ा तर्क निष्पादित और किया जाता है ..
  3. पाश
  4. कॉलबैक eventuall बुलाया जाएगा के लिए वापस चला जाता है y, जब UploadFileAsync (जो एक और धागा में कुछ तर्क चल रहा है) खत्म हो जाएगा

समस्या 3 बिंदु, जब निष्पादन पाश के लिए वापस करने के लिए ले जाता है, मैं जब तक जारी रखने से पाश ब्लॉक करने की आवश्यकता पर है कॉलबैक बुलाया जाता है।

+3

क्या आपके पास 'मजेदार' कार्यान्वयन तक पहुंच है? आपको शायद एक सिंक्रोनस इंटरफेस प्रदान करने पर विचार करना चाहिए जिस पर एसिंक एपीआई लागू किया गया है। –

+0

जिस तरीके से आप इसका वर्णन कर रहे हैं, आपका कोड अनुक्रमिक और एकल थ्रेडेड लगता है, जिसका अर्थ है कि 'कॉलबैक' फ़ंक्शन को लूप कहा जाता है जब तक कि लूप जारी नहीं रहेगा। अगर मैं अधिक विस्तृत स्पष्टीकरण देकर गलत हूं तो कृपया मुझे सही करें। –

+0

@ मादी: फिर आप इसे पीछे की ओर कर रहे हैं। आपको तर्क के मूल में 'अपलोडफाइल' के सिंक्रोनस संस्करण का उपयोग करना चाहिए और यदि आपको इसकी आवश्यकता हो तो इसके शीर्ष पर एसिंक एपीआई का उपयोग करें। –

उत्तर

20

तो अगर मैं सही ढंग से समझ, आप कॉल करना UploadFileAsync तब तक async कॉल अपने कॉलबैक को प्रभावित किया है ब्लॉक करना चाहते हैं। यदि हां, तो मैं प्रयोग करेंगे AutoResetEvent यानी

private readonly AutoResetEvent _signal = new AutoResetEvent(false); 

fun() 
    { 
    // Logic comes here 

    // runs a 2nd thread to perform upload .. calling "callback()" when done 
    webClient.UploadFileAsync(uri, "PUT", fileNameOnHD); 

    _signal.WaitOne(); // wait for the async call to complete and hit the callback  
} 



callback() 
{ 
    //Callback event 
    _signal.Set(); // signal that the async upload completed 
} 

का उपयोग AutoResetEvent का मतलब हो जाता है कि राज्य के बाद स्वचालित रूप Set बुलाया गया है और प्रतीक्षा धागा WaitOne

+0

अपलोडएसिंक के बाद Waitone() का उपयोग करते समय, प्रोग्राम रोक रहा है, और कॉलबैक नहीं कहा जा रहा है। –

+0

ठीक है .. मैंने एक अलग थ्रेड में मज़ेदार समस्या को हल किया है, "स्पष्ट रूप से" इसे मुख्य धागे में बुलाकर समस्या उत्पन्न हो रही है!, @ जुलिएट किंडा ने समस्या को इंगित करने में मदद की .. धन्यवाद आप दोनों =) –

4

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

आप कॉलबैक अंदर से fun कॉल कर सकते हैं। इन पंक्तियों (छद्म कोड) के साथ कुछ:

int n; 

callFunTenTimes() 
{ 
    n = 0; 
    fun(n); 
} 

callback() 
{ 
    ++n; 
    if (n < 10) 
     fun(n); 
    else 
     print("done"); 
} 

यह continuation passing style के समान है।

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

+0

मज़ाकिया है। मैं इन पंक्तियों के साथ अपनी समस्या के बारे में सोच रहा था: कॉलबैक फ़ंक्शन होने से लूप का क्या उपयोग होता है 'मांस' होता है। यह समाधान प्रतीक्षा समय को न्यूनतम रखने के लिए प्रतीत होता है। – Joe

+0

मुझे एसिंक संस्करण की आवश्यकता है क्योंकि यह एक "प्रगति" कॉलबैक प्रदान करता है जो मूल आवश्यकता है। –

+0

@ माडी डी: यदि आवश्यकता यह है कि अपलोड को असीमित रूप से व्यवहार करना चाहिए, तो कॉलबैक के साथ अपने फ़ंक्शन को एसिंक फ़ंक्शन क्यों न करें? क्या आप इस बारे में अधिक जानकारी दे सकते हैं कि आप इसका क्या उपयोग कर रहे हैं? क्या यह एक WinForms ऐप, एएसपी.NET, आदि है? –

1
समस्या

के माध्यम से संकेत प्राप्त रीसेट यहाँ है:

for(int i=0;i < 10 ; i++) 
{ 
    fun(); <-- if we block until this function finishes here, we stop the UI thread 
} 

तुम क्या कर रहे हैं अनुक्रमिक है।और तुम, यूआई धागा ब्लॉक यूआई धागा बंद लूप स्थानांतरित करने के लिए खर्च नहीं उठा सकते हैं:

volatile downloadComplete; 

void DownloadUpdates() 
{ 
    ThreadPool.QueueUserWorkItem(state => 
     for(int i = 0; i < 10; i++) 
     { 
      downloadComplete = false; 
      webClient.UploadFileAsync(uri, "PUT", fileNameOnHD); 
      while(!downloadComplete) { Thread.Sleep(1); } 
     }); 
} 

Upload_Completed_callback() 
{ 
    downloadComplete = true; 
} 

अब आप अपने यूआई धागा रोकने के बिना पाश के निष्पादन ब्लॉक कर सकते हैं, और आप भी का लाभ मिलेगा वेब क्लाइंट कक्षा से प्रगति संकेतक।

+0

इसके लिए एक बूलियन चर का उपयोग न करें, संकलक इसे अनुकूलित कर सकता है (जो ओपी का उल्लेख जारी रखने का व्यवहार नहीं करेगा)। ज़ेब्राबॉक्स ने एक प्रतीक्षा योग्य घटना वस्तु के साथ इसे करने का सही तरीका दिखाया। –

+1

@ बेन: मैं आपकी टिप्पणियों की सराहना करता हूं, लेकिन मुझे लगता है कि वे भ्रामक हैं। सबसे पहले, संकलक बूल को ऑप्टिमाइज़ करने के लिए नहीं जा रहा है जब तक कि इसका उपयोग या असाइन किया गया हो (और संभवतः यह है)। दूसरा, एक बूल और रीसेट एवेन्ट्स पर स्पिन-वेटिंग थ्रेड को ब्लॉक करने के वैध तरीके हैं, दोनों "इसे करने का सही तरीका" हैं, न तो "गलत" हैं, एक या दूसरा प्रोग्रामर के स्वाद पर निर्भर करता है। – Juliet

+0

वास्तव में उपयोगी उत्तर के लिए बहुत बहुत धन्यवाद, @ zebrabox के resetEvent समाधान के साथ आपके समाधान से थ्रेडिंग को जोड़कर, और अब यह काम कर रहा है .. =) –

3

ज़ेब्राबॉक्स को वेटहैंडल का उपयोग करने का अधिकार है। जबकि जूलियट का समाधान काम करता है, स्पिन-प्रतीक्षा करने वाला धागा वेटहैंडल के अनुपात में प्रोसेसर की एक बड़ी मात्रा का उपभोग करेगा, जो अनिवार्य रूप से निष्क्रिय बैठेगा।

+0

+1 दोनों शीर्ष उत्तरों (मेरे लिए) पर प्रकाश डालना .. –

+0

यह बहुत प्रोसेसर का उपभोग नहीं करेगा, लेकिन यह सिस्टम को सीपीयू को गहरी निष्क्रिय स्थिति में रखने से रोक सकता है और इसलिए बैटरी को तेजी से नीचे खींच सकता है लैपटॉप। –