2009-09-05 19 views
16

मुझे आश्चर्य है कि थ्रेड कॉल करने के बीच वास्तविक अंतर क्या है। नींद (1) और स्विचटो थ्रेड को कॉल करना (अगर हम अनदेखा करते हैं कि यह वर्तमान में बीसीएल द्वारा खुलासा नहीं किया गया है)।SwitchToThread बनाम नींद (1)

जो डफी का उल्लेख में his post कि:

"!। Kernel32 SwitchToThread एपीआई समस्याओं कि नींद (0) और नींद (1) कर प्रदर्शन नहीं करता" (शेड्यूलर के व्यवहार के संबंध में)

क्यों स्लीप स्विचटो थ्रेड की तरह व्यवहार नहीं करेगा? यह भिन्नता क्यों मौजूद है, और इसके लिए क्या अच्छा है? (यदि बिलकुल ..)

उत्तर

21

दो मतभेद हैं। SwitchToThread के लिए एमएसडीएन दस्तावेज़ों में पहला उल्लेख किया गया है:

निष्पादन की उपज कॉलिंग थ्रेड के प्रोसेसर तक ही सीमित है। ऑपरेटिंग सिस्टम निष्पादन को किसी अन्य प्रोसेसर पर स्विच नहीं करेगा, भले ही वह प्रोसेसर निष्क्रिय हो या कम प्राथमिकता का धागा चला रहा हो।

नींद (0) अन्य प्रोसेसर पर थ्रेड को भी चलाने की अनुमति देगा।

SwitchToThread केवल एक थ्रेड शेड्यूलिंग संदर्भ में ही उत्पन्न होता है। दूसरी तरफ सोते हैं, इसमें कई स्थितियां हैं जिनके लिए यह इंतजार कर रहा है। SleepEx के लिये दस्तावेज में विस्तार से इस उल्लेख:

* An I/O completion callback function is called 
* An asynchronous procedure call (APC) is queued to the thread. 
* The time-out interval elapses 

यह एक से अधिक थ्रेड के लिए निकलेगा।

सामान्य रूप से, नींद (0) एक टाइम्सलाइस पैदा करने की अधिक संभावना होगी, और हमेशा ओएस तक पहुंच जाएगी, भले ही कोई अन्य थ्रेड इंतजार न हो। यही कारण है कि एक लूप में नींद (0) जोड़ना प्रोसेसर उपयोग को कई मामलों में 100% (प्रति कोर) से 0% तक ले जाएगा। SwitchToThread नहीं होगा, जब तक कि कोई अन्य थ्रेड एक समय स्लाइस के लिए इंतजार कर रहा हो।

+2

आपके विश्लेषण को देखते हुए, 'if (! SwitchToThread()) नींद (0) नहीं कर रहा है, तो सबसे अच्छा समाधान हो सकता है? – wilx

0

SwitchToThread() नींद का एक "स्मार्ट" संस्करण है (0)। यह अच्छी तरह से प्रलेखित नहीं है, लेकिन मेरी समझ में, यह निम्नलिखित तरीके से काम करता है:

  1. जब वहाँ ready राज्य में अन्य धागे हैं (यानी एक से अधिक तार्किक प्रोसेसर उपलब्ध हैं चलाने के लिए इच्छुक धागे हैं) और इन थ्रेड हैं जो समान या उच्च प्राथमिकता है जो स्विचटो थ्रेड() को कॉल करने वाले थ्रेड की तुलना में व्यवहार करता है जैसे स्लीप (0) - यानी संदर्भों की महंगी लागत पर इन धागे में से किसी एक को लॉजिकल प्रोसेसर को सीड करता है स्विच;
  2. जब वहाँ कम प्राथमिकता साथ ready राज्य में सूत्र, यह सिर्फ बाहर निकल जाता है, धागा कि SwitchToThread() का आह्वान किया है यानी एक संदर्भ स्विच के किसी भी खर्च या एक 3 अंगूठी करने के लिए 0 संक्रमण (यह नहीं छोड़ता बिना निष्पादन जारी है उपयोगकर्ता मोड) - यह है कि कैसे नींद (0) व्यवहार करता है जो हमेशा से सबसे कम प्राथमिकता धागे पर नियंत्रण करता है;
  3. जब ready स्थिति में कोई थ्रेड नहीं है, तो SwitchToThread() भी स्लीप (0) जैसे बाहर निकलता है - इसलिए यदि आप इसे लूप में करते हैं, तो आपको वर्तमान लॉजिकल प्रोसेसर का 100% भार मिल रहा है, यानी शक्ति जल रहा है।

नींद (1) नींद (0) के समान है लेकिन 1 मिलीसेकंद देरी के साथ ही है। यह 1 मिलीसेकंद देरी तार्किक प्रोसेसर को मुक्त करती है और किसी भी शक्ति को जला नहीं देती है। इसके विपरीत, स्विच टॉथ्रेड, कभी भी किसी भी देरी का अनुभव नहीं करता है।

तो स्लीप (1) के साथ स्विचटो थ्रेड की तुलना करना बेहतर है, नींद (1) के साथ नहीं, क्योंकि नींद (1) स्लीप (0) + 1 मिलीसेकंड की देरी के समान है।

