थ्रेड क्यों सो रहा है


128

मैं अक्सर यह उल्लेख करता हूं कि Thread.Sleep();इसका उपयोग नहीं किया जाना चाहिए, लेकिन मैं यह नहीं समझ सकता कि ऐसा क्यों है। यदि Thread.Sleep();परेशानी हो सकती है, तो क्या कोई वैकल्पिक समाधान उसी परिणाम के साथ है जो सुरक्षित होगा?

जैसे।

while(true)
{
    doSomework();
    i++;
    Thread.Sleep(5000);
}

एक और एक है:

while (true)
{
    string[] images = Directory.GetFiles(@"C:\Dir", "*.png");

    foreach (string image in images)
    {
        this.Invoke(() => this.Enabled = true);
        pictureBox1.Image = new Bitmap(image);
        Thread.Sleep(1000);
    }
}

3
ब्लॉग का एक सारांश 'थ्रेडस्लेप () का दुरुपयोग न करें' हो सकता है।
मार्टिन जेम्स

5
मैं यह नहीं कहूंगा कि यह हानिकारक है। मैं इसके बजाय यह कहूंगा कि यह goto:आपकी समस्याओं की तुलना में बेहतर समाधान है Sleep
डिफॉल्ट

9
यह बिल्कुल वैसा नहीं है, जैसा कि gotoडिजाइन की गंध की तुलना में कोड गंध की तरह होता है। कंपाइलर डालने में कुछ भी गलत नहीं हैgotoआपके कोड में : कंप्यूटर भ्रमित नहीं होता है। लेकिन Thread.Sleepबिल्कुल वैसा ही नहीं है; संकलक उस कॉल को सम्मिलित नहीं करते हैं और इसके अन्य नकारात्मक परिणाम हैं। लेकिन हाँ, सामान्य भावना है कि इसका उपयोग करना गलत है क्योंकि लगभग हमेशा एक बेहतर समाधान निश्चित रूप से सही है।
कोड़ी ग्रे

32
हर कोई इस बारे में राय प्रदान कर रहा है कि उपरोक्त उदाहरण क्यों खराब हैं, लेकिन किसी ने फिर से लिखित संस्करण प्रदान नहीं किया है जो थ्रेड का उपयोग नहीं करता है। सोलेप () जो अभी भी दिए गए उदाहरणों के लक्ष्य को पूरा करता है।
स्टिंगजैक

3
हर बार जब आप sleep()कोड (या परीक्षण) में एक पिल्ला मर जाते हैं
रेजा एस

जवाबों:


163

कॉलिंग के साथ समस्याएं Thread.Sleepहैं काफी संक्षेप यहाँ समझाया :

Thread.Sleepइसका उपयोग होता है: एमटीए धागे पर परीक्षण / डिबगिंग करते समय लंबे संचालन का अनुकरण करना। .NET में इसका उपयोग करने का कोई अन्य कारण नहीं है।

Thread.Sleep(n) इसका मतलब है कि वर्तमान थ्रेड को कम से कम कई बार (या थ्रेड क्वांटम) की संख्या के लिए ब्लॉक कर सकते हैं n मिलीसेकंड के । एक संस्करण की लंबाई अलग-अलग संस्करणों / प्रकार के विंडोज और विभिन्न प्रोसेसर पर भिन्न होती है और आम तौर पर 15 से 30 मिलीसेकंड तक होती है। इसका मतलब है कि धागे को nमिलीसेकंड से अधिक के लिए ब्लॉक करने की गारंटी है । मिलिसेकंड के बाद आपका धागा फिर से जागृत होने की संभावना nलगभग असंभव है जितना असंभव हो सकता है। तो, Thread.Sleepसमय के लिए व्यर्थ है

