सूर्य कहता है, पायथन cProfile के साथ बॉटलनेक फ़ंक्शन की पहचान करें!

9 min

language: ja bn en es hi pt ru zh-cn zh-tw

हम!
ऊ!
करीब आओ!
म्याऊ!

नमस्ते, मैं अक्षम हूँ।
हाल ही में, मुझे मासाहिरो सकुराई के चैनल को बैकग्राउंड में रेडियो की तरह सुनना बहुत पसंद है, जो पहले हाल लेबोरेटरीज़ से थे, जब मैं अपने पीसी पर काम कर रहा होता हूँ।
वास्तव में, मुझे 3DS के साथ खेलने की यादें भी ताज़ा हो गईं, और उस समय इवाटा-शचो के निंटेंडो डायरेक्ट हमेशा मज़ेदार होते थे। जब मैं उन्हें फिर से देखता हूँ, तो मुझे फुजित्सु के तोशियो इकेडा जैसे अन्य लोग याद आते हैं; वृत्तचित्रों को देखने पर उनमें बहुत ऊर्जा दिखती है, और उस समय अमेरिका की कई यात्राएँ करना एक अविश्वसनीय दुनिया थी। उस समय वियतनाम युद्ध भी चल रहा था, और द्वितीय विश्व युद्ध के बाद युद्ध के बाद की छाया भी थी, फिर भी वह सारी ऊर्जा कहाँ से आई?

परिचय

मैं स्क्रिप्टिंग भाषाओं की निष्पादन गति के बारे में ज्यादा जागरूक नहीं था, लेकिन जब मैं अपना बनाया हुआ cuckooget चला रहा था, तो मुझे इसके बारे में सोचना पड़ा।
कुछ हिस्सों में, PyO3/maturin का उपयोग करके इंटरप्रेटर के भीतर रस्ट में लिखे कोड को निष्पादित किया जा सकता है।
सरल शब्दों में, रस्ट में लिखे फ़ंक्शन को पायथन लाइब्रेरी में बदल दिया जाता है, और निष्पादन रस्ट में लिखे कोड की संकलित बाइनरी फ़ाइल के माध्यम से होता है। इसका सीधा सा कारण यह है कि सीपीयू गणना जैसे कार्यों के लिए इस बाइनरी फ़ाइल को निष्पादित करना तेज़ होगा। परिणामस्वरूप, यह तेज़ हो गया, लेकिन इसमें एक बड़ी गलती है।
सबसे पहले, मैंने केवल पायथन कोड के साथ बेंचमार्क परीक्षण किए बिना ही माप किया था।
जैसा कि गो के जनक कहे जाने वाले रॉब पाइक ने 'सी प्रोग्रामिंग पर नोट्स' में लिखा है:

नियम 1: आप नहीं जान सकते कि आपका प्रोग्राम कहाँ समय खर्च करेगा। बॉटलनेक आश्चर्यजनक स्थानों पर होते हैं। इसलिए, जब तक आप यह स्पष्ट न कर लें कि बॉटलनेक कहाँ है, तब तक अनुमान न लगाएं या स्पीड हैक न करें।

यदि ऐसा है, तो माप किया जाना चाहिए। यदि निम्न-स्तरीय सी भाषा के सिद्धांत ऐसे हैं, तो यह असंभव है कि वे उच्च-स्तरीय परतों पर लागू न हों।

मैं कभी-कभी ऐसी बातें भूल जाता हूँ, इसलिए मुझे लगता है कि UNIX दर्शन जैसी चीज़ों की नियमित रूप से जाँच करना आत्म-अनुशासन के लिए आवश्यक है।

मैंने यह लिखा है, लेकिन एक इंसान होने के नाते, मैं जानता हूँ कि मैं अक्सर अपवादों को आकर्षित करता हूँ...

cProfile के साथ मापन

शुरुआत में, मैं import time से शुरू करके, start_time = time.time() और फ़ंक्शन के निष्पादन के अंत में end_time = time.time() के बाद print(f"exec time {start_time - end_time}") जैसे आदिम तरीकों का उपयोग कर रहा था, लेकिन यह कितना अक्षम है जब हम कंप्यूटर का उपयोग कर रहे हैं! इसलिए, मैंने कुछ ऐसा खोजने की कोशिश की जो प्रत्येक फ़ंक्शन के लिए निष्पादन समय प्रदर्शित कर सके।
ऐसा लगता है कि एक मानक लाइब्रेरी cProfile है। निम्नलिखित साइट समझने में आसान है:
Python cProfile के साथ कोड प्रदर्शन का विश्लेषण करें