मैंने इस मुद्दे पर "इंटेल 64 और आईए -32 आर्किटेक्चर ऑप्टिमाइज़ेशन रेफरेंस मैनुअल" और "इंटेल 64 और आईए -32 आर्किटेक्चर सॉफ्टवेयर डेवलपर मैनुअल" से कुछ विचार उधार लिया है, जो कुछ pause सीपीयू निर्देशों को भी कॉल करने का पक्ष लेते हैं (यह भी Intrinsics के रूप में उपलब्ध) SwitchToThread() या नींद (0) पर यदि आपका इंतजार बहुत छोटा है। कृपया ध्यान दें कि SwitchToThread() या नींद (0) लगभग तत्काल हैं, जबकि नींद (1) कम से कम एक मिलीसेकंद तक रहता है।

निम्नलिखित को भी ध्यान में रखा जाना चाहिए:

  • प्रत्येक कॉल नींद के लिए() या SwitchToThread() एक संदर्भ स्विच है, जो 10000+ चक्र हो सकता है की महंगी लागत अनुभव करता है।
  • यह 0 रिंग 0 संक्रमणों के लिए रिंग 3 की लागत भी पीड़ित है, जो 1000+ चक्र हो सकता है।
  • स्विचटो थ्रेड() या नींद (0) का कोई उपयोग नहीं हो सकता है यदि ready राज्य में कोई धागा नहीं है, लेकिन नींद (1) कम से कम एक मिलीसेकंड की प्रतीक्षा करता है चाहे इस पर 'तैयार' राज्य में अन्य धागे हैं या नहीं नहीं।

यदि आपका प्रतीक्षा लूप बहुत छोटा हो जाता है, तो कृपया कुछ pause CPU निर्देशों को पहले निष्पादित करने पर विचार करें। अधिक संसाधनों के अधिग्रहण के लिए इंतज़ार कर रहे कार्यों को सुविधाजनक बनाने के

  • प्रदर्शन: नीचे SwitchToThread (से पहले कुछ pause सीपीयू निर्देश के साथ "स्पिन प्रतीक्षा") या एक नींद() कॉल, बहु सूत्रण सॉफ्टवेयर लाभ को धीमा करके व्यस्त प्रतीक्षा से आसानी से।
  • कताई के दौरान पाइपलाइन के कम हिस्सों का उपयोग करके दोनों द्वारा पावर-बचत।
  • स्विचटो थ्रेड() या नींद (0) या नींद (1) कॉल के ऊपरी हिस्से के कारण अनावश्यक रूप से निष्पादित निर्देशों के बहुमत का उन्मूलन।

हालांकि, अगर आप नींद कॉल करने के लिए जा रहे हैं (1) जो कम से कम एक millisecond जो CPU चक्र के मामले में बहुत लंबा है, की तुलना में आप उम्मीद कर रहे हैं कि आपके इंतजार चक्र बहुत लंबा हो जाएगा, इसलिए pause चलाता है इस मामले में निर्देश व्यर्थ होंगे।

जब प्रतीक्षा लूप लंबे समय तक रहने की उम्मीद है, तो ओएस सिंक्रनाइज़ेशन एपीआई फ़ंक्शंस में से एक को कॉल करके ऑपरेटिंग सिस्टम को उपज करना बेहतर है, जैसे विंडोज ओएस पर WaitForSingleObject, लेकिन SwitchToThread() या नींद नहीं (0) या नींद (1), क्योंकि वे लंबे इंतजार पर बहुत अपमानजनक हैं। इसके अलावा, नींद (1) बहुत धीमी है और ओएस सिंक्रनाइज़ेशन फ़ंक्शन जैसे WaitForSingleObject या EnterCriticalSection बहुत अधिक प्रतिक्रिया देंगे और वे अधिक संसाधन-अनुकूल हैं।

मेरा निष्कर्ष: नींद (0) या नींद (1) या SwitchToThread() का उपयोग न करना बेहतर है। हर कीमत पर "स्पिन-प्रतीक्षा" लूप से बचें। WaitForMultipleObjects(), SetEvent(), और इसी तरह उच्च-स्तरीय सिंक्रनाइज़ेशन फ़ंक्शंस का उपयोग करें - वे प्रदर्शन, दक्षता और पावर सेविंग की शर्तों से श्रेष्ठ हैं।यद्यपि वे महंगे संदर्भ स्विच और रिंग 3 से रिंग 0 संक्रमणों तक भी पीड़ित हैं, लेकिन ये खर्च कम हैं (नींद() या स्विचटॉथ्रेड() के साथ "स्पिन-वेट" लूप में जो खर्च किया गया है उससे तुलना में उचित हैं।

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

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

कुछ लोगों ने जो लिखा है उसके विपरीत, नींद (0) CPU खपत को शून्य के करीब नहीं कम करता है। यह 'तैयार' स्थिति में मौजूद अन्य धागे को निष्पादन जारी करता है, लेकिन यदि ऐसे कोई धागे नहीं हैं, तो यह हजारों CPU चक्रों को बर्बाद कर देता है और वर्तमान धागे के 100% CPU चक्रों का उपभोग करता है, जैसा कि demonstrated by stackoverflow members भी है - और मेरे पास भी है बस इसे दोबारा जांचें - नींद (0) पाश विंडोज 10 64-बिट पर मौजूदा थ्रेड के 100% सीपीयू का उपभोग करती है।

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