धागे एक सीमित संसाधन हैं, वे बनाने के लिए लगभग 200,000 चक्र लेते हैं और नष्ट करने के लिए लगभग 100,000 चक्र होते हैं। डिफ़ॉल्ट रूप से वे अपने स्टैक के लिए 1 मेगाबाइट वर्चुअल मेमोरी को आरक्षित करते हैं और प्रत्येक संदर्भ स्विच के लिए 2,000-8,000 चक्रों का उपयोग करते हैं। यह किसी भी प्रतीक्षा धागे को एक बड़ा बेकार बना देता है।

पसंदीदा समाधान: WaitHandles

सबसे अधिक बनाई गई गलती Thread.Sleepएक समय-निर्माण ( डेमो और उत्तर) के साथ उपयोग कर रही है , अच्छा ब्लॉग-प्रवेश ) के साथ उपयोग कर रहा है

संपादित करें:
मैं अपना उत्तर बढ़ाना चाहूंगा:

हमारे पास 2 अलग-अलग उपयोग-मामले हैं:

  1. हम इंतजार कर रहे हैं क्योंकि हम एक विशिष्ट समय को जानते हैं जब हमें जारी रखना चाहिए (उपयोग Thread.Sleep,System.Threading.Timer या बाइक)

  2. हम प्रतीक्षा कर रहे हैं क्योंकि कुछ स्थिति कुछ समय बदलती है ... कीवर्ड / हैं / हैं कुछ समय ! अगर हालत-चेक हमारे कोड-डोमेन में है, तो हमें WaitHandles का उपयोग करना चाहिए - अन्यथा बाहरी घटक को कुछ प्रकार के हुक प्रदान करने चाहिए ... यदि यह इसकी डिज़ाइन खराब नहीं है!

मेरा जवाब मुख्य रूप से उपयोग-केस 2 को कवर करता है


30
मैं 1 एमबी मेमोरी को आज के हार्डवेयर पर विचार करने वाला एक बहुत बड़ा कचरा नहीं कहूंगा
डिफ़ॉल्ट

14
@Default हे, चर्चा करें कि मूल लेखक के साथ :) और, यह हमेशा आपके कोड पर निर्भर करता है - या बेहतर: कारक ... और मुख्य मुद्दा "थ्रेड्स एक सीमित संसाधन हैं" - आज के बच्चों को ज्यादा नहीं पता है दक्षता और कुछ कार्यान्वयनों की लागत के बारे में, क्योंकि "हार्डवेयर सस्ता है" ... लेकिन कभी-कभी आपको बहुत ओप्पेट कोड करने की आवश्यकता होती है
एंड्रियास

11
'इससे ​​किसी वेटिंग थ्रेड को भारी बर्बादी होती है?' यदि कुछ प्रोटोकॉल युक्ति जारी रखने से पहले एक सेकंड के ठहराव की मांग करती है, तो 1 सेकंड के लिए क्या इंतजार करना होगा? कुछ धागा, कहीं, इंतजार करना पड़ रहा है! थ्रेड बनाने / नष्ट करने के लिए ओवरहेड अक्सर अप्रासंगिक होता है क्योंकि एक धागा को अन्य कारणों से भी उठाना पड़ता है और यह प्रक्रिया के जीवनकाल के लिए चलता है। जब पंप चालू करने के बाद कोई युक्ति कहता है तो संदर्भ-स्विच से बचने के किसी भी तरीके को देखने के लिए मुझे दिलचस्पी होगी, फ़ीड वाल्व खोलने से पहले स्थिर करने के लिए कम से कम दस सेकंड प्रतीक्षा करें '।
मार्टिन जेम्स

9
@ कोडीग्रे - मैंने पोस्ट को फिर से पढ़ा। मैं अपनी टिप्पणियों में किसी भी रंग की मछली नहीं देखता हूं। एंड्रियास ने वेब से बाहर निकाला: 'थ्रेड.सलीप में इसका उपयोग किया गया है: एमटीए थ्रेड पर परीक्षण / डीबगिंग करते समय लंबे संचालन का अनुकरण करना। .NET में इसका उपयोग करने का कोई अन्य कारण नहीं है '। मेरा तर्क है कि कई ऐप हैं जहां नींद () कॉल अच्छी तरह से आवश्यक है। यदि डेवलपर्स के लीगन्स, (वहाँ के लिए कई हैं), नींद का उपयोग करने पर जोर देते हैं () स्थिति मॉनिटर के रूप में छोरों (घटनाओं / condvars / semas / जो भी हो, के साथ प्रतिस्थापित किया जाना चाहिए), यह दावा करने का कोई औचित्य नहीं है कि 'इसका उपयोग करने का कोई अन्य कारण नहीं है '।
मार्टिन जेम्स

