[英]python: if - in operator. Is there a difference between these two codes?
[英]Why there is a huge performance difference between these two codes in Python and Cython?
我遇到了在Python的性能問題,我的一個朋友建議我用用Cython搜索更長時間后,我發現這個代碼在這里
蟒蛇:
def test(value):
for i in xrange(value):
z = i**2
if(i==1000000):
print i
if z < i:
print "yes"
test(10000001)
用Cython:
def test(long long value):
cdef long long i
cdef long long z
for i in xrange(value):
z = i**2
if(i==1000000):
print i
if z < i:
print "yes"
test(10000001)
在我執行兩個代碼之后,令人驚訝的是我通過Cython實現了100倍的加速
為什么只是通過添加變量聲明來實現這種加速? 另外我應該提到波紋管代碼性能與Cython中的Python相同。
用Cython:
def test(long long value):
for i in xrange(value):
z = i**2
if(i==1000000):
print i
if z < i:
print "yes"
test(10000001)
Python是一種語言。 CPython是一個字節碼編譯器和Python的解釋 器 。
它需要一些代碼:
for i in xrange(value):
z = i**2
if(i==1000000):
print i
if z < i:
print "yes"
並給你“字節碼”:
for
循環中並將其內容循環到i
i
,加載2
,運行二進制功率,存儲z
i
,加載1000000
,比較 i
,打印 z
,加載i
,比較 'yes'
,打印 在全:
1 0 SETUP_LOOP 70 (to 73)
3 LOAD_NAME 0 (xrange)
6 LOAD_NAME 1 (value)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 56 (to 72)
16 STORE_NAME 2 (i)
2 19 LOAD_NAME 2 (i)
22 LOAD_CONST 0 (2)
25 BINARY_POWER
26 STORE_NAME 3 (z)
3 29 LOAD_NAME 2 (i)
32 LOAD_CONST 1 (1000000)
35 COMPARE_OP 2 (==)
38 POP_JUMP_IF_FALSE 49
4 41 LOAD_NAME 2 (i)
44 PRINT_ITEM
45 PRINT_NEWLINE
46 JUMP_FORWARD 0 (to 49)
5 >> 49 LOAD_NAME 3 (z)
52 LOAD_NAME 2 (i)
55 COMPARE_OP 0 (<)
58 POP_JUMP_IF_FALSE 13
6 61 LOAD_CONST 2 ('yes')
64 PRINT_ITEM
65 PRINT_NEWLINE
66 JUMP_ABSOLUTE 13
69 JUMP_ABSOLUTE 13
>> 72 POP_BLOCK
>> 73 LOAD_CONST 3 (None)
76 RETURN_VALUE
值得注意的是,在Python中,整數是int
或long
類的實例 。 這意味着不僅有數字,還有指針和另一條信息,至少說明它是什么類。 這會產生很多開銷。
但值得注意的是xrange
如何運作。
xrange
創建了一個可以由for
迭代的類實例( LOAD_NAME (xrange)
, CALL_FUNCTION
)。 for
(基本上)將委托給迭代器的__iter__
上的函數調用。 每個循環都有一個函數調用。
此外,每次要獲取或設置變量z
或i
,都必須查看本地字典。 這真的很慢。
在Cython中運行純Python代碼:
當你在Cython中運行它(問題中的第三個例子)時,它會編譯為C.但是所有這些C的作用都是告訴 CPython虛擬機要做什么。
僅CPython:一個人從書中讀書,並且實際執行其功能。
CPython的與用Cython:一個人喊 的說明誰merticulously實現其功能的人。
它可能會快一點,但緩慢的部分仍然是CPython正在慢慢完成工作。
使用cythonized代碼:
那么當你cdef long long
會發生什么呢?
Cython知道xrange
正在做long long
事情:
它知道循環是有效的(所以它不必檢查你給它一個list
或某些)
它知道循環不會溢出(因為它確實是未定義的!)
因此它可以把它變成一個C循環( for (int index=0; index<copy_of_value; index++) { i = index; ... }
)
這避免了int
和long
類,它們具有大量的間接開銷和類型檢查
這避免了字典查找。 事情永遠都是你把它們放在堆棧上的地方
例如i ** 2
更簡單,因為例程可以內聯(它總是一個數字,粗魯)並直接在整數上工作並忽略溢出
因此,結果最終主要由C運行,並且只進入CPython進行一些清理和print
調用。
合理?
正如我在評論中提到的:你的第三個解決方案是較慢/ as-slow-as-python-version,因為它缺少允許Cython加速代碼的靜態類型功能。 當你將變量聲明為long
fe時,Cython不需要構造一個“昂貴的”Python-Object,但可能完全依賴於C-Code。 我不是Cython也不是Python專家,但我猜Python的對象構造是主要的瓶頸。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.