क्या पायथन स्क्रिप्ट को बेंचमार्क करने का कोई सरल तरीका है?


82

आमतौर पर मैं शेल कमांड का उपयोग करता हूं time। मेरा उद्देश्य परीक्षण करना है कि क्या डेटा छोटा, मध्यम, बड़ा या बहुत बड़ा सेट है, कितना समय और स्मृति उपयोग होगा।

ऐसा करने के लिए लिनक्स या सिर्फ अजगर के लिए कोई उपकरण?

जवाबों:


120

पर एक नज़र डालें timeit , अजगर प्रोफाइलर और pycallgraph । " स्नेपविज़ " का उल्लेख करके नीचे टिप्पणीnikicc पर एक नज़र अवश्य डालें । यह आपको प्रोफाइलिंग डेटा का एक और दृश्य देता है जो मददगार हो सकता है।

समय

def test():
    """Stupid test function"""
    lst = []
    for i in range(100):
        lst.append(i)

if __name__ == '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test"))

    # For Python>=3.5 one can also write:
    print(timeit.timeit("test()", globals=locals()))

अनिवार्य रूप से, आप इसे एक स्ट्रिंग पैरामीटर के रूप में अजगर कोड पास कर सकते हैं, और यह निर्दिष्ट समय में चलेगा और निष्पादन समय प्रिंट करेगा। डॉक्स से महत्वपूर्ण बिट्स :

timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)Timerदिए गए कथन, सेटअप कोड और टाइमर फ़ंक्शन के साथ एक उदाहरण बनाएं और संख्या निष्पादन के timeitसाथ इसकी विधि चलाएं । वैकल्पिक ग्लोबल्स तर्क एक नेमस्पेस निर्दिष्ट करता है जिसमें कोड निष्पादित करना है।

... तथा:

Timer.timeit(number=1000000)मुख्य बयान के समय संख्या निष्पादित। यह एक बार सेटअप स्टेटमेंट को निष्पादित करता है, और फिर मुख्य स्टेटमेंट को कई बार निष्पादित करने में लगने वाला समय लौटाता है, एक फ्लोट के रूप में सेकंड में मापा जाता है। तर्क लूप के माध्यम से कई बार होता है, एक मिलियन तक डिफ़ॉल्ट होता है। मुख्य कथन, सेटअप स्टेटमेंट और उपयोग किए जाने वाले टाइमर फ़ंक्शन को कंस्ट्रक्टर को पास किया जाता है।

नोट: डिफ़ॉल्ट रूप से, समय के दौरान timeitअस्थायी रूप से बंद हो जाता है garbage collection। इस दृष्टिकोण का लाभ यह है कि यह स्वतंत्र समय को अधिक तुलनीय बनाता है। यह नुकसान यह है कि जीसी मापा जा रहा फ़ंक्शन के प्रदर्शन का एक महत्वपूर्ण घटक हो सकता है। यदि हां, तो जीसी को सेटअप स्ट्रिंग में पहले स्टेटमेंट के रूप में फिर से सक्षम किया जा सकता है । उदाहरण के लिए:

timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()

रूपरेखा

रूपरेखा आप एक दे देंगे ज्यादा क्या हो रहा है के बारे में विस्तृत विचार। यहां आधिकारिक डॉक्स से "त्वरित उदाहरण" दिया गया है :

import cProfile
import re
cProfile.run('re.compile("foo|bar")')

जो आपको देगा:

      197 function calls (192 primitive calls) in 0.002 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1    0.000    0.000    0.001    0.001 re.py:212(compile)
     1    0.000    0.000    0.001    0.001 re.py:268(_compile)
     1    0.000    0.000    0.000    0.000 sre_compile.py:172(_compile_charset)
     1    0.000    0.000    0.000    0.000 sre_compile.py:201(_optimize_charset)
     4    0.000    0.000    0.000    0.000 sre_compile.py:25(_identityfunction)
   3/1    0.000    0.000    0.000    0.000 sre_compile.py:33(_compile)

इन दोनों मॉड्यूल से आपको अंदाजा हो सकता है कि आपको अड़चनों की तलाश कहाँ करनी है।

इसके अलावा, के उत्पादन के साथ पकड़ पाने के लिए profile, इस पोस्ट पर एक नज़र है

Pycallgraph