8
30 साल के मल्टीट्रेड एप डेवलपमेंट में, (ज्यादातर C ++ / डेल्फी / विंडोज), मैंने कभी भी किसी डिलिबल कोड में स्लीप (0) या स्लीप (1) लूप की कोई जरूरत नहीं देखी। कभी-कभी, मैं डिबगिंग उद्देश्यों के लिए इस तरह के कोड में छाया हुआ हूं, लेकिन यह कभी भी ग्राहक के लिए अपना रास्ता नहीं बनाता है। 'यदि आप कुछ ऐसा लिख ​​रहे हैं जो पूरी तरह से हर धागे को नियंत्रित नहीं करता है' - थ्रेड्स का माइक्रो-प्रबंधन उतना ही बड़ा है जितना कि विकास कर्मचारियों का सूक्ष्म प्रबंधन। थ्रेड प्रबंधन वह है जो ओएस के लिए है - जो उपकरण प्रदान करता है उसका उपयोग किया जाना चाहिए।
मार्टिन जेम्स

34

SCENARIO 1 - async कार्य पूरा होने की प्रतीक्षा करें: मैं सहमत हूं कि WaitHandle / Auto | ManualResetEvent का उपयोग उस परिदृश्य में किया जाना चाहिए जहां एक थ्रेड पूरा होने के लिए दूसरे थ्रेड पर कार्य की प्रतीक्षा कर रहा है।

SCENARIO 2 - लूप करते समय: हालांकि, क्रूड टाइमिंग तंत्र के रूप में (जबकि + थ्रेड। सो) उन अनुप्रयोगों के 99% के लिए पूरी तरह से ठीक है, जिन्हें वास्तव में जानने की आवश्यकता नहीं है जिन्हें अवरुद्ध थ्रेड "जागने" के लिए । धागा बनाने के लिए 200k चक्र भी अमान्य है - टाइम लूप थ्रेड की जरूरत वैसे भी बनाई जा सकती है और 200k चक्र सिर्फ एक और बड़ी संख्या है (मुझे बताएं कि एक फ़ाइल / सॉकेट / डीबी कॉल को खोलने के लिए कितने चक्र हैं?)।

तो अगर + थ्रेड। सो काम करता है, चीजों को जटिल क्यों? केवल वाक्यविन्यास वकील, व्यावहारिक होंगे !


शुक्र है कि अब हमारे पास कुशलता से परिणाम की प्रतीक्षा करने के लिए टास्क कॉमप्लेक्शन स्रोत है।
ऑस्टिन सालगट

14

मैं इस सवाल का जवाब कोडिंग-पॉलिटिक्स के नजरिए से देना चाहता हूं, जो किसी के लिए मददगार हो भी सकता है और नहीं भी। लेकिन विशेष रूप से जब आप ऐसे टूल के साथ काम कर रहे होते हैं जो 9-5 कॉर्पोरेट प्रोग्रामर के लिए अभिप्रेत होते हैं, तो जो लोग दस्तावेज़ लिखते हैं, वे "नहीं करना चाहिए" और "कभी नहीं" जैसे शब्दों का उपयोग करते हैं, ऐसा तब तक न करें जब तक कि आप वास्तव में नहीं जानते कि आप क्या करते हैं। 'कर रहे हैं और क्यों "।

