INT .__ mul__,执行2X比operator.mul慢 [英] int.__mul__ , executes 2X slower than 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__$c$c>是一个槽的包装,即,<一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$c$c>是一个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$c$c>被调用。
静态的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屋!