Python与Javascript执行时间比较

8

我尝试使用Javascript(Node.js)和Python编写了最大子数组的暴力算法解决方案。以下是我的代码:

使用Python:

from datetime import datetime
from random import randint

arr = [randint(-1000,1000) for i in range(1000)]

def bruteForce(a):
  l = len(a)
  max = 0
  for i in range(l):
    sum = 0
    for j in range(i, l):
      sum += a[j]
      if(sum > max):
        max = sum
  return max

start = datetime.now()
bruteForce(arr)
end = datetime.now()

print(format(end-start))

还有JavaScript:

function randInt(start, end) {
    return Math.floor(Math.random() * (end - start + 1))
}

var arr = Array(1000).fill(randInt(-1000, 1000))

function bruteForce(arr) {
    var max = 0
    for (let i = 0; i < arr.length; i++) {
        var sum = 0
        for (let j = i; j < arr.length; j++) {
            sum += arr[j]
            max = Math.max(max, sum)
        }
    }
    return max
}

var start = performance.now()
bruteForce(arr)
var end = performance.now()
console.log(end - start)

JavaScript的结果大约是0.187秒,而Python则需要4.75秒,相比之下慢了约25倍。 我的代码没有进行优化还是Python真的比JavaScript慢这么多?

1
当在现代浏览器中运行时,结构良好的JS非常快。也许有一天,浏览器将对Python进行即时字节码编译,但它还有很多赶上的地方。我曾经将百万次循环的JS函数改写成C语言,运行时间非常接近 - 浏览器在处理重复操作(如循环)时特别高效,只有一个或两个变量发生变化。这里有一些有趣的背景材料:https://hacks.mozilla.org/2017/02/a-crash-course-in-just-in-time-jit-compilers/ - Dave Pritlove
@general-grievance,JS的时间是多少?当然不同的用户系统会有所不同,比较才是最重要的。看看不同的设置如何比较会很有趣。 - Dave Pritlove
1
在我的电脑上,它们都需要大约0.3秒。 - Achille G
2
@DavePritlove 确实。在TIO上测试:Python:约0.1秒,JS在删除所有输出代码后为0.07-0.08秒。因此,速度较慢,但并非25倍。 - General Grievance
@general-grievance,是的,那很接近。谢谢。 - Dave Pritlove
JS - 2.011249989271164, Py - 0:00:00.014953, MacBook Pro M1 - Marius
1个回答

11

Python并不比JavaScript慢,这取决于其实现方式。 以下是比较了Node和使用JIT的PyPy的结果:

> /pypy39/python brute.py
109.8594 ms N= 10000 result= 73682
> node brute.js
167.4442000091076 ms N= 10000 result= 67495

我们甚至可以说"Python有点更快"... 如果我们使用Cython,并且加上一些类型提示,它将再次比以前快得多 - 实际上是全速的C语言速度:

> cythonize -a -i brutec.pyx
> python -c "import brutec"
69.28919999999998 ms N= 10000 result= 52040

为了使比较合理,我修复了你的脚本中存在的一些问题:

  • 修复:js脚本使用单个随机数填充数组中的所有相同值
  • 在Python中进行了相同基本类型的循环 - 而不是使用range迭代器(否则速度会稍慢)
  • 使用相同的时间格式并增加数组长度到10000 - 否则时间分辨率和线程切换抖动太小

Python代码:

from time import perf_counter as clock
from random import randint

N = 10000
arr = [randint(-1000,1000) for i in range(N)]

def bruteForce(a):
  l = len(a)
  max = 0
  i = 0
  while i < l:
    sum = 0
    j = i
    while j < l:
      sum += a[j]
      if sum > max:
        max = sum
      j += 1
    i += 1
  return max

start = clock()
r = bruteForce(arr)
end = clock()
print((end - start) * 1000, 'ms', 'N=', N, 'result=', r)
##print(arr[:10])

JS 代码:

var start = -1000, end = 1000, N=10000
var arr = Array.from({length: N}, 
    () => Math.floor(Math.random() * (end - start + 1) + start))

function bruteForce(arr) {
    var max = 0
    for (let i = 0; i < arr.length; i++) {
        var sum = 0
        for (let j = i; j < arr.length; j++) {
            sum += arr[j];
            max = Math.max(max, sum)
            //~ if (sum > max) max = sum;
        }
    }
    return max
}

var start = performance.now()
r = bruteForce(arr)
var end = performance.now()
console.log(end - start, 'ms', 'N=', N, 'result=', r)
//~ console.log(arr.slice(0, 10))

用注释增强的 Cython(或 Python)代码,附带了一些类型提示:
import cython
from time import perf_counter as clock
from random import randint

N = 10000
arr = [randint(-1000,1000) for i in range(N)]

def bruteForce(arr):
  l: cython.int = len(arr)
  assert l <= 10000
  a: cython.int[10000] = arr  # copies mem from Python array
  max: cython.int = 0
  i: cython.int = 0
  while i < l:
    sum: cython.int = 0
    j: cython.int = i
    while j < l:
      sum += a[j]
      if sum > max:
        max = sum
      j += 1
    i += 1
  return max

start = clock()
r = bruteForce(arr)
end = clock()
print((end - start) * 1000, 'ms', 'N=', N, 'result=', r)
##print(arr[:10])

(在一台慢速笔记本上完成)


1
Py 花费了 2825.7724170107394 毫秒 N= 10000 结果为 71565,JS 花费了 39.68283399939537 毫秒 N= 10000 结果为 49005。 - Marius
以下是我在虚拟机上的结果:~# node --version v10.19.0 ~# python3 --version Python 3.8.10 ~# python3 test.py 11107.16739995405 毫秒 N= 10000 结果= 81061 ~# node test.js 249.11676907539368 'ms' 'N=' 10000 'result=' 137303 - ooziefixer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接