C # दुनिया में मेरे अन्य पसंदीदा के एक जोड़े हैं कि वे आपको "कभी भी लॉक (यह) नहीं कहते हैं" या "GC.Collect ()" कभी नहीं कहते हैं। इन दोनों को कई ब्लॉगों और आधिकारिक दस्तावेज़ों में जबरदस्ती घोषित किया गया है, और IMO पूरी तरह गलत हैं। कुछ स्तर पर यह गलत सूचना अपने उद्देश्य को पूरा करती है, जिसमें यह शुरुआती लोगों को उन चीजों को करने से दूर रखती है, जिन्हें वे विकल्पों पर पूरी तरह से शोध करने से पहले नहीं समझते हैं, लेकिन साथ ही, खोज इंजनों के माध्यम से वास्तविक जानकारी प्राप्त करना मुश्किल हो जाता है। प्रश्न का उत्तर न देते हुए "कुछ क्यों नहीं?"

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

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


5

यह 1) .स्पिनिंग और 2) है। आपके उदाहरणों का लूप लूप करना, जिसके खिलाफ लोग सावधानी बरतते हैं , जिसके , न कि थ्रेड। स्लीप () भाग। मुझे लगता है कि थ्रेड। स्लीप () आमतौर पर आसानी से कोड को सुधारने के लिए जोड़ा जाता है जो कताई या एक मतदान लूप में होता है, इसलिए यह सिर्फ "खराब" कोड के साथ जुड़ा हुआ है।

इसके अलावा लोग सामान की तरह करते हैं:

while(inWait)Thread.Sleep(5000); 

जहां चर inWait को थ्रेड-सुरक्षित तरीके से एक्सेस नहीं किया जाता है, जो समस्याओं का कारण बनता है।

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

जैसा कि एंड्रियास एन ने उल्लेख किया है, थ्रेडिंग इन सी #, जो अलबहारी द्वारा पढ़ा गया है , यह वास्तव में बहुत अच्छा है।


तो आपके कोड उदाहरण में क्या करने का विकल्प है?
shinzou

kuhaku - हाँ, अच्छा सवाल है। स्पष्ट रूप से थ्रेड। सो () एक शॉर्टकट है, और कभी-कभी एक बड़ा शॉर्टकट है। ऊपर के उदाहरण के लिए, मतदान लूप के नीचे फ़ंक्शन में बाकी कोड "जबकि (inWait) थ्रेड। सोलेप (5000);" एक नया फ़ंक्शन है। वह नया फ़ंक्शन एक प्रतिनिधि (कॉलबैक फ़ंक्शन) है और आप इसे "इनवाइट" ध्वज को सेट करने के लिए पास करते हैं, और "इनवाइट" ध्वज को बदलने के बजाय, कॉलबैक लागू किया जाता है। यह सबसे छोटा उदाहरण था जो मुझे मिल सकता था: myelin.co.nz/notes/callbacks/cs-delegates.html
mike

बस यह सुनिश्चित करने के लिए कि मुझे यह मिल गया है, आपका मतलब Thread.Sleep()एक अन्य फ़ंक्शन के साथ लपेटना है , और उस लूप में कॉल करना है?
शिंज़ौ

5

नींद का उपयोग उन मामलों में किया जाता है जहां स्वतंत्र कार्यक्रम (जिन पर आपका कोई नियंत्रण नहीं है) कभी-कभी आमतौर पर उपयोग किए जाने वाले संसाधन (जैसे, एक फ़ाइल) का उपयोग कर सकते हैं, कि आपके कार्यक्रम को जब यह चलता है, और जब संसाधन इनका उपयोग में हो, अन्य प्रोग्राम आपके प्रोग्राम का उपयोग करने से अवरुद्ध है। इस स्थिति में, जहाँ आप अपने कोड में संसाधन का उपयोग करते हैं, आप संसाधन की अपनी पहुँच को एक कोशिश-कैच में डालते हैं (अपवाद को पकड़ने के लिए जब आप संसाधन तक नहीं पहुँच सकते हैं), और आपने इसे थोड़ी देर के लूप में डाल दिया। यदि संसाधन मुक्त है, तो नींद को कभी नहीं बुलाया जाता है। लेकिन अगर संसाधन अवरुद्ध है, तो आप उचित समय के लिए सोते हैं, और संसाधन को फिर से एक्सेस करने का प्रयास करते हैं (यही कारण है कि आप लूप कर रहे हैं)। हालांकि, इस बात को ध्यान में रखें कि आपको लूप पर किसी प्रकार का सीमक लगाना होगा, इसलिए यह एक संभावित लूप नहीं है।


