सभी को नमस्कार। आज हम
पायथन डेवलपर पाठ्यक्रम के शुभारंभ की पूर्व संध्या पर तैयार एक और अनुवाद साझा करना चाहते हैं। चलो चलते हैं!

मैंने पिछले 4-5 वर्षों में पायथन का उपयोग किसी भी अन्य प्रोग्रामिंग भाषा की तुलना में अधिक किया। पायथन फ़ायरफ़ॉक्स, परीक्षण और सीआई उपकरण के तहत बनाता है के लिए प्रमुख भाषा है। मर्क्यूरियल भी ज्यादातर पाइथन में लिखा गया है। मैंने इस पर अपने तीसरे पक्ष के कई प्रोजेक्ट भी लिखे।
अपने काम के दौरान, मैंने पायथन के प्रदर्शन और इसके अनुकूलन उपकरणों के बारे में थोड़ा ज्ञान प्राप्त किया। इस लेख में, मैं इस ज्ञान को साझा करना चाहूंगा।
पायथन के साथ मेरा अनुभव मुख्य रूप से सीपीथॉन दुभाषिया से संबंधित है, खासकर सीपीथॉन 2.7। मेरे सभी अवलोकन सभी पायथन वितरण के लिए सार्वभौमिक नहीं हैं, या उन लोगों के लिए जो पायथन के समान संस्करणों में समान विशेषताएं हैं। मैं कथा के दौरान इसका उल्लेख करने की कोशिश करूंगा। ध्यान रखें कि यह लेख पायथन के प्रदर्शन का विस्तृत विवरण नहीं है। मैं केवल उस बारे में बात करूंगा जो मैं अपने दम पर आया हूं।
मॉड्यूल शुरू करने और आयात करने की ख़ासियत के कारण लोड
पायथन इंटरप्रेटर शुरू करना और मॉड्यूल आयात करना एक लंबी प्रक्रिया है जब यह मिलीसेकंड में आता है।
यदि आपको अपनी किसी भी परियोजना में सैकड़ों या हजारों पायथन प्रक्रियाओं को शुरू करने की आवश्यकता है, तो मिलीसेकंड में यह देरी कई सेकंड तक देरी में बदल जाएगी।
यदि आप सीएलआई उपकरण प्रदान करने के लिए पायथन का उपयोग करते हैं, तो ओवरहेड उपयोगकर्ता के लिए ध्यान देने योग्य फ्रीज का कारण बन सकता है। यदि आपको तुरंत सीएलआई उपकरण की आवश्यकता है, तो प्रत्येक कॉल के साथ पायथन दुभाषिया को चलाना इस जटिल उपकरण को प्राप्त करना कठिन बना देगा।
मैंने इस समस्या के बारे में पहले ही लिख दिया था। मेरे कुछ पुराने नोट्स इस बारे में बात करते हैं, उदाहरण के लिए,
2014 में ,
मई 2018 और
अक्टूबर 2018 में ।
स्टार्टअप देरी को कम करने के लिए कई चीजें हैं जो आप नहीं कर सकते हैं: इस मामले को ठीक करना पायथन दुभाषिया को हेरफेर करने के लिए संदर्भित करता है, क्योंकि यह वह है जो कोड के निष्पादन को नियंत्रित करता है, जिसमें बहुत अधिक समय लगता है। स्टार्टअप में अतिरिक्त पायथन कोड निष्पादित करने से बचने के लिए आप कॉल में
साइट मॉड्यूल के आयात को अक्षम करने के लिए सबसे अच्छी बात कर सकते हैं। दूसरी ओर, कई एप्लिकेशन साइट थिंकपैड मॉड्यूल की कार्यक्षमता का उपयोग करते हैं, इसलिए आप इसे अपने जोखिम पर उपयोग कर सकते हैं।
हमें आयात मॉड्यूल की समस्या पर भी विचार करना चाहिए। पायथन दुभाषिया क्या अच्छा है अगर यह किसी भी कोड को संसाधित नहीं करता है? तथ्य यह है कि कोड को दुभाषिया के लिए मॉड्यूल के उपयोग के माध्यम से अधिक बार उपलब्ध कराया जाता है।
मॉड्यूल आयात करने के लिए, आपको कई कदम उठाने होंगे। और उनमें से प्रत्येक में भार और देरी का एक संभावित स्रोत है।
मॉड्यूल की खोज और उनके डेटा को पढ़ने के कारण एक निश्चित देरी होती है। जैसा कि मैंने
PyOxidizer के साथ प्रदर्शन किया है, एक फाइल सिस्टम से एक मॉड्यूल को आर्किटेक्चरली सरल समाधान के साथ खोजने और लोड करने की जगह ले रहा है, जिसमें मेमोरी संरचना में डेटा संरचना से मॉड्यूल डेटा पढ़ना शामिल है, आप इस कार्य के लिए प्रारंभिक समाधान समय के 70-80% के लिए मानक पायथन लाइब्रेरी आयात कर सकते हैं। फ़ाइल सिस्टम फ़ाइल में एक मॉड्यूल होने से फ़ाइल सिस्टम पर लोड बढ़ जाता है और निष्पादन के महत्वपूर्ण पहले चरणों के दौरान पायथन एप्लिकेशन को धीमा कर सकता है। PyOxidizer जैसे समाधान इससे बचने में मदद कर सकते हैं। मुझे उम्मीद है कि पायथन समुदाय वर्तमान दृष्टिकोण की इन लागतों को देखता है और मॉड्यूल के वितरण तंत्रों के लिए एक संक्रमण पर विचार कर रहा है, जो मॉड्यूल में व्यक्तिगत फ़ाइलों पर इतना निर्भर नहीं हैं।
एक मॉड्यूल के लिए अतिरिक्त आयात लागत का एक अन्य स्रोत आयात के दौरान उस मॉड्यूल में कोड का निष्पादन है। कुछ मॉड्यूल में मॉड्यूल के कार्यों और कक्षाओं के बाहर एक क्षेत्र में कोड के कुछ हिस्सों होते हैं, जो मॉड्यूल आयात होने पर निष्पादित होता है। इस तरह के कोड को निष्पादित करने से आयात की लागत बढ़ जाती है। वर्कअराउंड: आयात के समय सभी कोड निष्पादित न करें, लेकिन केवल यदि आवश्यक हो तो इसे निष्पादित करें। पायथन 3.7
__getattr__
मॉड्यूल का समर्थन करता है, जिसे एक मॉड्यूल की विशेषता नहीं पाए जाने पर कहा जाएगा। इसका उपयोग पहले उपयोग पर मॉड्यूल विशेषताओं को आलसी रूप से आबाद करने के लिए किया जा सकता है।
आयात मंदी से छुटकारा पाने का एक और तरीका है कि मॉड्यूल को आलसी तरीके से आयात किया जाए। आयात के दौरान सीधे मॉड्यूल लोड करने के बजाय, आप एक कस्टम आयात मॉड्यूल पंजीकृत करते हैं जो बदले में स्टब लौटाता है। जब आप पहली बार इस स्टब तक पहुँचते हैं, तो यह इस मॉड्यूल बनने के लिए वास्तविक मॉड्यूल और "म्यूट" को लोड करेगा।
यदि आप फ़ाइल सिस्टम को बायपास करते हैं और मॉड्यूल के अनावश्यक भागों को चलाने से बचते हैं (मॉड्यूल आमतौर पर वैश्विक रूप से आयात किए जाते हैं, लेकिन केवल कुछ मॉड्यूल फ़ंक्शन का उपयोग किया जाता है) तो आप दसियों मिलीसेकंड को दसियों मॉड्यूल से बचा सकते हैं।
मॉड्यूल का आलसी आयात एक नाजुक चीज है। कई मॉड्यूल में ऐसे टेम्पलेट हैं जिनमें निम्नलिखित चीजें हैं:
try: import foo
;
except ImportError:
एक आलसी मॉड्यूल आयातक कभी भी एक ImportError नहीं फेंक सकता है, क्योंकि यदि वह करता है, तो उसे मॉड्यूल के लिए फाइल सिस्टम में देखना होगा कि क्या यह सिद्धांत में मौजूद है। यह अतिरिक्त भार जोड़ देगा और खर्च किए गए समय को बढ़ाएगा, इसलिए आलसी आयातक सिद्धांत में ऐसा नहीं करते हैं! यह समस्या बहुत कष्टप्रद है। आलसी मॉड्यूल के आयातक मर्क्यूरियल उन मॉड्यूलों की एक सूची की प्रक्रिया करता है, जिन्हें आलसी आयात नहीं किया जा सकता है, और इसे उन्हें बायपास करना होगा। एक अन्य समस्या
from foo import x, y
वाक्य रचना
from foo import x, y
, जो उन मामलों में भी आलसी मॉड्यूल के आयात को बाधित करता है जहां फू एक मॉड्यूल है (पैकेज के विपरीत), क्योंकि मॉड्यूल को अभी भी x और y के संदर्भ को वापस करने के लिए आयात किया जाना चाहिए।
PyOxidizer में बाइनरी में वायर्ड मॉड्यूल का एक निश्चित सेट है, इसलिए यह ImportError को बढ़ाने में प्रभावी हो सकता है। पायथन 3.7 से __getattr__ मॉड्यूल आलसी मॉड्यूल आयातकों के लिए अतिरिक्त लचीलापन प्रदान करता है। मैं कुछ प्रक्रियाओं को स्वचालित करने के लिए एक विश्वसनीय आलसी आयातक को PyOxidizer में एकीकृत करने की उम्मीद करता हूं।
दुभाषिया शुरू करने और समय की देरी से बचने का सबसे अच्छा समाधान पायथन में पृष्ठभूमि की प्रक्रिया शुरू करना है। यदि आप एक पायनियर प्रक्रिया के रूप में पायथन प्रक्रिया शुरू करते हैं, एक वेब सर्वर के लिए कहते हैं, तो आप यह कर सकते हैं। समाधान मर्क्यूरियल ऑफ़र एक पृष्ठभूमि प्रक्रिया शुरू करने के लिए है जो
कमांड सर्वर प्रोटोकॉल प्रदान करता है। hg C निष्पादन योग्य (या अब Rust) है, जो इस पृष्ठभूमि की प्रक्रिया से जुड़ता है और एक कमांड भेजता है। कमांड सर्वर के लिए एक दृष्टिकोण खोजने के लिए, आपको बहुत सारे काम करने की आवश्यकता है, यह बेहद अस्थिर है और इसमें सुरक्षा समस्याएं हैं। मैं PyOxidizer का उपयोग करके एक कमांड सर्वर देने के विचार पर विचार कर रहा हूं ताकि निष्पादन योग्य फ़ाइल के अपने फायदे हों, और सॉफ्टवेयर समाधान की लागत की समस्या खुद PyOxidizer प्रोजेक्ट बनाकर हल की गई थी।
कॉल देरी
पायथन में कॉलिंग फ़ंक्शन एक अपेक्षाकृत धीमी प्रक्रिया है। (यह अवलोकन PyPy पर कम लागू है, जो JIT कोड निष्पादित कर सकता है।)
मैंने मर्क्यूरियल के लिए दर्जनों पैच देखे, जिससे कॉलिंग फ़ंक्शन के रूप में अनावश्यक भार से बचने के लिए कोड को इस तरह से संरेखित और संयोजित करना संभव हो गया। वर्तमान विकास चक्र में, प्रगति बार को अपडेट करते समय कुछ फ़ंक्शन को कम करने के लिए कुछ प्रयास किए गए हैं। (हम किसी भी ऑपरेशन के लिए प्रगति बार का उपयोग करते हैं जिसमें कुछ समय लग सकता है, ताकि उपयोगकर्ता समझता है कि क्या हो रहा है)। कॉलिंग
फ़ंक्शन के परिणामों को प्राप्त करना और
फ़ंक्शंस के बीच सरल खोजों से बचने पर निष्पादन में सैकड़ों मिलीसेकंड की बचत होती है जब हम एक मिलियन निष्पादन के बारे में बात करते हैं, उदाहरण के लिए।
यदि आपके पास पायथन में तंग छोर या पुनरावर्ती कार्य हैं जहां सैकड़ों हजारों या अधिक फ़ंक्शन कॉल हो सकते हैं, तो आपको एक व्यक्तिगत फ़ंक्शन को कॉल करने के ओवरहेड के बारे में पता होना चाहिए, क्योंकि यह बहुत महत्व का है। ओवरहेड से बचने के लिए सरल अंतर्निहित कार्यों और कार्यों को संयोजित करने की क्षमता को ध्यान में रखें।
विशेषता लुक ओवरहेड
यह समस्या एक फ़ंक्शन कॉल के कारण ओवरहेड के समान है, क्योंकि अर्थ लगभग समान है!
पायथन में हल करने के गुण ढूँढना धीमा हो सकता है। (और फिर से, PyPy में, यह तेज है)। हालाँकि, इस समस्या से निपटना हम अक्सर मर्क्यूरियल में करते हैं।
मान लीजिए कि आपके पास निम्नलिखित कोड हैं:
obj = MyObject() total = 0 for i in len(obj.member): total += obj.member[i]
ओमित करें कि इस उदाहरण को लिखने के लिए और अधिक कुशल तरीके हैं (उदाहरण के लिए,
total = sum(obj.member)
), और ध्यान दें कि लूप को प्रत्येक पुनरावृत्ति पर obj.member परिभाषित करने की आवश्यकता है। पायथन में
विशेषताओं को परिभाषित करने के लिए एक अपेक्षाकृत परिष्कृत तंत्र है। सरल प्रकारों के लिए, यह काफी तेज हो सकता है। लेकिन जटिल प्रकारों के लिए, यह विशेषता पहुंच स्वचालित रूप से
__getattr__
,
__getattribute__
, विभिन्न
__getattribute__
विधियों और यहां तक कि
@property
उपयोगकर्ता-परिभाषित फ़ंक्शन को कॉल कर सकती है। यह एक विशेषता की त्वरित खोज के समान है जो कई फ़ंक्शन कॉल कर सकता है, जिससे अतिरिक्त लोड हो जाएगा। और अगर आप
obj.member1.member2.member3
, आदि जैसी चीजों का उपयोग करते हैं, तो यह लोड बढ़ सकता है।
प्रत्येक विशेषता परिभाषा एक अतिरिक्त लोड का कारण बनती है। और चूंकि पायथन में लगभग सब कुछ एक शब्दकोश है, हम कह सकते हैं कि हर विशेषता खोज एक शब्दकोश खोज है। बुनियादी डेटा संरचनाओं के बारे में सामान्य अवधारणाओं से, हम जानते हैं कि डिक्शनरी खोज उतनी तेज़ नहीं है, जितना कहना है, इंडेक्स सर्च। हां, निश्चित रूप से सीपीथॉन में कुछ ट्रिक्स हैं जो शब्दकोश खोजों के कारण ओवरहेड से छुटकारा पा सकते हैं। लेकिन मुख्य विषय जिस पर मैं स्पर्श करना चाहता हूं वह यह है कि किसी भी विशेषता खोज एक संभावित प्रदर्शन रिसाव है।
तंग छोरों के लिए, विशेष रूप से वे जो संभावित रूप से सैकड़ों हजारों पुनरावृत्तियों से अधिक होते हैं, आप स्थानीय चर के लिए एक मान असाइन करके विशेषताओं को खोजने के लिए इन औसत दर्जे के ओवरहेड्स से बच सकते हैं। आइए निम्नलिखित उदाहरण देखें:
obj = MyObject() total = 0 member = obj.member for i in len(member): total += member[i]
बेशक, यह केवल सुरक्षित रूप से किया जा सकता है अगर इसे एक चक्र में प्रतिस्थापित नहीं किया जाता है। यदि ऐसा होता है, तो पुनरावृत्त पुराने तत्व का लिंक रखेगा और सब कुछ विस्फोट हो सकता है।
ऑब्जेक्ट की विधि को कॉल करते समय एक ही चाल का प्रदर्शन किया जा सकता है। के बदले
obj = MyObject() for i in range(1000000): obj.process(i)
आप निम्न कार्य कर सकते हैं:
obj = MyObject() fn = obj.process for i in range(1000000:) fn(i)
यह भी ध्यान देने योग्य है कि मामले में जब विशेषता खोज को एक विधि को कॉल करने की आवश्यकता होती है (जैसा कि पिछले उदाहरण में), तो पायथन 3.7 पिछले रिलीज की तुलना में अपेक्षाकृत
तेज है। लेकिन मुझे यकीन है कि यहां अत्यधिक लोड जुड़ा हुआ है, सबसे पहले, फ़ंक्शन कॉल के साथ, और विशेषता खोज पर लोड के साथ नहीं। इसलिए, यदि आप विशेषताओं के लिए अतिरिक्त खोज को छोड़ देते हैं, तो सब कुछ तेज़ी से काम करेगा।
अंत में, चूंकि एक विशेषता खोज इसके लिए एक फ़ंक्शन को कॉल करता है, इसलिए यह कहा जा सकता है कि फ़ंक्शन कॉल के कारण लोड की तुलना में विशेषता खोज आमतौर पर एक समस्या से कम है। आमतौर पर, गति में महत्वपूर्ण परिवर्तनों को नोटिस करने के लिए, आपको बहुत सी विशेषता खोजों को समाप्त करना होगा। इस मामले में, जैसे ही आप लूप के अंदर सभी विशेषताओं तक पहुंच देते हैं, आप फ़ंक्शन को कॉल करने से पहले लूप में केवल 10 या 20 विशेषताओं के बारे में बात कर सकते हैं। और हजारों या दसियों पुनरावृत्तियों में से कम से कम हजारों के साथ छोरों को जल्दी से सैकड़ों हजारों या लाखों विशेषता खोज प्रदान कर सकते हैं। इसलिए सावधान!
वस्तु भार
पायथन इंटरप्रेटर के दृष्टिकोण से, सभी मूल्य ऑब्जेक्ट हैं। CPython में, प्रत्येक तत्व एक PyObject संरचना है। दुभाषिया द्वारा नियंत्रित प्रत्येक वस्तु ढेर पर होती है और इसकी अपनी स्मृति होती है जिसमें संदर्भ संख्या, वस्तु का प्रकार और अन्य पैरामीटर होते हैं। कचरा कलेक्टर द्वारा प्रत्येक वस्तु का निपटान किया जाता है। इसका अर्थ है कि प्रत्येक नई वस्तु संदर्भ गिनती, कचरा संग्रह आदि के कारण ओवरहेड जोड़ देती है। (और फिर से, PyPy इस अनावश्यक बोझ से बच सकता है, क्योंकि यह अल्पकालिक मूल्यों के जीवनकाल के बारे में अधिक "सावधान" है।)
आम तौर पर, आपके द्वारा बनाए गए अधिक अद्वितीय मूल्य और पायथन ऑब्जेक्ट आपके लिए धीमी चीजें काम करते हैं।
मान लीजिए कि आप एक लाख वस्तुओं के संग्रह पर पुनरावृति करते हैं। आप इस ऑब्जेक्ट को टपल में एकत्रित करने के लिए एक फ़ंक्शन कहते हैं:
for x in my_collection: a, b, c, d, e, f, g, h = process(x)
इस उदाहरण में,
process()
8-ट्यूपल टपल लौटाएगी। इससे कोई फर्क नहीं पड़ता है कि हम रिटर्न वैल्यू को नष्ट करते हैं या नहीं: इस ट्यूपल को पायथन में कम से कम 9 मान बनाने की आवश्यकता है: टपल के लिए 1 और इसके आंतरिक सदस्यों के लिए 8। ठीक है, वास्तविक जीवन में कम मूल्य हो सकते हैं यदि
process()
किसी मौजूदा वस्तु का संदर्भ देती है। या, इसके विपरीत, अधिक हो सकते हैं यदि उनके प्रकार सरल नहीं हैं और प्रतिनिधित्व करने के लिए कई PyObjects की आवश्यकता होती है। मैं सिर्फ यह कहना चाहता हूं कि दुभाषिये के हुड के नीचे कुछ निर्माणों की पूरी प्रस्तुति के लिए वस्तुओं की एक वास्तविक बाजीगरी है।
अपने स्वयं के अनुभव से मैं कह सकता हूं कि ये ओवरहेड केवल उन ऑपरेशनों के लिए प्रासंगिक हैं जो सी या रस्ट जैसी मूल भाषा में लागू होने पर गति प्राप्त करते हैं। समस्या यह है कि सीपीथॉन दुभाषिया बस इतनी तेजी से बायटेकोड को निष्पादित करने में असमर्थ है कि वस्तुओं की संख्या के कारण अतिरिक्त भार। इसके बजाय, आपको किसी फ़ंक्शन को कॉल करके या बोझिल गणनाओं आदि के माध्यम से प्रदर्शन को कम करने की संभावना है। इससे पहले कि आप वस्तुओं के कारण अतिरिक्त भार को नोटिस कर सकें। बेशक, कुछ अपवाद हैं, अर्थात् ट्यूल या कई मूल्यों के शब्दकोशों का निर्माण।
ओवरहेड के एक ठोस उदाहरण के रूप में, आप कम-स्तरीय डेटा संरचनाओं को पार्स करने वाले C कोड के साथ Mercurial का हवाला दे सकते हैं। अधिक पार्सिंग गति के लिए, सी कोड, सीपीथॉन की तुलना में तेजी से परिमाण का क्रम चलाता है। लेकिन जैसे ही सी कोड परिणाम का प्रतिनिधित्व करने के लिए PyObject बनाता है, गति कई बार गिर जाती है। दूसरे शब्दों में, लोड में पायथन तत्वों का निर्माण और प्रबंधन शामिल है ताकि उन्हें कोड में उपयोग किया जा सके।
इस समस्या का एक तरीका पायथन में कम तत्वों का उत्पादन करना है। यदि आपको किसी एक तत्व को संदर्भित करने की आवश्यकता है, तो फ़ंक्शन शुरू करें और इसे वापस लौटाएं, न कि टपल या एन तत्वों का शब्दकोश। हालांकि, फ़ंक्शन कॉल के कारण संभावित लोड की निगरानी करना बंद न करें!
यदि आपके पास बहुत से कोड हैं जो CPython C API का उपयोग करके तेज़ी से काम करते हैं, और ऐसे तत्व जिन्हें विभिन्न मॉड्यूलों के बीच वितरित करने की आवश्यकता होती है, तो Python प्रकारों के बिना करें जो C संरचनाओं के रूप में अलग-अलग डेटा का प्रतिनिधित्व करते हैं और इन संरचनाओं को एक्सेस करने के लिए पहले से ही कोड संकलित कर चुके हैं। इसके बजाय सीपीथॉन सी एपीआई के माध्यम से जा रहा है। डेटा तक पहुंचने के लिए CPython C API से बचने से, आपको बहुत सारे अतिरिक्त भार से छुटकारा मिल जाएगा।
तत्वों को डेटा के रूप में व्यवहार करना (एक पंक्ति में सब कुछ एक्सेस करने के लिए कार्य करने के बजाय) एक पायथन के लिए सबसे अच्छा तरीका होगा। पहले से संकलित कोड के लिए एक और वैकल्पिक हल है PyObject को तुरंत रद्द करना। यदि आप जटिल तत्वों का प्रतिनिधित्व करने के लिए Python (PyTypeObject) में एक कस्टम प्रकार बनाते हैं, तो आपको विशेषता के मान को देखने के लिए कस्टम C फ़ंक्शन बनाने के लिए
tp_members या
tp_getet फ़ील्ड को परिभाषित करना
होगा । यदि आप कहते हैं, तो एक पार्सर लिखें और जानें कि ग्राहकों को केवल विश्लेषण किए गए क्षेत्रों के सबसेट तक पहुंच प्राप्त होगी, आप जल्दी से एक प्रकार का कच्चा डेटा बना सकते हैं, इस प्रकार को वापस कर सकते हैं और पायथन विशेषताओं को खोजने के लिए C फ़ंक्शन को कॉल कर सकते हैं जो PyOffject की प्रक्रिया करता है। आप भी पार्सिंग में देरी कर सकते हैं जब तक कि फ़ंक्शन को संसाधनों को बचाने के लिए नहीं बुलाया जाता है यदि पार्सिंग की कभी आवश्यकता नहीं होती है! यह तकनीक काफी दुर्लभ है, क्योंकि इसमें गैर-तुच्छ कोड लिखने की आवश्यकता होती है, लेकिन यह एक सकारात्मक परिणाम देता है।
प्रारंभिक संग्रह आकार निर्धारण
यह CPython C API पर लागू होता है।
सूची या शब्दकोश जैसे संग्रह बनाते समय, नए संग्रह को पॉप्युलेट करने के लिए
PyList_New()
+
PyList_SET_ITEM()
का उपयोग करें यदि इसका आकार पहले से ही निर्माण के समय परिभाषित है। यह संग्रह के आकार को पूर्व-निर्धारित करेगा ताकि उसमें तत्वों की एक सीमित संख्या रखने में सक्षम हो। यह आइटम सम्मिलित करते समय एक पर्याप्त संग्रह आकार के लिए जाँच को छोड़ने में मदद करता है। हजारों वस्तुओं का संग्रह बनाते समय, यह आपको कुछ संसाधनों को बचाएगा!
C API में Zero-copy का उपयोग करना
पायथन सी एपीआई वास्तव में उनके संदर्भों को लौटाने के बजाय वस्तुओं की प्रतियां बनाना पसंद करता है। उदाहरण के लिए,
PyBytes_FromStringAndSize () प्रतियां
char*
पायथन द्वारा आरक्षित मेमोरी में। यदि आप बड़ी संख्या में मान या बड़े डेटा के लिए ऐसा करते हैं, तो हम मेमोरी I / O के गीगाबाइट और आवंटनकर्ता पर संबंधित लोड के बारे में बात कर सकते हैं।
यदि आपको सी एपीआई के बिना उच्च-प्रदर्शन कोड लिखने की आवश्यकता है, तो आपको अपने आप को
बफर प्रोटोकॉल और संबंधित प्रकारों, जैसे कि
मेमोरीव्यू से परिचित करना चाहिए
।Buffer protocol
पायथन प्रकारों में बनाया गया है और दुभाषियों को / बाइट्स से टाइप करने की अनुमति देता है। यह सी कोड दुभाषिया को एक निश्चित आकार के एक
void*
विवरणक प्राप्त करने की भी अनुमति देता है। यह आपको PyObject के साथ मेमोरी में किसी भी पते को जोड़ने की अनुमति देता है। बाइनरी डेटा के साथ काम करने वाले कई कार्य पारदर्शी रूप से
buffer protocol
लागू करने वाली किसी भी वस्तु को स्वीकार करते हैं। और यदि आप किसी भी ऑब्जेक्ट को बाइट्स के रूप में स्वीकार करना चाहते हैं, तो आपको फ़ंक्शन तर्क प्राप्त करते समय
s*
,
y*
या
w*
प्रारूप की इकाइयों का उपयोग करने की आवश्यकता है।
buffer protocol
का उपयोग करते हुए, आप दुभाषिया को
zero-copy
संचालन का उपयोग करने के लिए सबसे अच्छा उपलब्ध अवसर देते हैं और अतिरिक्त बाइट्स को मेमोरी में कॉपी करने से मना करते हैं।
फॉर्म
memoryview
पायथन में प्रकारों का उपयोग करके, आप प्रतियों को बनाने के बजाय, पायथन को संदर्भ द्वारा मेमोरी स्तरों तक पहुंचने की अनुमति देंगे।
यदि आपके पास गीगाबाइट का कोड है जो आपके पायथन प्रोग्राम से गुजरता है, तो शून्य-कॉपी का समर्थन करने वाले पायथन प्रकारों का व्यावहारिक उपयोग आपको प्रदर्शन अंतर से बचाएगा। मैंने एक बार देखा कि
पायथन-ज़स्टेनडाइट किसी भी पायथन एलजेड 4 बाइंडिंग की तुलना में अधिक तेज़ निकला (हालाँकि यह चारों ओर का दूसरा तरीका होना चाहिए), क्योंकि मैंने
buffer protocol
बहुत अधिक उपयोग किया और अत्यधिक स्मृति I / O
python-zstandard
!
निष्कर्ष
इस लेख में, मैंने कई वर्षों तक अपने पायथन कार्यक्रमों को अनुकूलित करते हुए सीखी गई कुछ चीजों के बारे में बात करना चाहा। मैं दोहराता हूं और कहता हूं कि यह किसी भी तरह से पायथन के प्रदर्शन में सुधार के तरीकों का व्यापक अवलोकन नहीं है। मैं मानता हूं कि मैं शायद दूसरों की तुलना में पायथन का अधिक उपयोग करता हूं, और मेरी सिफारिशों को सभी कार्यक्रमों पर लागू नहीं किया जा सकता है।
आपको किसी भी तरह से अपने पायथन कोड को बड़े पैमाने पर सही नहीं करना चाहिए और उदाहरण के लिए, इस लेख को पढ़ने के बाद विशेषताओं की खोज करना चाहिए । हमेशा की तरह, जब प्रदर्शन अनुकूलन की बात आती है, तो पहले ठीक करें कि कोड विशेष रूप से धीमा कहां है।
py-spy Python. , , Python, . , , , !
, Python . , , Python - . Python – PyPy, . Python . , Python , . , « ». , , , Python, , , .
;-)