2016-04-21 5 views
7

संक्षिप्त प्रश्न:
क्या किसी और को सिंगलटन .NET HttpClient का उपयोग करने में कोई समस्या आई है, जहां एप्लिकेशन पुनरारंभ होने तक प्रोसेसर को 100% पर चिपकाता है?.NET: शब्दकोश के कारण HttpClient में 100% CPU उपयोग?

विवरण:
मैं एक Windows सेवा है कि निरंतर, अनुसूची आधारित ईटीएल करता चल रहा हूँ। कभी-कभी डेटा-सिंकिंग थ्रेड में से एक या तो मर जाता है, या नियंत्रण से बाहर निकलता है और प्रोसेसर को 100% पर चिपकाता है।

मैं भाग्यशाली था कि किसी ने बस सेवा (मानक फिक्स) को फिर से शुरू करने से पहले यह लाइव हो रहा था, और एक डंप-फ़ाइल को पकड़ने में सक्षम था।

WinDbg (w/SOS और SOSEX) में इसे लोड करना, मैंने पाया कि मेरे पास लगभग 15 धागे (मुख्य प्रसंस्करण धागे के उप-कार्य) हैं जो सभी समान स्टैक-निशान के साथ चल रहे हैं। हालांकि, कोई डेडलॉक्स नहीं दिखता है। अर्थात। उच्च उपयोग धागे चल रहे हैं, लेकिन कभी खत्म नहीं हो रहा है।

प्रासंगिक ढेर ट्रेस खंड (छोड़े गए पते) इस प्रकार है:

System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].FindEntry(System.__Canon) 
System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].TryGetValue(System.__Canon, System.__Canon ByRef) 
System.Net.Http.Headers.HttpHeaders.ContainsParsedValue(System.String, System.Object) 
System.Net.Http.Headers.HttpGeneralHeaders.get_TransferEncodingChunked() 
System.Net.Http.Headers.HttpGeneralHeaders.AddSpecialsFrom(System.Net.Http.Headers.HttpGeneralHeaders) 
System.Net.Http.Headers.HttpRequestHeaders.AddHeaders(System.Net.Http.Headers.HttpHeaders) 
System.Net.Http.HttpClient.SendAsync(System.Net.Http.HttpRequestMessage, System.Net.Http.HttpCompletionOption, System.Threading.CancellationToken) 
... 
[Our Application Code] 
this article (और दूसरों को मैंने पाया), शब्दकोशों के उपयोग धागा सुरक्षित, और अनंत छोरों नहीं है के अनुसार

यदि आप एक बहु-थ्रेडेड तरीके से एक शब्दकोश का उपयोग करते हैं तो संभव है (जैसे सीधे क्रैश होते हैं)।

लेकिन हमारे आवेदन कोड स्पष्ट रूप से एक शब्दकोश का उपयोग नहीं कर रहा है। तो स्टैक-ट्रेस में वर्णित शब्दकोश कहां है?

.NET परावर्तक के माध्यम से, दिखाई देता है कि HttpClient "DefaultRequestHeaders" प्रॉपर्टी में कॉन्फ़िगर किए गए किसी भी मान को स्टोर करने के लिए शब्दकोश का उपयोग करता है। इसलिए, एचटीपी क्लाइंट के माध्यम से भेजे जाने वाले किसी भी अनुरोध से, सिंगलटन, गैर-थ्रेड-सुरक्षित शब्दकोश (अनुरोध में डिफ़ॉल्ट शीर्षलेख जोड़ने के लिए) की गणना को ट्रिगर करता है, जो संभावित रूप से असीमित रूप से स्पिन (या मार सकता है) एक भ्रष्टाचार होता है।

माइक्रोसॉफ्ट ने स्पष्ट रूप से कहा है कि एचटीपी क्लाइंट क्लास थ्रेड-सुरक्षित है। लेकिन ऐसा लगता है जैसे यह किसी भी शीर्षलेख को HttpClient के DefaultRequestHeaders में जोड़ा गया है, तो यह अब सत्य नहीं है।