3

मेरे पास एक उपयोग का मामला है जिसे मैं यहां कवर नहीं करता हूं, और यह तर्क दूंगा कि यह थ्रेड का उपयोग करने का एक वैध कारण है। सोलेप ():

हजारों लोगों द्वारा साझा किए गए डीबी को सांत्वना देने वाले एप्लिकेशन में, मुझे बहुत महंगी डेटाबेस कॉल की एक बड़ी राशि बनाने की आवश्यकता है। डीबी को हथौड़ा नहीं करने और घंटों तक दूसरों को बाहर करने के लिए, मुझे 100 एमएस के क्रम में कॉल के बीच एक ठहराव की आवश्यकता होगी। यह समय से संबंधित नहीं है, बस अन्य थ्रेड्स के लिए DB तक पहुंच उपज है।

संदर्भ के लिए स्विचिंग के बीच 2000-8000 चक्रों को खर्च करना, जो निष्पादित करने के लिए 500 एमएस ले सकता है सौम्य है, क्योंकि धागे के लिए 1 एमबी स्टैक होता है, जो एक सर्वर पर एकल उदाहरण के रूप में चलता है।


हां, Thread.Sleepएक एकल-थ्रेड, एकल-उद्देश्य कंसोल एप्लिकेशन का उपयोग करना, जिसका वर्णन आप करते हैं, पूरी तरह से ठीक है।
थियोडोर जूलियास

-7

मैं यहां कई लोगों से सहमत हूं, लेकिन मुझे लगता है कि यह निर्भर करता है।

हाल ही में मैंने यह कोड किया है:

private void animate(FlowLayoutPanel element, int start, int end)
{
    bool asc = end > start;
    element.Show();
    while (start != end) {
        start += asc ? 1 : -1;
        element.Height = start;
        Thread.Sleep(1);
    }
    if (!asc)
    {
        element.Hide();
    }
    element.Focus();
}

यह एक सरल चेतन-कार्य था, और मैंने इस Thread.Sleepपर प्रयोग किया ।

मेरा निष्कर्ष, अगर यह काम करता है, तो इसका उपयोग करें।


-8

उन लोगों के लिए जिन्होंने SCENARIO 2 में Thread.Sleep के उपयोग के खिलाफ एक वैध तर्क नहीं देखा है, वास्तव में एक है - आवेदन निकास जबकि लूप द्वारा आयोजित किया जाता है (SCENARIO 1/3 सिर्फ सादा बेवकूफ है इसलिए अधिक योग्य नहीं है उल्लेख)

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

    static void Main(string[] args)
    {
        Thread t = new Thread(new ThreadStart(ThreadFunc));
        t.Start();

        Console.WriteLine("Hit any key to exit.");
        Console.ReadLine();

        Console.WriteLine("App exiting");
        return;
    }

    static void ThreadFunc()
    {
        int i=0;
        try
        {
            while (true)
            {
                Console.WriteLine(Thread.CurrentThread.ThreadState.ToString() + " " + i);

                Thread.Sleep(1000 * 10);
                i++;
            }
        }
        finally
        {
            Console.WriteLine("Exiting while loop");
        }
        return;
    }

9
-, Thread.Sleepनहीं, इसका कारण यह नहीं है (लूप होते हुए नित्य एक नया धागा है)! आप सिर्फ Thread.Sleepइनलाइन हटा सकते हैं - एट वॉयला: इस कार्यक्रम के रूप में अच्छी तरह से बाहर नहीं होगा ...
एंड्रियास Niedermair
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.