नोट pycallgraph को फरवरी 2018 से आधिकारिक तौर पर छोड़ दिया गया है । दिसंबर 2020 तक यह अजगर 3.6 पर काम कर रहा था। जब तक कि कैसे पायथन प्रोफाइल को उजागर करता है, तब तक इसमें कोई कोर बदलाव नहीं होते हैं, हालांकि इसे एक उपयोगी उपकरण बना रहना चाहिए।

यह मॉड्यूल निम्न की तरह कॉलगर्ल बनाने के लिए ग्राफविज़ का उपयोग करता है:

कॉलग्राफ उदाहरण

आप आसानी से देख सकते हैं कि किन रास्तों का इस्तेमाल सबसे ज्यादा बार किया गया है। आप या तो उन्हें pycallgraph API का उपयोग करके बना सकते हैं, या पैक स्क्रिप्ट का उपयोग कर सकते हैं:

pycallgraph graphviz -- ./mypythonscript.py

ओवरहेड हालांकि काफी विचारणीय है। तो पहले से ही लंबे समय से चल रही प्रक्रियाओं के लिए, ग्राफ बनाने में कुछ समय लग सकता है।


10
यदि cProfile का उपयोग किया जाता है तो पूरी स्क्रिप्ट को प्रोफाइल करने और फ़ाइल के साथ परिणाम सहेजने का भी विकल्प होता है python -m cProfile -o results.prof myscript.py। Oputput फ़ाइल को बहुत अच्छी तरह से एक ब्राउज़र में स्नेविज़ नामक प्रोग्राम द्वारा प्रस्तुत किया जा सकता हैsnakeviz results.prof
nikicc

pycallgraph की आखिरी रिलीज़ 2013 में हुई थी और इसे 2018 से
बोरिस

@ बोरिस यह जानना अच्छा है। मैंने वास्तव में कल इसका उपयोग किया है और - कम से कम अभी के लिए - यह अभी भी काम करता है। मैं पोस्ट अपडेट कर दूंगा। आप जानकारी के लिए Thatnk।
२१

28

मैं समय-समय पर एक साधारण डेकोरेटर का उपयोग करता हूं

def st_time(func):
    """
        st decorator to calculate the total time of a func
    """

    def st_func(*args, **keyArgs):
        t1 = time.time()
        r = func(*args, **keyArgs)
        t2 = time.time()
        print "Function=%s, Time=%s" % (func.__name__, t2 - t1)
        return r

    return st_func

यह निश्चित रूप से "फंक्शन =% s, टाइम =% s"% (func .__ name__, t2 - t1) है।
थैंक्स

17

timeitमॉड्यूल, धीमी और अजीब था तो मैं यह लिखा:

def timereps(reps, func):
    from time import time
    start = time()
    for i in range(0, reps):
        func()
    end = time()
    return (end - start) / reps

उदाहरण:

import os
listdir_time = timereps(10000, lambda: os.listdir('/'))
print "python can do %d os.listdir('/') per second" % (1 / listdir_time)

मेरे लिए, यह कहता है:

python can do 40925 os.listdir('/') per second

यह एक आदिम प्रकार का बेंचमार्किंग है, लेकिन यह काफी अच्छा है।


7
@exhuma, मैं विवरण भूल गया और शायद मेरे आकलन में जल्दबाजी थी! मुझे लगता है कि मैंने "अजीब" कहा क्योंकि यह कोड के दो भाग को तार के रूप में लेता है (फ़ंक्शन / लैम्ब्डा के बजाय)। लेकिन मैं उस मूल्य को देख सकता हूं जब कोड के बहुत ही कम चलने वाले सेगमेंट। मुझे लगता है कि मैंने कहा "धीमी" क्योंकि यह 1,000,000 छोरों को चूकता है और मैंने इसे समायोजित करने के तरीके को नहीं देखा! मुझे लगता है कि मेरा कोड पहले से ही प्रतिनिधि की संख्या से विभाजित है। लेकिन timeit कोई संदेह नहीं है एक बेहतर समाधान है, मैं इसे अस्वीकार करने के लिए माफी चाहता हूं।
सैम वाटकिंस

11

