速度竞赛!
原文链接:https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/the-amazing-race
13977 评分此文:
.1
速度竞赛!
Zachary Norman 2016年9月28日,星期三
不久前,IDL 8.5 引入了 IDL-Python 桥接。正是通过这个新版本,我首次体验了 Python 编程并测试了 IDL-Python 桥接。在过去的一年里,看到桥接部分融入的新变化和改进令人兴奋。
这些新功能包括:
- IDL-Python 桥接提供了更好的错误捕获能力
- 增强的 Jupyter 笔记本,允许在同一环境中开发完整的 IDL 程序和 Python 代码
- 改进了变量来回传递的支持
在花费了大量时间使用 Python 之后,我一直在思考 Python 和 IDL 之间的某些优势是什么。我经常听到一些工程师说的一件事是,IDL 比 Python 快得多。对于这篇博客,我决定对此进行测试,看看 Python 和 IDL 到底如何相互比较。
在谈论测试之前,我想先解释一下测试是如何设置的,以及将要展示的处理时间可能存在的一些注意事项。对于我创建的测试,我尽力选择了在 IDL 和 Python 之间具有可比性的测试。由于我不是 Python 专家,很可能存在比我即将展示的方法更快的方法。测试中包含的大部分内容都是我通过网页搜索轻松找到的——这意味着我使用的大多数方法都是人们可能使用的最常见的编程方法。这展示了 IDL 相较于人们可能在 Python 中编写的通用程序可能快多少。
测试内容:
以下是在 IDL 和 Python 之间实际测试的内容,测试使用了一个 [10000, 10000] 或 10000*10000 个元素的数组
- 数组创建时间
- 类型转换时间
- 索引数组创建时间 (例如 [0,1,2,3,4...,n-1])
- 将所有元素的数组值递增 1
- 数组的复杂数学表达式(精确方程:sqrt(sin(arr*arr)))
- IDL 单线程和多线程
- 数组元素访问时间(例如,设置 y = arr[i])
- 简单的图像处理滤波器时间(滤波器:sobel, roberts, prewitt)
结果:
平均数组创建时间(秒):
Python : 0.213000 +/- 0.00953933
IDL : 0.0936666 +/- 0.0155028
总时间(秒):
Python : 0.639000
IDL : 0.281000
Python/IDL 时间比:2.27402
平均数组数据类型转换时间(秒):
Python : 0.171333 +/- 0.0155028
IDL : 0.0730000 +/- 0.00866031
总时间(秒):
Python : 0.514000
IDL : 0.219000
Python/IDL 时间比:2.34703
平均索引数组创建时间(秒):
Python : 0.229000 +/- 0.00866031
IDL : 0.124667 +/- 0.0160104
总时间(秒):
Python : 0.687000
IDL : 0.374000
Python/IDL 时间比:1.83690
平均数组值递增时间(秒):
Python : 0.0933333 +/- 0.000577446
IDL : 0.0313334 +/- 0.000577377
总时间(秒):
Python : 0.280000
IDL : 0.0940001
Python/IDL 时间比:2.97872
平均复杂数学语句(1 线程)时间(秒):
Python : 6.36967 +/- 0.0645319
IDL : 8.34667 +/- 0.0155028
总时间(秒):
Python : 19.1090
IDL : 25.0400
Python/IDL 时间比:0.763139
平均复杂数学语句(8 线程)时间(秒):
Python : 6.34400 +/- 0.0321871
IDL : 1.93933 +/- 0.00923762
总时间(秒):
Python : 19.0320
IDL : 5.81800
Python/IDL 时间比:3.27123
平均遍历数组元素时间(秒):
Python : 11.5290 +/- NaN
IDL : 3.29100 +/- NaN
总时间(秒):
Python : 11.5290
IDL : 3.29100
Python/IDL 时间比:3.50319
平均图像处理例程时间(秒):
Python : 15.3660 +/- 0.0829635
IDL : 1.39900 +/- 0.0238955
总时间(秒):
Python : 46.0980
IDL : 4.19700
Python/IDL 时间比:10.9836
结论:
简而言之,除了复杂数学语句测试外,IDL 在所有速度测试中都显著优于 Python。然而,IDL 能够对大型数组进行内置的多线程访问,并且在启用多线程的情况下,当使用所有可用核心时,IDL 的性能显著优于 Python。
以下是用于比较 IDL 和 Python 处理速度的 IDL 代码。要使用它,您将需要一些 Python 模块,这些模块可以在过程 "python_test" 的开头找到。
IDL 代码:
pro printTimes, pythontimes, idltimes, TIMED = timed
compile_opt idl2
;check if we have a name for the process to print with the mean
if ~keyword_set(timed) then begin
add = ' time (seconds):'
endif else begin
add = timed + ' time (seconds):'
endelse
print, 'Average ' + add
print, ' Python : ' + strtrim(pythontimes.mean(),2) + ' +/- ' + strtrim(stddev(pythontimes),2)
print, ' IDL : ' + strtrim(idltimes.mean(),2) + ' +/- ' + strtrim(stddev(idltimes),2)
print, 'Total time (seconds):'
print, ' Python : ' + strtrim(total(pythontimes),2)
print, ' IDL : ' + strtrim(total(idltimes),2)
print, 'Python/IDL time ratio: ' + strtrim(total(pythontimes)/total(idltimes),2)
end
pro python_test
compile_opt idl2
;initialize Python
>>> 'import numpy as np'
>>> 'import time'
>>> 'import math'
>>> 'from idlpy import *'
>>> 'from skimage.filters import roberts, sobel, prewitt'
;number of times we want to run each test
nloops = 3
;array dimensions for iterator tests
dims = 10000
;>>>'dims = ' + strtrim(dims,2)
python.dims = dims
;array dimensions for filter tests
dims_filter = 10000
python.dims_filter = dims_filter
;initialize arrays to hol dpython times
pythontimes = fltarr(nloops)
idltimes = fltarr(nloops)
;test array creation in Python and IDL
for i=0,nloops-1 do begin
tStart = systime(/seconds)
>>> 'arr = np.ones((dims,dims))'
tEndPython = systime(/seconds)
arr = fltarr(dims,dims)
tEndIDL = systime(/seconds)
;save the times
pythontimes[i] = tEndPython - tStart
idltimes[i] = tEndIDL - tEndPython
endfor
print
printTimes, pythontimes, idltimes, TIMED = 'array creation'
;check type conversion times
for i=0,nloops-1 do begin
tStart = systime(/seconds)
>>> 'arr2 = arr.astype(int)'
tEndPython = systime(/seconds)
arr2 = fix(arr)
tEndIDL = systime(/seconds)
;save the times
pythontimes[i] = tEndPython - tStart
idltimes[i] = tEndIDL - tEndPython
endfor
print
printTimes, pythontimes, idltimes, TIMED = 'array data type conversion'
;check index array creation times
for i=0,nloops-1 do begin
tStart = systime(/seconds)
>>> 'arr = np.arange(0, dims*dims, dtype=long)'
tEndPython = systime(/seconds)
arr = lindgen(dims*dims)
tEndIDL = systime(/seconds)
;save the times
pythontimes[i] = tEndPython - tStart
idltimes[i] = tEndIDL - tEndPython
endfor
print
printTimes, pythontimes, idltimes, TIMED = 'index array creation'
;check adding values to array
for i=0,nloops-1 do begin
tStart = systime(/seconds)
>>> 'arr += 1'
tEndPython = systime(/seconds)
arr += 1
tEndIDL = systime(/seconds)
;save the times
pythontimes[i] = tEndPython - tStart
idltimes[i] = tEndIDL - tEndPython
endfor
print
printTimes, pythontimes, idltimes, TIMED = 'increasing array value'
;check complex math expressions with a single thread
pref_set, 'IDL_CPU_TPOOL_NTHREADS', 1, /commit
for i=0,nloops-1 do begin
tStart = systime(/seconds)
>>> 'y = np.sin(arr*arr)**.5'
tEndPython = systime(/seconds)
y = sqrt(sin(arr*arr))
tEndIDL = systime(/seconds)
;save the times
pythontimes[i] = tEndPython - tStart
idltimes[i] = tEndIDL - tEndPython
endfor
print
printTimes, pythontimes, idltimes, TIMED = 'complex math statements (' + strtrim(!CPU.TPOOL_NTHREADS,2) + ' thread)'
pref_set, 'IDL_CPU_TPOOL_NTHREADS', /default, /commit
;check complex math expressions with all threads
for i=0,nloops-1 do begin
tStart = systime(/seconds)
>>> 'y = np.sin(arr*arr)**.5'
tEndPython = systime(/seconds)
y = sqrt(sin(arr*arr))
tEndIDL = systime(/seconds)
;save the times
pythontimes[i] = tEndPython - tStart
idltimes[i] = tEndIDL - tEndPython
endfor
print
printTimes, pythontimes, idltimes, TIMED = 'complex math statements (' + strtrim(!CPU.TPOOL_NTHREADS,2) + ' thread)'
;check array element access times
nhere = 1
for i=0,nhere-1 do begin
tStart = systime(/seconds)
>>>'for x in np.nditer(arr):\n y=x'
tEndPython = systime(/seconds)
foreach x, arr do y = x
tEndIDL = systime(/seconds)
;save the times
pythontimes[i] = tEndPython - tStart
idltimes[i] = tEndIDL - tEndPython
endfor
print
printTimes, pythontimes[0:nhere-1], idltimes[0:nhere-1], TIMED = 'loop through array element'
;check times for image processing
im_dat = lonarr(dims_filter, dims_filter)
;set a square in the middle of the image to 1
im_dat[.4*dims_filter:.6*dims_filter,.4*dims_filter:.6*dims_filter] = 1
;send the array to Python as well
python.im_dat = im_dat
for i=0,nloops-1 do begin
tStart = systime(/seconds)
>>> 'edge_sobel = sobel(im_dat)'
>>> 'edge_roberts = roberts(im_dat)'
>>> 'edge_prewitt = prewitt(im_dat)'
tEndPython = systime(/seconds)
edge_sobel = sobel(im_dat)
edge_roberts = roberts(im_dat)
edge_prewitt = prewitt(im_dat)
tEndIDL = systime(/seconds)
;save the times
pythontimes[i] = tEndPython - tStart
idltimes[i] = tEndIDL - tEndPython
endfor
print
printTimes, pythontimes, idltimes, TIMED = 'image processing routines'
stop
end