java - 对 Java、Groovy、Jython 和 Python 进行基准测试

标签 java python groovy jruby jython

我正在尝试对 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/

相关文章:

java - 不正确的week_of_year

java - 将字符串转换为 ASCII 格式,然后再转换为 HEX 格式

python - 从列表中删除重复的连续元组?

python - 如何从 Python 中的 InstagramAPI 开始?

Groovy AST - 在编译时添加注释

java - 特殊字符的问题

Python - 将不同类的对象传递给函数

jenkins - 编写 Jenkins 管道作业脚本

javascript - 在 Grails 的 JavaScript 源代码中执行 groovy 语句

java - 从另一个类中处理 JFrame