समयसीमा मॉड्यूल का उपयोग कैसे करें


351

मैं क्या timeitकरता है की अवधारणा को समझता हूं लेकिन मुझे यकीन नहीं है कि इसे अपने कोड में कैसे लागू किया जाए।

मैं दो कार्यों की तुलना कैसे कह सकता हूं, insertion_sortऔर tim_sort, के साथ timeit?

जवाबों:


266

जिस तरह से टाइमटाइम काम करता है वह एक बार सेटअप कोड चलाने और फिर कई बार बयानों की श्रृंखला में कॉल करने का होता है। इसलिए, यदि आप छंटाई का परीक्षण करना चाहते हैं, तो कुछ देखभाल की आवश्यकता होती है, ताकि इन-प्लेस सॉर्ट पर एक पास पहले से ही सॉर्ट किए गए डेटा के साथ पास को प्रभावित न करे (जो निश्चित रूप से, Timsort वास्तव में चमक देगा क्योंकि यह सबसे अच्छा प्रदर्शन करता है जब डेटा पहले से ही आंशिक रूप से ऑर्डर किया गया हो)।

यहाँ एक उदाहरण दिया गया है कि छंटाई के लिए परीक्षण कैसे सेट करें:

>>> import timeit

>>> setup = '''
import random

random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''

>>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000))
0.334147930145

ध्यान दें कि कथनों की श्रृंखला हर पास पर अनसोल्ड डेटा की एक नई प्रतिलिपि बनाती है।

इसके अलावा, माप सूट को सात बार चलाने और केवल सबसे अच्छा समय रखने की समय तकनीक पर ध्यान दें - यह वास्तव में आपके सिस्टम पर चल रही अन्य प्रक्रियाओं के कारण माप विकृतियों को कम करने में मदद कर सकता है।

वे सही समय का उपयोग करने के लिए मेरी युक्तियां हैं। उम्मीद है की यह मदद करेगा :-)


8
हां, इसमें लिस्ट कॉपी भी शामिल है (जो कि सॉर्ट की तुलना में बहुत तेज है)। यदि आप हालांकि कॉपी नहीं करते हैं, तो पहले पास सूची को छाँट लेता है और शेष पारित किसी भी काम को करने के लिए नहीं होता है। यदि आप केवल समय के लिए समय जानना चाहते हैं, तो ऊपर और बिना चलाएं timsort(a)और अंतर लें :-)
रेमंड हेटिंगर

मैं प्रत्येक सेटअप के लिए 7 बार दोहराने की सलाह दूंगा, और फिर औसत; बल्कि दूसरे रास्ते से। इस तरह, यदि अन्य प्रक्रियाओं के कारण प्रत्येक स्पाइक को औसतन बाहर की बजाय पूरी तरह से अनदेखा किए जाने का अच्छा मौका है।
अधिकतम

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

4
आप 1000 इनपुट के लिए एक औसत (अच्छी तरह से, कुल, लेकिन यह बराबर है) की गणना करते हैं; फिर 7 बार दोहराएं, और न्यूनतम लें । आपको 1000 से अधिक इनपुट की औसत की आवश्यकता है क्योंकि आप औसत (सबसे अच्छा नहीं) एल्गोरिथ्म जटिलता चाहते हैं। आपके द्वारा दिए गए कारण के लिए आपको न्यूनतम आवश्यकता है। मुझे लगा कि मैं एक इनपुट चुनकर, एल्गोरिथ्म को 7 बार चलाकर, न्यूनतम लेकर आपका दृष्टिकोण सुधार सकता हूं; फिर इसे 1000 अलग-अलग इनपुट्स के लिए दोहराते हुए, और औसत ले रहे हैं। मुझे नहीं पता था कि आपके .repeat(7,1000)पहले से ही (एक ही बीज का उपयोग करके) ऐसा करता है! तो आपका समाधान सही IMO है।
अधिकतम

5
मैं केवल यह जोड़ सकता हूं कि आप 7000 निष्पादन के अपने बजट को कैसे आवंटित करते हैं (उदाहरण के लिए, .repeat(7, 1000)बनाम .repeat(2, 3500)बनाम .repeat(35, 200) इस बात पर निर्भर करना चाहिए कि इनपुट परिवर्तनशीलता के कारण सिस्टम लोड के कारण त्रुटि की तुलना कैसे होती है। चरम स्थिति में यदि आपका सिस्टम हमेशा भारी लोड के अधीन है, और आपको निष्पादन समय वितरण के बाईं ओर एक लंबी पतली पूंछ दिखाई देती है (जब आप इसे एक दुर्लभ निष्क्रिय अवस्था में पकड़ते हैं), तो आप इससे भी .repeat(7000,1)अधिक उपयोगी हो सकते हैं .repeat(7,1000)यदि आप 7000 से अधिक रन बजट नहीं कर सकते।
अधिकतम

277

यदि आप timeitएक इंटरैक्टिव पायथन सत्र में उपयोग करना चाहते हैं, तो दो सुविधाजनक विकल्प हैं:

  1. IPython शेल का उपयोग करें । यह सुविधाजनक %timeitविशेष समारोह पेश करता है:

    In [1]: def f(x):
       ...:     return x*x
       ...: 
    
    In [2]: %timeit for x in range(100): f(x)
    100000 loops, best of 3: 20.3 us per loop
  2. मानक पायथन दुभाषिया में, आप __main__सेटअप सत्र से आयात करके इंटरेक्टिव सत्र के दौरान पहले से परिभाषित कार्यों और अन्य नामों तक पहुँच सकते हैं :

    >>> def f(x):
    ...     return x * x 
    ... 
    >>> import timeit
    >>> timeit.repeat("for x in range(100): f(x)", "from __main__ import f",
                      number=100000)
    [2.0640320777893066, 2.0876040458679199, 2.0520210266113281]

97
from __main__ import fतकनीक दिखाने के लिए +1 । मुझे नहीं लगता कि यह उतना व्यापक रूप से जाना जाता है जितना इसे होना चाहिए। यह इस तरह के मामलों में उपयोगी है जहां एक फ़ंक्शन या विधि कॉल समयबद्ध हो रही है। अन्य मामलों में (चरणों की एक श्रृंखला का समय), यह कम सहायक है क्योंकि यह फ़ंक्शन कॉल ओवरहेड का परिचय देता है।
रेमंड हेटिंगर

15
आप बस कर सकते हैं%timeit f(x)
qed

नोट: "आयात f" सेटअप तेजी से स्थानीय रीड तक पहुंच बनाता है - जो सामान्य सामान्य कोड में एक वैश्विक फ़ंक्शन कॉल (शॉर्ट फास्ट फ़ंक्शन का) को बिल्कुल प्रतिबिंबित नहीं करता है। Py3.5 में + असली ग्लोबल्स की आपूर्ति की जा सकती है: "संस्करण 3.5 में बदला: वैकल्पिक ग्लोबल्स पैरामीटर जोड़ा गया था;" टाइमटाइम मॉड्यूल के ग्लोबल्स से पहले जहां अपरिहार्य (जो बहुत अर्थ नहीं देता है)। संभवतः कॉलिंग कोड ( sys._getframe(N).f_globals) का ग्लोबल्स शुरुआत से ही डिफ़ॉल्ट होना चाहिए था।
kxr

140

मैं आपको एक रहस्य पर जाने दूँगा: उपयोग करने का सबसे अच्छा तरीका timeitकमांड लाइन पर है।

कमांड लाइन पर, timeitउचित सांख्यिकीय विश्लेषण करता है: यह आपको बताता है कि सबसे कम समय कितना समय लगा। यह अच्छा है क्योंकि समय में सभी त्रुटि सकारात्मक है। इसलिए कम से कम समय में इसमें सबसे कम त्रुटि है। नकारात्मक त्रुटि प्राप्त करने का कोई तरीका नहीं है क्योंकि कंप्यूटर कभी भी तेजी से गणना नहीं कर सकता है क्योंकि यह गणना कर सकता है!

तो, कमांड लाइन इंटरफ़ेस:

%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop

यह काफी सरल है, एह?

आप सामान सेट कर सकते हैं:

%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop

जो उपयोगी है, भी!

यदि आप कई लाइनें चाहते हैं, तो आप शेल के स्वचालित निरंतरता का उपयोग कर सकते हैं या अलग-अलग तर्क का उपयोग कर सकते हैं:

%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop

का एक सेटअप देता है

x = range(1000)
y = range(100)

और बार

sum(x)
min(y)

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

 SETUP="

 ... # lots of stuff

 "

 echo Minmod arr1
 python -m timeit -s "$SETUP" "Minmod(arr1)"

 echo pure_minmod arr1
 python -m timeit -s "$SETUP" "pure_minmod(arr1)"

 echo better_minmod arr1
 python -m timeit -s "$SETUP" "better_minmod(arr1)"

 ... etc

यह कई प्रारंभिकताओं के कारण थोड़ा अधिक समय ले सकता है, लेकिन आम तौर पर यह कोई बड़ी बात नहीं है।


लेकिन क्या होगा अगर आप अपने मॉड्यूल के अंदर का उपयोग करना चाहते हैंtimeit ?

वैसे, सरल तरीका यह है:

def function(...):
    ...

timeit.Timer(function).timeit(number=NUMBER)

और वह आपको कम से कम ( कम से कम नहीं !) समय देता है जो उस संख्या को चलाता है।

एक अच्छा विश्लेषण प्राप्त करने के लिए, उपयोग करें .repeatऔर न्यूनतम लें:

min(timeit.Timer(function).repeat(repeat=REPEATS, number=NUMBER))

आपको सामान्य रूप से निचले ओवरहेड के functools.partialबजाय इसके साथ गठबंधन करना चाहिए lambda: ...। इस प्रकार आपके पास कुछ ऐसा हो सकता है:

from functools import partial

def to_time(items):
    ...

test_items = [1, 2, 3] * 100
times = timeit.Timer(partial(to_time, test_items)).repeat(3, 1000)

# Divide by the number of repeats
time_taken = min(times) / 1000

आप भी कर सकते हैं:

timeit.timeit("...", setup="from __main__ import ...", number=NUMBER)

जो आपको कमांड-लाइन से इंटरफ़ेस के करीब कुछ देगा , लेकिन बहुत कम शांत तरीके से। "from __main__ import ..."आप के द्वारा बनाई गई कृत्रिम वातावरण के अंदर अपने मुख्य मॉड्यूल से कोड का उपयोग करने देता timeit

यह ध्यान देने योग्य है कि यह एक सुविधा आवरण है Timer(...).timeit(...)और इसलिए यह समय पर विशेष रूप से अच्छा नहीं है। Timer(...).repeat(...)जैसा कि मैंने ऊपर दिखाया है मैं व्यक्तिगत रूप से उपयोग करना पसंद करता हूं।


चेतावनी

timeitहर जगह उस होल्ड के साथ कुछ कैविएट हैं ।

  • ओवरहेड का हिसाब नहीं है। कहो कि आप समय x += 1निकालना चाहते हैं , यह जानने के लिए कि कितना समय लगता है:

    >>> python -m timeit -s "x = 0" "x += 1"
    10000000 loops, best of 3: 0.0476 usec per loop

    खैर, यह 0.0476 47s नहीं है । आप केवल यह जानते हैं कि यह उससे कम है। सभी त्रुटि सकारात्मक है।

    तो कोशिश करो और शुद्ध उपरि खोजें:

    >>> python -m timeit -s "x = 0" ""      
    100000000 loops, best of 3: 0.014 usec per loop

    यह एक अच्छा 30% ओवरहेड सिर्फ समय से है! यह बड़े पैमाने पर सापेक्ष समय को कम कर सकता है। लेकिन आप केवल जोड़ने की टाइमिंग के बारे में वास्तव में परवाह करते थे ; xओवरहेड में शामिल करने के लिए लुक-अप टाइमिंग की भी आवश्यकता है:

    >>> python -m timeit -s "x = 0" "x"
    100000000 loops, best of 3: 0.0166 usec per loop

    अंतर बहुत बड़ा नहीं है, लेकिन यह वहां है।

  • म्यूट करने के तरीके खतरनाक हैं।

    >>> python -m timeit -s "x = [0]*100000" "while x: x.pop()"
    10000000 loops, best of 3: 0.0436 usec per loop

    लेकिन यह पूरी तरह से गलत है! xपहली पुनरावृत्ति के बाद खाली सूची है। आपको फिर से संगठित करने की आवश्यकता होगी:

    >>> python -m timeit "x = [0]*100000" "while x: x.pop()"
    100 loops, best of 3: 9.79 msec per loop

    लेकिन फिर आपके पास बहुत सारे ओवरहेड हैं। उसके लिए अलग से खाता।

    >>> python -m timeit "x = [0]*100000"                   
    1000 loops, best of 3: 261 usec per loop

    ध्यान दें कि ओवरहेड को घटाना यहां उचित है क्योंकि ओवरहेड उस समय का एक छोटा-ईश अंश है।

    आपके उदाहरण के लिए, यह ध्यान देने योग्य है कि प्रविष्टि सॉर्ट और टिम सॉर्ट दोनों पहले से ही सॉर्ट किए गए सूचियों के लिए पूरी तरह से असामान्य समय व्यवहार हैं। इसका मतलब है कि random.shuffleअगर आप अपनी टाइमिंग को खत्म करने से बचना चाहते हैं तो आपको एक तरह की आवश्यकता होगी ।


1
usec का क्या अर्थ है? क्या यह माइक्रोसेकंड है?
हसन इकबाल

2
@ हसनइकबालअनिक हां।
विड्रैक

@StefanPochmann क्योंकि यह कई बार नमूना लेने का प्रयास नहीं करता है।
विड्रैक


@Veedrac आपको शुद्ध समय-सार उप-सार को घटाने पर कथन को ध्यान में रखते हुए, जब कोई तर्क नहीं दिया जाता है, तो timeitएक passकथन निष्पादित करता है , जो निश्चित रूप से, कुछ समय लेता है। यदि कोई तर्क दिया जाता है, तो उसे क्रियान्वित नहीं कियाpass जाएगा , इसलिए हर समय से कुछ usecs घटाना गलत होगा। 0.014
अर्ने

99

यदि आप कोड / फ़ंक्शन के दो ब्लॉक की तुलना जल्दी करना चाहते हैं तो आप कर सकते हैं:

import timeit

start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)

43

मुझे कमांड लाइन से टाइमटाइम का उपयोग करने का सबसे आसान तरीका मिल गया है:

यह देखते हुए test.py :

def InsertionSort(): ...
def TimSort(): ...

इस तरह रन टाइमिट:

% python -mtimeit -s'import test' 'test.InsertionSort()'
% python -mtimeit -s'import test' 'test.TimSort()'


12
# Генерация целых чисел

def gen_prime(x):
    multiples = []
    results = []
    for i in range(2, x+1):
        if i not in multiples:
            results.append(i)
            for j in range(i*i, x+1, i):
                multiples.append(j)

    return results


import timeit

# Засекаем время

start_time = timeit.default_timer()
gen_prime(3000)
print(timeit.default_timer() - start_time)

# start_time = timeit.default_timer()
# gen_prime(1001)
# print(timeit.default_timer() - start_time)

7

यह महान काम करता है:

  python -m timeit -c "$(cat file_name.py)"

विंडोज के बराबर क्या होगा?
शैलेन

2
यदि आप किसी भी स्क्रिप्ट की आवश्यकता है, तो आप पैरामीटर कैसे पास करते हैं?
जुसो ओह्टनन

3

निम्न में से प्रत्येक में एक ही शब्दकोश को सेटअप करने देता है और निष्पादन समय का परीक्षण करता है।

सेटअप तर्क मूल रूप से शब्दकोश सेट कर रहा है

नंबर को 1000000 बार कोड चलाना है। सेटअप नहीं, लेकिन stmt

जब आप इसे चलाते हैं, तो आप देख सकते हैं कि सूचकांक प्राप्त करने की तुलना में तेज़ है। आप इसे कई बार देख सकते हैं।

कोड मूल रूप से कोश में c का मान प्राप्त करने का प्रयास करता है।

import timeit

print('Getting value of C by index:', timeit.timeit(stmt="mydict['c']", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
print('Getting value of C by get:', timeit.timeit(stmt="mydict.get('c')", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))

यहाँ मेरे परिणाम हैं, तुम्हारा अलग होगा।

सूचकांक द्वारा: 0.20900007452246427

द्वारा प्राप्त करें: 0.54841166886888


अजगर आप किस संस्करण का उपयोग कर रहे हैं?
एडुआर्डो

3

बस अपने पूरे कोड को समयसीमा के तर्क के रूप में पास करें:

import timeit

print(timeit.timeit(

"""   
limit = 10000
prime_list = [i for i in range(2, limit+1)]

for prime in prime_list:
    for elem in range(prime*2, max(prime_list)+1, prime):
        if elem in prime_list:
            prime_list.remove(elem)
"""   
, number=10))


0

बिल्ट-इन टाइमिट मॉड्यूल IPython कमांड लाइन से सबसे अच्छा काम करता है।

एक मॉड्यूल के भीतर समय से कार्य करने के लिए:

from timeit import default_timer as timer
import sys

def timefunc(func, *args, **kwargs):
    """Time a function. 

    args:
        iterations=3

    Usage example:
        timeit(myfunc, 1, b=2)
    """
    try:
        iterations = kwargs.pop('iterations')
    except KeyError:
        iterations = 3
    elapsed = sys.maxsize
    for _ in range(iterations):
        start = timer()
        result = func(*args, **kwargs)
        elapsed = min(timer() - start, elapsed)
    print(('Best of {} {}(): {:.9f}'.format(iterations, func.__name__, elapsed)))
    return result

0

मापदंडों को स्वीकार करने वाले फ़ंक्शन के साथ पायथन आरईपीएल दुभाषिया का उपयोग कैसे करें, इसका उदाहरण।

>>> import timeit                                                                                         

>>> def naive_func(x):                                                                                    
...     a = 0                                                                                             
...     for i in range(a):                                                                                
...         a += i                                                                                        
...     return a                                                                                          

>>> def wrapper(func, *args, **kwargs):                                                                   
...     def wrapper():                                                                                    
...         return func(*args, **kwargs)                                                                  
...     return wrapper                                                                                    

>>> wrapped = wrapper(naive_func, 1_000)                                                                  

>>> timeit.timeit(wrapped, number=1_000_000)                                                              
0.4458435332577161                                                                                        

0

आप दो फ़ंक्शन बनाएंगे और फिर इसके समान कुछ चलाएंगे। ध्यान दें, आप सेब से सेब की तुलना करने के लिए एक ही संख्या में निष्पादन / चलाने का चयन करना चाहते हैं।
यह पायथन 3.7 के तहत परीक्षण किया गया था।

यहां छवि विवरण दर्ज करें यहाँ इसे कॉपी करने में आसानी के लिए कोड है

!/usr/local/bin/python3
import timeit

def fibonacci(n):
    """
    Returns the n-th Fibonacci number.
    """
    if(n == 0):
        result = 0
    elif(n == 1):
        result = 1
    else:
        result = fibonacci(n-1) + fibonacci(n-2)
    return result

if __name__ == '__main__':
    import timeit
    t1 = timeit.Timer("fibonacci(13)", "from __main__ import fibonacci")
    print("fibonacci ran:",t1.timeit(number=1000), "milliseconds")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.