मैं आमतौर पर यह time ./script.pyदेखने के लिए एक त्वरित करता हूं कि इसमें कितना समय लगता है। यह आपको स्मृति नहीं दिखाता है, लेकिन कम से कम डिफ़ॉल्ट के रूप में नहीं। आप /usr/bin/time -v ./script.pyस्मृति उपयोग सहित बहुत सी जानकारी प्राप्त करने के लिए उपयोग कर सकते हैं ।


1
बस याद रखें, विकल्प के /usr/bin/timeसाथ यह कमांड -vकई डिस्ट्रो में डिफ़ॉल्ट रूप में उपलब्ध नहीं है, स्थापित किया जाना है। sudo apt-get install timeमें डेबियन, ubuntu, आदि pacman -S timeअभिलेखागार
रुई

6

आपकी सभी मेमोरी जरूरतों के लिए मेमोरी प्रोफाइलर।

https://pypi.python.org/pypi/memory_profiler

एक पाइप स्थापित करें:

pip install memory_profiler

पुस्तकालय आयात करें:

import memory_profiler

उस आइटम में एक डेकोरेटर जोड़ें जिसे आप प्रोफाइल करना चाहते हैं:

@profile
def my_func():
    a = [1] * (10 ** 6)
    b = [2] * (2 * 10 ** 7)
    del b
    return a

if __name__ == '__main__':
    my_func()

कोड निष्पादित करें:

python -m memory_profiler example.py

आउटपुट प्राप्त करें:

 Line #    Mem usage  Increment   Line Contents
 ==============================================
 3                           @profile
 4      5.97 MB    0.00 MB   def my_func():
 5     13.61 MB    7.64 MB       a = [1] * (10 ** 6)
 6    166.20 MB  152.59 MB       b = [2] * (2 * 10 ** 7)
 7     13.61 MB -152.59 MB       del b
 8     13.61 MB    0.00 MB       return a

उदाहरण डॉक्स से हैं, जो ऊपर दिए गए हैं।


3

पर एक नज़र डालें नाक और उसके प्लगइन्स से एक है, पर यह एक विशेष रूप से।

एक बार स्थापित होने के बाद, नाक आपके रास्ते में एक स्क्रिप्ट है, और आप एक निर्देशिका में कॉल कर सकते हैं जिसमें कुछ अजगर स्क्रिप्ट हैं:

$: nosetests

यह वर्तमान निर्देशिका में सभी अजगर फाइलों में दिखेगा और किसी भी फ़ंक्शन को निष्पादित करेगा जो इसे एक परीक्षण के रूप में पहचानता है: उदाहरण के लिए, यह परीक्षण के रूप में इसके नाम में test_ शब्द के साथ किसी भी फ़ंक्शन को पहचानता है।

तो आप बस एक अजगर स्क्रिप्ट बना सकते हैं, जिसे test_yourfunction.py कहा जाता है और उसमें कुछ इस तरह लिखा जाता है:

$: cat > test_yourfunction.py

def test_smallinput():
    yourfunction(smallinput)

def test_mediuminput():
    yourfunction(mediuminput)

def test_largeinput():
    yourfunction(largeinput)

फिर दौड़ना पड़ेगा

$: nosetest --with-profile --profile-stats-file yourstatsprofile.prof testyourfunction.py

और प्रोफ़ाइल फ़ाइल पढ़ने के लिए, इस अजगर लाइन का उपयोग करें:

python -c "import hotshot.stats ; stats = hotshot.stats.load('yourstatsprofile.prof') ; stats.sort_stats('time', 'calls') ; stats.print_stats(200)"

मुझे लगता है कि यह मानक अजगर पुस्तकालय से प्रोफाइलर के समान है। परीक्षण प्रश्न का विषय नहीं था। प्लस: noseहॉटशॉट पर निर्भर करता है। यह अब पायथन 2.5 के बाद से बनाए नहीं रखा गया है और केवल "विशेष उपयोग के लिए" रखा गया है
पूर्वव्यापी

2

केयरफुल होना timeitबहुत धीमा है, यह मेरे मध्यम प्रोसेसर पर 12 सेकंड लेता है बस आरंभ करने के लिए (या शायद फ़ंक्शन चलाएं)। आप इस स्वीकार किए गए उत्तर का परीक्षण कर सकते हैं

def test():
    lst = []
    for i in range(100):
        lst.append(i)

if __name__ == '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test")) # 12 second

साधारण बात के लिए मैं timeइसके बजाय अपने पीसी पर उपयोग करूंगा , यह परिणाम लौटाता है0.0

