title: Benchmarking Java, Groovy, Jython and Python
body: <p>I'm trying to benchmark a Monte Carlo calculation of PI (3.14159) throwing darts. I've implemented my code in Java, Groovy, BeanShell, Julia, Jython and Python (Python2 implemented in C).</p>
  <p>Here is my original Java code &quot;MonteCarloPI.java&quot;:</p>
  <pre><code>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 &lt; events; i++) {
              x = r.nextFloat();      // Throw a dart
              y = r.nextFloat();
              nThrows++;
              if ( x*x + y*y &lt;= 1 )  nSuccess++;
         }
   double itime = ((System.nanoTime() - then)/1e9);
   System.out.println(&quot;Time for calculations (sec): &quot; + itime+&quot;\n&quot;);
   System.out.println(&quot;Pi = &quot; + 4*(double)nSuccess/(double)nThrows +&quot;\n&quot;);
        }
  }
  </code></pre>
  <p>Here is my Groovy code in the file &quot;MonteCarloPI.groovy&quot;:</p>
  <pre><code>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 &lt; events; i++) {
              x = r.nextFloat()      // Throw a dart
              y = r.nextFloat()
              nThrows++
              if ( x*x + y*y &lt;= 1 )  nSuccess++
  }
  itime = ((System.nanoTime() - then)/1e9)
  System.out.println(&quot;Time for calculations (sec): &quot; + itime+&quot;\n&quot;)
  System.out.println(&quot;Pi = &quot; + 4*(double)nSuccess/(double)nThrows +&quot;\n&quot;)
         
  </code></pre>
  <p>Alternatively, I've removed the  definitions such as  &quot;float&quot; and &quot;int&quot; (i.e. loose types). This checks the performance using &quot;loose&quot; types.</p>
  <p>I've renamed &quot;MonteCarloPI.groovy&quot; to a BeanShell script file &quot;MonteCarloPI.bsh&quot; (BeanShell has a very similar syntax as Groovy)</p>
  <p>In the case of the standard Python language, the code &quot;MonteCarloPI_CPython.py&quot; looks as this:</p>
  <pre><code>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 &lt;= 1 ):  nSuccess+=1
  itime = time.time() - then
  print (&quot;Time: &quot;,itime,&quot;sec Pi = &quot;,4*nSuccess/float(nThrows))
  </code></pre>
  <p>This code is executed either in CPython 2.7.18 (Python implemented in C) or Jython 2.7.2 (Java implementation). For Python 3.8.3 (&quot;Python3&quot;), replace &quot;xrange&quot; with &quot;range&quot;.</p>
  <p>I also implemented the same algorithm in JRuby (MonteCarloPI.rb):</p>
  <pre><code>require &quot;java&quot;
  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 &lt;= 1 )
                  nSuccess += 1
    end
  end
  itime = (System.nanoTime() - xthen)/1e9;
  xpi=(4.0*nSuccess)/nThrows
  puts &quot;Time for calculations (sec):  #{itime}&quot;
  puts &quot;Pi = #{xpi}&quot;
  </code></pre>
  <p>Here the code using Julia:</p>
  <pre><code>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 &lt;= 1
                   global nSuccess += 1;
          end
  end
  itime = time() - then
  println( &quot;Time for calculations (sec):&quot;, itime, &quot; sec&quot;)
  println( &quot;Pi = &quot;, 4.0*nSuccess/float(nThrows) )
  </code></pre>
  <p>I ran &quot;MonteCarloPI.java&quot;, &quot;MonteCarloPI.groovy&quot;, &quot;MonteCarloPI.py&quot;,  &quot;MonteCarloPI.bsh&quot; and MonteCarloPI.rb inside <a href="https://datamelt.org/" rel="nofollow noreferrer">DataMelt</a> editor.
  The julia code was processed using locally installed julia-1.5.0/bin.</p>
  <p>Here is the benchmark results on Intel(R) Core(TM) i5-4690K CPU @ 3.50GHz (ubuntu 20.04, 8 GB memory), with 2048 MB allocated for JDK9 when running  Groovy, Jython, BeanShell code:</p>
  <pre><code>Java   code:   1.7 sec Pi = 3.14176584  -&gt; executed in DataMelt/JDK9
  Groovy code:   2.1 sec Pi = 3.14144832  -&gt; executed in DataMelt/JDK9
  Groovy code:   18 sec Pi = 3.14141132  -&gt; same but with &quot;loose&quot; types 
  Julia code:    15 sec Pi = 3.14156104  -&gt; executed in julia-1.5.0
  Python code:   24 sec Pi = 3.14188036  -&gt; executed in CPython 2.7.18
  Python code:   30 sec Pi = 3.14188230  -&gt; executed in CPython 3.2.8
  Python code:    3 sec Pi = 3.14188036  -&gt; executed using PyPy
  Jython code:   24 sec Pi = 3.14187860  -&gt; executed in DataMelt/JDK9
  JRuby  code:   25 sec Pi = 3.14187860  -&gt; executed in DataMelt/JDK9
  BeanShell code: takes forever?!       -&gt; executed in DataMelt/JDK9
  </code></pre>
  <p>As you can see, Java and Groovy calculations take about the same time (about 2 sec). With loose types in Groovy, the execution takes 9 times slower.
  Python is a factor 12 slower than Java and Groovy. Python3 is even slower. JRuby is as slow as Python. PyPy is rather fast (but slower than Java/Groovy).
  But  BeanShell cannot do this calculation at all (takes forever, and my computer never stops processing this file).</p>
  <p>Any wisdom on this?</p>