我正在尝试对 PI (3.14159) throw 飞镖的蒙特卡罗计算进行基准测试。我用 Java、Groovy、BeanShell、Julia、Jython 和 Python(用 C 实现的 Python2)实现了我的代码。
这是我的原始 Java 代码“MonteCarloPI.java”:
import java.util.Random;
public class MonteCarloPI {
public static void main(String[] args)
{
int nThrows = 0;
int nSuccess = 0;
double x, y;
long then = System.nanoTime();
int events=(int)1e8;
Random r = new Random();
for (int i = 0; i < events; i++) {
x = r.nextFloat(); // Throw a dart
y = r.nextFloat();
nThrows++;
if ( x*x + y*y <= 1 ) nSuccess++;
}
double itime = ((System.nanoTime() - then)/1e9);
System.out.println("Time for calculations (sec): " + itime+"\n");
System.out.println("Pi = " + 4*(double)nSuccess/(double)nThrows +"\n");
}
}
这是我在文件“MonteCarloPI.groovy”中的 Groovy 代码:
import java.util.Random
int nThrows = 0
int nSuccess = 0
double x, y
long then = System.nanoTime()
int events=1e8
r = new Random()
for (int i = 0; i < events; i++) {
x = r.nextFloat() // Throw a dart
y = r.nextFloat()
nThrows++
if ( x*x + y*y <= 1 ) nSuccess++
}
itime = ((System.nanoTime() - then)/1e9)
System.out.println("Time for calculations (sec): " + itime+"\n")
System.out.println("Pi = " + 4*(double)nSuccess/(double)nThrows +"\n")
或者,我删除了诸如“float”和“int”(即松散类型)之类的定义。这会使用“松散”类型检查性能。
我已将“MonteCarloPI.groovy”重命名为 BeanShell 脚本文件“MonteCarloPI.bsh”(BeanShell 的语法与 Groovy 非常相似)
在标准 Python 语言的情况下,代码“MonteCarloPI_CPython.py”如下所示:
import random,time
nThrows,nSuccess = 0,0
then = time.time()
events=int(1e8)
for i in xrange(events):
x,y = random.random(),random.random(); # Throw a dart
nThrows +=1
if ( x*x + y*y <= 1 ): nSuccess+=1
itime = time.time() - then
print ("Time: ",itime,"sec Pi = ",4*nSuccess/float(nThrows))
此代码在 CPython 2.7.18(Python 在 C 中实现)或 Jython 2.7.2(Java 实现)中执行。对于 Python 3.8.3(“Python3”),将“xrange”替换为“range”。
我还在 JRuby (MonteCarloPI.rb) 中实现了相同的算法:
require "java"
java_import java.lang.System;
java_import java.util.Random;
nThrows = 0; nSuccess = 0;
xthen = System.nanoTime();
events=1e8;
r = Random.new();
for i in 0 .. events do
x = r.nextFloat(); # Throw a dart
y = r.nextFloat();
nThrows +=1
if ( x*x + y*y <= 1 )
nSuccess += 1
end
end
itime = (System.nanoTime() - xthen)/1e9;
xpi=(4.0*nSuccess)/nThrows
puts "Time for calculations (sec): #{itime}"
puts "Pi = #{xpi}"
这里是使用 Julia 的代码:
using Random
nThrows = 0
nSuccess = 0
events=1e8
then = time()
for j in 0:events
x = rand(); # Throw a dart
y = rand();
global nThrows += 1;
if x*x + y*y <= 1
global nSuccess += 1;
end
end
itime = time() - then
println( "Time for calculations (sec):", itime, " sec")
println( "Pi = ", 4.0*nSuccess/float(nThrows) )
我在 DataMelt 中运行了“MonteCarloPI.java”、“MonteCarloPI.groovy”、“MonteCarloPI.py”、“MonteCarloPI.bsh”和 MonteCarloPI.rb。编辑。 julia 代码是使用本地安装的 julia-1.5.0/bin 处理的。
以下是在 Intel(R) Core(TM) i5-4690K CPU @ 3.50GHz(ubuntu 20.04、8 GB 内存)上的基准测试结果,在运行 Groovy、Jython、BeanShell 代码时为 JDK9 分配了 2048 MB:
Java code: 1.7 sec Pi = 3.14176584 -> executed in DataMelt/JDK9
Groovy code: 2.1 sec Pi = 3.14144832 -> executed in DataMelt/JDK9
Groovy code: 18 sec Pi = 3.14141132 -> same but with "loose" types
Julia code: 15 sec Pi = 3.14156104 -> executed in julia-1.5.0
Python code: 24 sec Pi = 3.14188036 -> executed in CPython 2.7.18
Python code: 30 sec Pi = 3.14188230 -> executed in CPython 3.2.8
Python code: 3 sec Pi = 3.14188036 -> executed using PyPy
Jython code: 24 sec Pi = 3.14187860 -> executed in DataMelt/JDK9
JRuby code: 25 sec Pi = 3.14187860 -> executed in DataMelt/JDK9
BeanShell code: takes forever?! -> executed in DataMelt/JDK9
如您所见,Java 和 Groovy 的计算时间差不多(大约 2 秒)。使用 Groovy 中的松散类型,执行速度会慢 9 倍。 Python 比 Java 和 Groovy 慢 12 倍。 Python3 甚至更慢。 JRuby 和 Python 一样慢。 PyPy 相当快(但比 Java/Groovy 慢)。 但是 BeanShell 根本无法进行此计算(需要很长时间,而且我的计算机永远不会停止处理此文件)。
对此有什么看法吗?
最佳答案
干得漂亮。你在那里进行了有趣的比较。作为 Python 开发人员,我想添加一些关于 Python 的额外 View 。
我认为它之所以慢主要是因为动态类型。另一个原因是您正在计算标量值(即使用 for 循环并一次计算一个数字)。 Python 的优势之一是使用 NumPy 库进行 vector 计算(这允许同时计算多个数字)。所以,这是我的算法实现。注意:我使用的是 python 3.6。
import numpy as np
import time
start = time.time()
events = int(1e8)
nThrows, nSuccess = 0, 0
x, y = np.random.uniform(size=(2, events))
nSuccess = (x*x + y*y <= 1).sum()
nThrows = events
pi = 4*nSuccess/float(nThrows)
stop = time.time()
print('Time: {}, Pi = {}'.format(stop-start, pi))
以下是我的 i7 x64 计算机 (Windows 10) 上的基准测试结果:
Python (original code): 42.6s Pi = 3.1414672
Python (my optimized code): 4.7s Pi = 3.1417642
如您所见,在我的计算机上运行的原始 python 代码比您计算机上的 python 代码慢。因此,优化版本可能比 Java 或 Groovy 更快。
希望这对您有所帮助。
关于java - 对 Java、Groovy、Jython 和 Python 进行基准测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54281767/