跳转至

速度竞赛!

原文链接: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

ENVI 5.4 即将推出:ENVITask 样式表 使用 IDL 的 TOTAL 函数最小化舍入误差