import time

def test():
    lst = []
    for i in range(100):
        lst.append(i)

t1 = time.time()

test()

result = time.time() - t1
print(result) # 0.000000xxxx

1
timeitशोर को औसत करने के लिए, अपने कार्य को कई बार चलाता है । दोहराए जाने की संख्या एक विकल्प है, इस प्रश्न पर स्वीकृत जवाब में बेंचमार्क को बाद के समय या बाद के भाग में देखें।
पीटर कॉर्ड्स

1

किसी भी फ़ंक्शन का त्वरित रूप से परीक्षण करने का आसान तरीका इस सिंटैक्स का उपयोग करना है: %timeit my_code

उदाहरण के लिए :

%timeit a = 1

13.4 ns ± 0.781 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

1

snakeviz cProfile के लिए इंटरैक्टिव दर्शक

https://github.com/jiffyclub/snakeviz/

cProfile का उल्लेख https://stackoverflow.com/a/1593034/895245 पर किया गया था और स्नेकविज़ का उल्लेख एक टिप्पणी में किया गया था , लेकिन मैं इसे और उजागर करना चाहता था।

यह केवल cprofile/ pstatsआउटपुट को देखकर प्रोग्राम के प्रदर्शन को डीबग करना बहुत कठिन है , क्योंकि वे केवल बॉक्स से बाहर प्रति फ़ंक्शन कुल समय हो सकते हैं।

हालाँकि, हमें वास्तव में सामान्य रूप से एक नेस्टेड दृश्य को देखना पड़ता है जिसमें प्रत्येक कॉल के स्टैक के निशान होते हैं जो वास्तव में मुख्य बाधाओं को आसानी से ढूंढ सकते हैं।

और यह वही है जो स्नेकविज़ अपने डिफ़ॉल्ट "आइकिकल" दृश्य के माध्यम से प्रदान करता है।

पहले आपको cProfile डेटा को एक बाइनरी फ़ाइल में डंप करना होगा, और फिर आप उस पर स्नेकविज़ कर सकते हैं

pip install -u snakeviz
python -m cProfile -o results.prof myscript.py
snakeviz results.prof

यह एक URL प्रिंट करने के लिए प्रिंट करता है जिसे आप अपने ब्राउज़र पर खोल सकते हैं, जिसमें वांछित आउटपुट होता है जो इस तरह दिखता है:

यहाँ छवि विवरण दर्ज करें

और आप तब कर सकते हैं:

  • फ़ंक्शन वाले फ़ाइल का पूरा पथ देखने के लिए प्रत्येक बॉक्स को होवर करें
  • ज़ूम इन करने के लिए उस बॉक्स को शीर्ष पर दिखाने के लिए एक बॉक्स पर क्लिक करें

अधिक प्रोफ़ाइल उन्मुख प्रश्न: आप एक पायथन स्क्रिप्ट कैसे प्रोफाइल कर सकते हैं?


-1

यदि आप समय के लिए बॉयलरप्लेट कोड नहीं लिखना चाहते हैं और परिणामों का विश्लेषण करना आसान है, तो बेंचमार्क पर एक नज़र डालें । साथ ही यह पिछले रनों के इतिहास को बचाता है, इसलिए विकास के दौरान समान फ़ंक्शन की तुलना करना आसान है।

# pip install benchmarkit

from benchmarkit import benchmark, benchmark_run

N = 10000
seq_list = list(range(N))
seq_set = set(range(N))

SAVE_PATH = '/tmp/benchmark_time.jsonl'

@benchmark(num_iters=100, save_params=True)
def search_in_list(num_items=N):
    return num_items - 1 in seq_list

@benchmark(num_iters=100, save_params=True)
def search_in_set(num_items=N):
    return num_items - 1 in seq_set

benchmark_results = benchmark_run(
   [search_in_list, search_in_set],
   SAVE_PATH,
   comment='initial benchmark search',
)  

टर्मिनल के लिए प्रिंट और अंतिम रन के लिए डेटा के साथ शब्दकोशों की सूची देता है। कमांड लाइन प्रविष्टि भी उपलब्ध है।

यहाँ छवि विवरण दर्ज करें

यदि आप बदलते हैं N=1000000और फिर से दौड़ते हैं

यहाँ छवि विवरण दर्ज करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.