2013-05-19 6 views
14

आप निम्नलिखित समय को देखें, तो:पूर्णांक .__ mul__, कार्यान्वित 2X की तुलना में धीमी operator.mul

C:\Users\Henry>python -m timeit -s "mul = int.__mul__" "reduce(mul,range(10000))" 
1000 loops, best of 3: 908 usec per loop 

C:\Users\Henry>python -m timeit -s "from operator import mul" "reduce(mul,range(10000))" 
1000 loops, best of 3: 410 usec per loop 

वहाँ

reduce(int.__mul__,range(10000)) और बाद में तेजी से होने के साथ reduce(mul,range(10000)) के बीच निष्पादन की गति में एक महत्वपूर्ण अंतर है ।

क्या हो रहा था को देखने के लिए dis मॉड्यूल का उपयोग कर:

int.__mul__ पद्धति का उपयोग करना:

C:\Users\Henry>python 
Python 2.7.4 (default, Apr 6 2013, 19:55:15) [MSC v.1500 64 bit (AMD64)] on win32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> mul = int.__mul__ 
>>> def test(): 
...  mul(1,2) 
... 
>>> import dis 
>>> dis.dis(test) 
    2   0 LOAD_GLOBAL    0 (mul) 
       3 LOAD_CONST    1 (1) 
       6 LOAD_CONST    2 (2) 
       9 CALL_FUNCTION   2 
      12 POP_TOP 
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE 
>>> 

और ऑपरेटर mul विधि

C:\Users\Henry>python 
Python 2.7.4 (default, Apr 6 2013, 19:55:15) [MSC v.1500 64 bit (AMD64)] on win32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> from operator import mul 
>>> def test(): 
...  mul(1,2) 
... 
>>> import dis 
>>> dis.dis(test) 
    2   0 LOAD_GLOBAL    0 (mul) 
       3 LOAD_CONST    1 (1) 
       6 LOAD_CONST    2 (2) 
       9 CALL_FUNCTION   2 
      12 POP_TOP 
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE 
>>> 

वे एक ही दिखाई देते हैं, तो क्यों है निष्पादन गति में एक अंतर है? मैं अजगर


python3 पर एक ही होता है की CPython कार्यान्वयन की चर्चा करते हुए हूँ:

$ python3 -m timeit -s 'mul=int.__mul__;from functools import reduce' 'reduce(mul, range(10000))' 
1000 loops, best of 3: 1.18 msec per loop 
$ python3 -m timeit -s 'from operator import mul;from functools import reduce' 'reduce(mul, range(10000))' 
1000 loops, best of 3: 643 usec per loop 
$ python3 -m timeit -s 'mul=lambda x,y:x*y;from functools import reduce' 'reduce(mul, range(10000))' 
1000 loops, best of 3: 1.26 msec per loop 
+5

आप 'टेस्ट()' के बाइटकोड डिस्सेप्लर देख रहे हैं और यह सिर्फ 'mul' कहता है, इसलिए यह दोनों मामलों में समान है। यह 'मुल' के दो कार्यान्वयन है जो शायद अलग हैं। –

+0

@HristoIliev धन्यवाद, मैंने नहीं किया कि यह केवल परीक्षण को अलग कर रहा था। मुझे लगता है कि बहुत अधिक समझ में आता है। मैं देख रहा हूं कि इन्हें कुछ और कैसे लागू किया गया था। – HennyH

+0

क्या आप अजगर दो का उपयोग कर रहे हैं? समस्या यह हो सकती है कि इंटेल की मां बहती रहेगी और लंबे समय तक चलने वाली कॉल को कॉल करेगी जबकि ऑपरेटर इस अतिरिक्त कॉल से बच जाएगा। – Bakuriu

उत्तर

14

int.__mul__, एक स्लॉट आवरण, अर्थात्, एक PyWrapperDescrObject है, जबकि operator.mul एक buit में कार्य है। मुझे लगता है कि विपरीत निष्पादन गति इस अंतर के कारण होती है।

>>> int.__mul__ 
<slot wrapper '__mul__' of 'int' objects> 
>>> operator.mul 
<built-in function mul> 

जब हम एक PyWrapperDescrObject फोन, wrapperdescr_call कहा जाता है।


static PyObject * 
wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) 
{ 
    Py_ssize_t argc; 
    PyObject *self, *func, *result; 

    /* Make sure that the first argument is acceptable as 'self' */ 
    assert(PyTuple_Check(args)); 
    argc = PyTuple_GET_SIZE(args); 
    if (argc d_type->tp_name); 
     return NULL; 
    } 
    self = PyTuple_GET_ITEM(args, 0); 
    if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), 
            (PyObject *)(descr->d_type))) { 
     PyErr_Format(PyExc_TypeError, 
        "descriptor '%.200s' " 
        "requires a '%.100s' object " 
        "but received a '%.100s'", 
        descr_name((PyDescrObject *)descr), 
        descr->d_type->tp_name, 
        self->ob_type->tp_name); 
     return NULL; 
    } 

    func = PyWrapper_New((PyObject *)descr, self); 
    if (func == NULL) 
     return NULL; 
    args = PyTuple_GetSlice(args, 1, argc); 
    if (args == NULL) { 
     Py_DECREF(func); 
     return NULL; 
    } 
    result = PyEval_CallObjectWithKeywords(func, args, kwds); 
    Py_DECREF(args); 
    Py_DECREF(func); 
    return result; 
} 

हमें जो देखते हैं उसे देखते हैं!

func = PyWrapper_New((PyObject *)descr, self); 

एक नया PyWrapper ऑब्जेक्ट का निर्माण किया गया है। यह निष्पादन गति को काफी धीमा कर देगा। कभी-कभी, एक साधारण कार्य चलाने के लिए एक नई वस्तु बनाने में अधिक समय लगता है।
इस प्रकार, यह हैरान नहीं है कि int.__mul__operator.mul से धीमा है।

संबंधित मुद्दे