INT .__ mul__,执行2X比operator.mul慢 [英] int.__mul__ , executes 2X slower than operator.mul

查看:390
本文介绍了INT .__ mul__,执行2X比operator.mul慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果你看看下面的时序:

  C:\\用户\\亨利​​GT;蟒蛇-m timeit -sMUL = INT .__ mul__,减少(MUL,范围(10000))
1000循环,最好的3:每回路908微秒C:\\用户\\亨利​​GT;蟒蛇-m timeit -s,从运营商进口MUL,减少(MUL,范围(10000))
1000循环,最好的3:每回路410微秒

有是

之间在执行速度显著差

减少(INT .__ MUL __,范围(10000))减少(MUL,范围(10000))与后者快

使用 DIS 模块来看看

发生了什么:

使用 INT .__ MUL __ 方法:

  C:\\用户\\亨利​​GT;蟒蛇
Python的2.7.4(默认情况下,2013年4月6日,19时55分一十五秒)MSC v.1500 64位(AMD64)]在Win32
键入help,版权,信用或许可的详细信息。
>>> MUL = INT .__ mul__
>>> DEF试验(+):
... MUL(1,2)
...
>>>进口DIS
>>> dis.dis(测试)
  2 0 0 LOAD_GLOBAL(MUL)
              3 LOAD_CONST 1(1)
              6 LOAD_CONST 2(2)
              9 CALL_FUNCTION 2
             12 POP_TOP
             13 LOAD_CONST 0(无)
             16 RETURN_VALUE
>>>

和操作 MUL

  C:\\用户\\亨利​​GT;蟒蛇
Python的2.7.4(默认情况下,2013年4月6日,19时55分一十五秒)MSC v.1500 64位(AMD64)]在Win32
键入help,版权,信用或许可的详细信息。
>>>从运营商进口MUL
>>> DEF试验(+):
... MUL(1,2)
...
>>>进口DIS
>>> dis.dis(测试)
  2 0 0 LOAD_GLOBAL(MUL)
              3 LOAD_CONST 1(1)
              6 LOAD_CONST 2(2)
              9 CALL_FUNCTION 2
             12 POP_TOP
             13 LOAD_CONST 0(无)
             16 RETURN_VALUE
>>>

他们似乎是相同的,所以为什么会出现在执行速度有区别吗?我指的是CPython的Python实现


同样发生在python3:

  $ python3 -m timeit -s'MUL = INT .__ MUL __;从functools进口减少'降低(MUL,范围(10000))'
1000循环,最好的3:每循环1.18毫秒
$ python3 -m timeit -s从运营商进口MUL;从functools进口减少'降低(MUL,范围(10000))'
1000循环,最好的3:每回路643微秒
$ python3 -m timeit -s'MUL =拉姆达X,Y:X * Y;从functools进口减少'降低(MUL,范围(10000))'
1000循环,最好的3:每循环1.26毫秒


解决方案

<一个href=\"http://hg.python.org/cpython/file/026ee0057e2d/Objects/intobject.c#l1374\"><$c$c>int.__mul__是一个槽的包装,即,<一href=\"http://hg.python.org/cpython/file/026ee0057e2d/Objects/descrobject.c#l574\">PyWrapperDescrObject,而<一个href=\"http://hg.python.org/cpython/file/026ee0057e2d/Modules/operator.c#l91\"><$c$c>operator.mul是一个BUIT函数。
我认为相反的执行速度是由这种差异造成的。

 &GT;&GT;&GT; INT .__ mul__
&LT;槽包装'诠释'对象的制造&gt'__mul__';
&GT;&GT;&GT; operator.mul
&LT;内置功能MUL&GT;

当我们称之为<一个href=\"http://hg.python.org/cpython/file/026ee0057e2d/Objects/descrobject.c#l574\">PyWrapperDescrObject, <一href=\"http://hg.python.org/cpython/file/026ee0057e2d/Objects/descrobject.c#l306\"><$c$c>wrapperdescr_call被调用。

 
静态的PyObject *
wrapperdescr_call(PyWrapperDescrObject * DESCR,*的PyObject ARGS,*的PyObject kwds)
{
    Py_ssize_t ARGC;
    *的PyObject自我,* FUNC,*结果;    / *确保第一个参数是'自我'可以接受的* /
    断言(PyTuple_Check(参数));
    ARGC = PyTuple_GET_SIZE(参数);
    如果(ARGC d_type-> tp_name);
        返回NULL;
    }
    自= PyTuple_GET_ITEM(参数,0);
    如果(!_PyObject_RealIsSubclass((*的PyObject)Py_TYPE(个体经营)
                                  (的PyObject *)(descr-> d_type))){
        PyErr_Format(PyExc_TypeError,
                     描述%.200s'
                     要求%.100s对象
                     但收到了%.100s
                     descr_name((PyDescrObject *)DESCR)
                     descr-> d_type-> tp_name,
                     自> ob_type-> tp_name);
        返回NULL;
    }     FUNC = PyWrapper_New((的PyObject *)DESCR,自);
    如果(FUNC == NULL)
        返回NULL;
    ARGS = PyTuple_GetSlice(参数,1,ARGC);
    如果(参数== NULL){
        Py_DECREF(FUNC);
        返回NULL;
    }
    结果= PyEval_CallObjectWithKeywords(FUNC,ARGS,kwds);
    Py_DECREF(参数);
    Py_DECREF(FUNC);
    返回结果;
}

让我们来看看我们发现了什么!

  FUNC = PyWrapper_New((*的PyObject)DESCR,个体经营);

一个新的PyWrapper对象已经建成。它将显著减慢执行速度。
有时,它需要更多的时间来创建新的对象,而不是运行一个简单函数。

因此,并不感到惊讶, INT .__ MUL __ operator.mul 慢。

If you look at the following timings:

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

There is a significant difference in execution speed between

reduce(int.__mul__,range(10000)) and reduce(mul,range(10000)) with the latter being faster.

using the dis module to look at what was happening:

Using int.__mul__ method:

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
>>>

And the operator mul method

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
>>>

They appear the same, so why is there a difference in execution speed? I am referring to the CPython implementation of Python


The same happens on python3:

$ 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

解决方案

int.__mul__ is a slot wrapper, namely, a PyWrapperDescrObject, while operator.mul is a buit-in function. I think the opposite execution speed is caused by this difference.

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

When we call a PyWrapperDescrObject, wrapperdescr_call is called.


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;
}

Let us look at what we found!

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

A new PyWrapper object has been constructed. It would slow down the execution speed significantly. Sometimes, it takes more time to create a new object than to run a simple function.
Thus, it is not surprised that int.__mul__ is slower than operator.mul.

这篇关于INT .__ mul__,执行2X比operator.mul慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