मेरा विश्लेषण यह इंगित करता है कि यह वास्तविक मूल समस्या है, और एक आसान कामकाज केवल डिफ़ॉल्टRequestHeaders का उपयोग नहीं करना है जहां HttpClient को बहु-थ्रेडेड तरीके से उपयोग किया जा सकता है।

हालांकि, मैं कुछ पुष्टि की तलाश में हूं कि मैं गलत पेड़ को भड़क नहीं रहा हूं। यदि यह सही है, तो यह .NET ढांचे में एक बग जैसा लगता है, जिसे मैं स्वचालित रूप से संदेह करता हूं।

शब्दशः प्रश्न के लिए खेद है, लेकिन आपके पास किसी भी इनपुट के लिए धन्यवाद।

+0

यह थ्रेड सॉफ्टी के साथ उनका मानक स्पिल है: "इस प्रकार के किसी भी सार्वजनिक स्थैतिक (विजुअल बेसिक में साझा) सदस्य थ्रेड सुरक्षित हैं। किसी भी इंस्टेंस सदस्यों को थ्रेड सुरक्षित होने की गारंटी नहीं है।" –

+0

कृपया एक [mcve] –

+1

प्रदान करें क्यों Http क्लाइंट को सिंगलटन बनाते हैं? ऐसा लगता है कि सबसे आसान फिक्स बस प्रत्येक थ्रेड को बनाने और अपने उदाहरण का उपयोग करने देना होगा। – pquest

उत्तर

1

सभी टिप्पणियों के लिए धन्यवाद; उन्होंने मुझे विभिन्न लाइनों के साथ सोचने के लिए प्रेरित किया, और इस मुद्दे के अंतिम मूल कारण को खोजने में मेरी मदद की।

private HttpClient InitializeClient() 
{ 
    if (_client == null) 
    { 
     _client = GetHttpClient(); 
     _client.DefaultRequestHeaders.Accept.Clear(); 
     _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
     SetBaseAddress(BaseAddress); 
    } 
    return _client; 
} 

मैंने कहा कि HttpClient एक सिंगलटन था,:

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

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

(ध्यान दें कि यह ऑब्जेक्ट के कन्स्ट्रक्टर में नहीं किया जा रहा है क्योंकि यह एक अमूर्त वर्ग है, और "GetHttpClient" एक सार विधि है - बीटीडब्लू: कभी भी बेस-क्लास के कन्स्ट्रक्टर में एक सार विधि को कॉल न करें। .. जो अन्य दुःस्वप्न का कारण बनता है)

बेशक, यह काफी स्पष्ट है कि यह थ्रेड-सुरक्षित नहीं है, और परिणामस्वरूप व्यवहार गैर-निर्धारक है।

यह कोड डबल-चेक किए गए "लॉक" कथन के पीछे इस कोड को रखना है (हालांकि मैं "डिफ़ॉल्टRequestHeaders" प्रॉपर्टी के उपयोग को समाप्त कर दूंगा, क्योंकि बस)।

संक्षेप में, यदि आप एचटीपी क्लाइंट को प्रारंभ करने में सावधान हैं तो मेरा मूल प्रश्न कभी भी एक मुद्दा नहीं होना चाहिए।

आपके द्वारा प्रदान किए गए विचारों की स्पष्टता के लिए धन्यवाद!

+0

यह एक क्लासिक थ्रेडिंग समस्या है। दौड़ के कारण हैश टेबल चक्रीय हो जाता है। बोलने के लिए एक अनंत टकराव। मैंने आपका प्रश्न नहीं देखा या मैंने जवाब दिया होगा। – usr

+0

@usr: कोई चिंता नहीं; मैं इस कारण के रूप में एक अच्छा स्पष्टीकरण प्राप्त करने के लिए बस खुश हूँ। :) – Greenknight

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