Я пытался сравнить вычисление метания дротиков в PI (3.14159) по методу Монте-Карло. Я реализовал свой код на Java, Groovy, BeanShell, Jython и Python (Python2 реализован на C)
Вот мой оригинальный код Java "MonteCarloPI.java":
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;
for (int i = 0; i < events; i++) {
x = Math.random(); // Throw a dart
y = Math.random();
nThrows++;
if ( x*x + y*y <= 1 ) nSuccess++;
}
int itime = (int)((System.nanoTime() - then)/1e9);
System.out.println("Time for calculations (sec): " + itime+"\n");
System.out.println("Pi = " + 4*(double)nSuccess/(double)nThrows +"\n");
}
}
Вот мой код Groovy, помещенный в файл "MonteCarloPI.groovy":
int nThrows = 0; int nSuccess = 0;
double x, y;
long then = System.nanoTime();
int events=(int)1e8;
for (int i = 0; i < events; i++) {
x = Math.random(); y = Math.random(); // Throw a dart
nThrows++;
if ( x*x + y*y <= 1 ) nSuccess++;
}
int itime = (int)((System.nanoTime() - then)/1e9);
System.out.println("Time for calculations (sec): " + itime+"\n");
System.out.println("Pi = " + 4*(float)nSuccess/(float)nThrows +"\n");
А вот мой код Jython "MonteCarloPI.py":
from java.util import Random
from java.lang import *
nThrows,nSuccess = 0,0
then = System.nanoTime()
events=int(1e8)
for i in xrange(events):
x,y = Math.random(),Math.random(); # Throw a dart
nThrows +=1
if ( x*x + y*y <= 1 ): nSuccess+=1
itime = (int)((System.nanoTime() - then)/1e9)
print "Time for calculations (sec): ",itime
print "Pi = ", 4*nSuccess/float(nThrows)
Я переименовал «MonteCarloPI.groovy» в файл сценария BeanShell «MonteCarloPI.bsh» (синтаксис BeanShell очень похож на Groovy)
В случае стандартного Python код «MonteCarloPI_CPython.py» выглядит так:
import random
import 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 for calculations (sec): ",itime
print "Pi = ", 4*nSuccess/float(nThrows)
Я также реализовал тот же алгоритм в JRuby (MonteCarloPI.rb):
require "java"
java_import java.lang.System;
java_import java.lang.Math;
nThrows = 0; nSuccess = 0;
xthen = System.nanoTime();
events=1e8;
for i in 0 .. events do
x = Math.random(); y = Math.random(); # Throw a dart
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}"
Я запустил «MonteCarloPI.java», «MonteCarloPI.groovy», «MonteCarloPI.py», «MonteCarloPI.bsh» и MonteCarloPI.rb внутри DataMelt редактора.
Вот результаты тестов на моем компьютере i7 x64 (Linux Mint) с 2048 МБ, выделенными для JDK9 при выполнении кода Groovy, Jython, BeanShell:
Java code: 3 sec Pi = 3.14176584 -> executed in DataMelt/JDK9
Groovy code: 3 sec Pi = 3.14144832 -> executed in DataMelt/JDK9
Python code: 3 sec Pi = 3.14188036 -> executed using PyPy
Groovy code: 14 sec Pi = 3.14141132 -> when using loose types for x,y
Python code: 28 sec Pi = 3.14188036 -> executed in Python (CPython)
JRuby code: 31 sec Pi = 3.14187860 -> executed in DataMelt/JDK9
Jython code: 40 sec Pi = 3.14187860 -> executed in DataMelt/JDK9
BeanShell code: takes forever?! -> executed in DataMelt/JDK9
Jython after replacing xrange() with range() -> takes forever?!
Как видите, вычисления Java и Groovy занимают примерно одно и то же время (3 секунды).
Python в 10 раз медленнее, чем Java и Groovy. JRuby такой же медленный, как Python. PyPy довольно быстрый (так же быстро, как Java / Groovy).
Но Jython и BeanShell вообще не могут выполнить этот расчет (это занимает вечно, и мой компьютер никогда не прекращает обработку этого файла).
В последнем примере использовался Jython версии 2.7.2a. Я повторил выполнение кода Jython вне DataMelt, используя сценарий "jython.sh", поставляемый с самим Jython, и получил те же результаты (т.е. вычисление Jython занимает вечность).
Я знал, что Jython полезен для манипуляций с высокоуровневыми классами Java, но я не ожидал, что он не сможет многое сделать для такого простого числового случая, когда используется «range» вместо «xrange».
Python также удивительно медленный по сравнению со скриптами в Groovy.
Есть ли в этом какая-то мудрость?