शुरुआती लोगों के लिए Rust अनुप्रयोगों का प्रदर्शन अनुकूलन

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

परिचय: Rust का प्रदर्शन जादू नहीं, बल्कि अनुशासन क्यों है



Rust को उचित रूप से सबसे तेज़ सिस्टम प्रोग्रामिंग भाषाओं में से एक माना जाता है। हालाँकि, किसी भी अन्य भाषा की तरह, "कच्चा" कोड हमेशा अपनी सीमा पर काम नहीं करता है। कई नौसिखिए डेवलपर्स, Python या JavaScript से Rust में आते हुए, तत्काल गति में वृद्धि की उम्मीद करते हैं, लेकिन भूल जाते हैं कि अनुकूलन एक प्रक्रिया है, कंपाइलर का उपहार नहीं।



यह लेख उन लोगों के लिए है जिन्होंने पहले ही Rust में अपने पहले प्रोग्राम लिखे हैं और समझना चाहते हैं कि उनसे अधिकतम कैसे प्राप्त करें। हम तीन प्रमुख क्षेत्रों पर चर्चा करेंगे: प्रोफाइलिंग (यह जानने के लिए कि क्या सुधारना है), zero-cost एब्स्ट्रैक्शन (ताकि आप उस चीज़ के लिए भुगतान न करें जिसका आप उपयोग नहीं करते) और मेमोरी प्रबंधन (बाधाओं से बचने के लिए)। सभी उदाहरण कोड के साथ होंगे जिन्हें आप तुरंत अपने वातावरण में चला सकते हैं।



1. प्रोफाइलिंग: अनुकूलन से पहले, मापें



अनुकूलन का मुख्य नियम: आँख बंद करके अनुकूलन न करें। प्रोफाइलिंग के बिना, आप कोड को "तेज़" करने में घंटों बर्बाद करने का जोखिम उठाते हैं जो पहले से ही तेज़ है, जबकि वास्तविक बाधा पर किसी का ध्यान नहीं जाता।



प्रोफाइलिंग के लिए उपकरण



Rust इकोसिस्टम में कई उत्कृष्ट उपकरण हैं। शुरुआत के लिए मैं cargo-flamegraph की सलाह देता हूँ - यह कल्पना करता है कि प्रोग्राम सबसे अधिक समय कहाँ बिताता है। स्थापना:



cargo install flamegraph


अपनी बाइनरी फ़ाइल के लिए प्रोफाइलिंग चलाएँ:



cargo flamegraph --bin my_app


निष्पादन के बाद, आपको "फ्लेम-ग्राफ" के साथ एक SVG फ़ाइल प्राप्त होगी। चौड़े "कॉलम" उन फ़ंक्शन को दिखाते हैं जो सबसे अधिक CPU का उपभोग करते हैं।



उदाहरण: बाधा का पता लगाना



मान लीजिए कि हमारे पास एक फ़ंक्शन है जो संख्याओं के वर्गों का योग करता है:



fn sum_of_squares(n: u64) -> u64 {    let mut sum = 0;    for i in 1..=n {        sum += i * i;    }    sum}


यदि प्रोफाइलर दिखाता है कि 90% समय इस फ़ंक्शन पर खर्च होता है, तो हम जानते हैं कि कहाँ देखना है। यदि बाधा इनपुट-आउटपुट (जैसे फ़ाइल पढ़ना) है, तो गणनाओं का अनुकूलन परिणाम नहीं देगा।



2. Zero-cost एब्स्ट्रैक्शन: कंपाइलर कैसे मदद करता है (और बाधा डालता है)



Rust की मुख्य विशेषताओं में से एक zero-cost एब्स्ट्रैक्शन की अवधारणा है। इसका मतलब है कि उच्च-स्तरीय निर्माण (इटरेटर, closures, ट्रेट्स) को मैन्युअल रूप से लूप लिखने की तुलना में कोई अतिरिक्त ओवरहेड नहीं जोड़ना चाहिए। हालाँकि, यह केवल सही उपयोग के साथ काम करता है।



इटरेटर बनाम लूप



कई नौसिखिए इस तरह लिखते हैं:



let v: Vec<i32> = (0..1000).collect();let mut result = Vec::new();for i in &v {    result.push(i * 2);}


इस कोड को इटरेटर का उपयोग करके फिर से लिखा जा सकता है, और Rust कंपाइलर इसे उसी मशीन कोड में अनुकूलित करेगा:



let v: Vec<i32> = (0..1000).collect();let result: Vec<i32> = v.iter().map(|x| x * 2).collect();


इसके अलावा, यदि आप क्रमिक रूप से filter, map और fold का उपयोग करते हैं, तो कंपाइलर उन्हें एक ही पास में "मर्ज" कर सकता है - इसे loop fusion कहा जाता है। मैन्युअल लूप ऐसा अनुकूलन प्रदान नहीं करते हैं।



Box<dyn Trait> बनाम generics



एक और सामान्य गलती ट्रेट-ऑब्जेक्ट्स (Box<dyn SomeTrait>) का अत्यधिक उपयोग है। वे डायनेमिक डिस्पैच का कारण बनते हैं, जो ओवरहेड जोड़ता है। यदि संकलन समय पर विकल्पों की संख्या ज्ञात है, तो generics (स्टैटिक डिस्पैच) का उपयोग करें:



// बुरा: डायनेमिक डिस्पैचfn process(items: Vec<Box<dyn Processor>>) {    for item in items {        item.run();    }}

// अच्छा: स्टैटिक डिस्पैचfn process<T: Processor>(items: Vec<T>) { for item in items { item.run()

ब्लॉग

पुस्तक अनुशंसाएँ