मेरे मामले में, मैंने इसे इस प्रकार सत्यापित किया:

python3 -m cProfile -o profile.pstats ./main.py https://soulminingrig.com/ site

इसके द्वारा, ./main.py द्वारा निष्पादित फ़ंक्शन का निष्पादन समय profile.pstats नामक बाइनरी फ़ाइल में संग्रहीत किया जाता है।

फ़ंक्शन निष्पादन परिणामों की जाँच करें

पिछली साइट पर, इसे पायथन निष्पादन योग्य फ़ाइल का उपयोग करके किया गया था, लेकिन मैं इसे अधिक आसानी से pstats के कमांड-लाइन मोड में प्रवेश करके जाँचूँगा।

python3 -m pstats profile.pstats

यह pstats के कमांड-लाइन मोड में प्रवेश करेगा, और आप नीचे दिए गए आउटपुट परिणामों की जाँच कर सकते हैं।

profile.pstats% stats 5
Thu Nov  7 20:24:10 2024    profile.pstats

         48488696 function calls (47625490 primitive calls) in 51.151 seconds

   Random listing order was used
   List reduced from 3017 to 5 due to restriction <5>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1586    0.001    0.000    0.001    0.000 /home/haturatu/.local/lib/python3.12/site-packages/aiohttp/client_reqrep.py:909(__del__)
       80    0.000    0.000    0.001    0.000 /usr/lib/python3.12/copy.py:247(_reconstruct)
        4    0.000    0.000    0.005    0.001 /usr/lib/python3.12/encodings/__init__.py:71(search_function)
        3    0.000    0.000   98.745   32.915 /usr/lib/python3.12/asyncio/base_events.py:651(run_until_complete)
     1103    0.001    0.000    0.003    0.000 /usr/lib/python3.12/re/_parser.py:312(_class_escape)

आप help के साथ अन्य कमांड की जाँच कर सकते हैं।

profile.pstats% help

Documented commands (type help <topic>):
========================================
EOF  add  callees  callers  help  quit  read  reverse  sort  stats  strip

मेरे मामले में, मैंने stats 100 के रूप में आउटपुट किया, इसे एक अलग खुले टर्मिनल से vim में बेतरतीब ढंग से खोला, कॉपी-पेस्ट किया और quit किया।
इस vim में पेस्ट की गई और सहेजी गई टेक्स्ट फ़ाइल के लिए, मैं awk और sort का उपयोग करके प्रत्येक को देखूँगा।

tottime के मामले में

$ awk '{ print $2","$6 }' bench | sort | column -t -s "," | tail 
0.009    /usr/lib/python3.12/re/_compiler.py:243(_optimize_charset)
0.010    /usr/lib/python3.12/concurrent/futures/_base.py:428(result)
0.012    /usr/lib/python3.12/asyncio/base_events.py:627(run_forever)
0.013    /usr/lib/python3.12/re/__init__.py:280(_compile)
0.018    /usr/lib/python3.12/re/_compiler.py:37(_compile)
0.022    /usr/lib/python3.12/concurrent/futures/_base.py:497(set_running_or_notify_cancel)
0.030    /home/haturatu/git/devgit/async_web_mirror.py:186(download_and_save_image)
0.031    /usr/lib/python3.12/re/_parser.py:512(_parse)
0.061    /usr/lib/python3.12/concurrent/futures/_base.py:537(set_result)
tottime  filename:lineno(function)

किसी तरह, ऐसा लगता है कि tottime के साथ प्रत्येक फ़ंक्शन के लिए बेंचमार्क जैसी जानकारी फिलहाल पर्याप्त है।

क्या ब्यूटीफुल सूप4 का बॉटलनेक सिर्फ एक एहसास है?

अन्य वातावरणों से, ऐसा लग रहा था कि bs4 से कॉल किया गया element.py में search_tag धीमा कर रहा था।
मुझे यहाँ दिलचस्पी थी:

        if ((not self.name)
            or call_function_with_tag_data
            or (markup and self._matches(markup, self.name))
            or (not markup and self._matches(markup_name, self.name))):

यह विश्वास करना मुश्किल है कि or ऑपरेशन एक बॉटलनेक है...
हालांकि, इस element.py में केवल 7 स्थान हैं जहाँ or का मूल्यांकन किया जाता है, और उनमें से 3 का उपयोग यहाँ किया जा रहा है।
यह जगह थोड़ी संदिग्ध लगती है।


तो, चूंकि विषय bs4 के बारे में हो गया है, यहीं तक।
फिर मिलेंगे।

Related Posts