Session Abstract: It is an exciting time for developing applications that run on the Java™ Virtual Machine (JVM™ machine), because you have more choices than ever. You can take your pick of languages such as Python, Ruby, Groovy, and Scala for writing your applications while still leveraging the power of the JVM machine. However, what are the performance trade-offs? This session, for developers who want to use alternative languages on the JVM machine, looks at implementing various algorithms in each of these languages and compares how well they perform on the JVM machine. It discusses the characteristics of each language and how they influence performance results. It also throws in pure Java technology-based implementations of these algorithms as well as “native” performance for languages such as Python and Ruby. Some of the results can be very surprising.
10. Three Algorithms & Six Languages
• Prime Number Sieve • Groovy
• Case Insensitive Word Sort • JRuby
• Reversible Numbers • Jython
• Clojure
• Scala
• Fan
11. Three Algorithms & Six Languages
• Prime Number Sieve • Groovy
• Case Insensitive Word Sort • JRuby
• Reversible Numbers • Jython
• Clojure
• Scala
• Fan
13. public class Primes {
final private List<Integer> primes;
private final int size;
public Primes(int n){
size = n;
primes = new ArrayList<Integer>(n);
init();
}
private void init(){
int i=2;
int max = calcSize();
List<Boolean> nums = new ArrayList<Boolean>(max);
for (int j=0;j<max;j++){
nums.add(true);
}
while (i < max && primes.size() < size){
int p = i;
if (nums.get(i)){
primes.add(p);
int j = 2*p;
while (j < max - p){
nums.set(j,false);
j += p;
}
}
i += 1;
}
}
public int last(){
return primes.get(primes.size()-1);
}
private int calcSize(){
int max = 2;
while ((max/Math.log(max)) < size && max < Integer.MAX_VALUE && max > 0){
max *=2;
}
return max;
}
}
14. class RubyPrimes
attr_accessor :cnt, :primes
def initialize(n)
@primes = Array.new(n,0)
@cnt = 0
i = 2
max = calcSize
nums = Array.new(max,true)
while (i < max && @cnt < @primes.length)
p = i
if (nums[i])
@primes[@cnt] = p
@cnt += 1
(p .. (max/p)).each{ |j| nums[p*j] = false }
end
i += 1
end
end
def calcSize
max = 2
max = max * 2 while ( max/Math.log(max) < @primes.length)
max
end
def last
@primes[@cnt -1]
end
end
15. class PyPrimes(object):
__slots__ = ['cnt','primes','size']
def __init__(self,n):
self.primes = n*[0]
self.cnt = 0
self.size = n
i = 2
max = self.calcSize()
nums = max*[True]
while i < max and self.cnt < self.size:
p = i
if nums[i]:
self.primes[self.cnt] = p
self.cnt += 1
for j in xrange(p, max/p):
nums[p*j] = False
i+= 1
def calcSize(self):
max = 2
while max/log(max) < self.size:
max = max *2 # this makes the sieve too big, but fast
return max
def last(self):
return self.primes[self.cnt - 1]
17. class ScalaPrimes(val size:Int){
val primes = new ArrayBuffer[Int]
var cnt = 0
init
def last = primes(primes.size - 1)
private
def init {
var i = 2
val max = calcSize
val nums = new ArrayBuffer[Boolean]
for (i<-0 until max) nums += true
while (i < max && cnt < size){
val p = i
if (nums(i)){
primes += p
cnt += 1
(p until max/p).foreach((j) => nums.update(p*j,false))
}
i += 1
}
}
def calcSize = {
var max = 2
while ( (max/log(max)) < size && max < MAX_VALUE && max > 0) {
max *= 2
}
max
}
}
18. class Primes {
Int[] primes := Int[,]
Int size
new make(Int n) {
size = n
primes.capacity = n
init
}
private Void init() {
i := 2
max := calcSize
nums := Bool[,]
nums.fill(true, max)
while (i < max && primes.size < size) {
p := i
if (nums[i])
{
primes.add(p)
j := 2*p;
while (j < max - p) {
nums[j] = false
j += p;
}
}
i += 1;
}
}
Int last() { primes.last }
private Int calcSize() {
max := 2
while ((max.toFloat/max.toFloat.log).toInt < size && max < 0x7fff_ffff && max > 0) {
max *=2; // memory inefficient, but fast
}
return max;
}
}
21. public class WordSort {
private final File dataFile;
private final List<String> words;
public WordSort(String fileName){
dataFile = new File(fileName);
int idx = fileName.lastIndexOf(quot;/quot;);
String name = fileName.substring(idx+1, fileName.length() - 4);
int numWords = Integer.parseInt(name);
words = new ArrayList<String>(numWords);
}
public List<String> getSortedWords(){
if (words.size() > 0){
return words;
}
try {
BufferedReader reader = new BufferedReader(new FileReader(dataFile));
try{
String line;
while ( (line = reader.readLine()) != null){
for (String string : line.split(quot; quot;)){
words.add(string);
}
}
} finally {
reader.close();
}
Collections.sort(words, new Comparator<String>(){
public int compare(String s, String s1) {
return s.toLowerCase().compareTo(s1.toLowerCase());
}
});
return words;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
22. public class GroovyWordSort {
File dataFile
List words = []
public GroovyWordSort(fileName){
dataFile = new File(fileName)
}
def sortedWords(){
if (!words){
dataFile.eachLine{it.tokenize().each {words.add(it) }}
words = words.sort{w,w1 -> w.toLowerCase() <=> w1.toLowerCase()}
}
words
}
}
23. class RubyWordSort
def initialize(fileName)
@dataFile = File.new(fileName)
@words = Array.new
end
def sortedWorts
if (@words.length == 0)
@dataFile.each_line{ |line| line.split(' ').each{ |word| @words << word}}
@words = @words.sort{ |w,w1| w.upcase <=> w1.upcase }
end
@words
end
end
24. class PyWordSort(object):
def __init__(self, fileName):
print quot;init quot; + fileName
self.dataFile = open(fileName)
self.words = []
def sortedWords(self):
if len(self.words) == 0:
for line in self.dataFile:
for word in line.split():
self.words.append(word)
self.words.sort(lambda w,w1: cmp(w.lower(), w1.lower()))
return self.words
30. WTF is a Reversible Number?
Some positive integers n have the property that the sum [ n + reverse(n) ] consists entirely of odd
(decimal) digits. For instance, 36 + 63 = 99 and 409 + 904 = 1313. We will call such numbers
reversible; so 36, 63, 409, and 904 are reversible. Leading zeroes are not allowed in either n or
reverse(n).
There are 120 reversible numbers below one-thousand.
31. public class Reversible {
final int max;
final int numReversible;
public Reversible(int max){
this.max = max;
this.numReversible = this.countReversible();
}
public int countReversible(){
if (numReversible > 0){
return numReversible;
}
int cnt = 0;
for (int i=11;i<=max;i++){
if (reversible(i)) {
cnt++;
}
}
return cnt;
}
private boolean reversible(int n){
return allOdd(reverse(n));
}
private boolean allOdd(int n){
String str = Integer.toString(n);
for (int i=0;i<str.length();i++){
int m = Character.digit(str.charAt(i),10);
if (m % 2 == 0) return false;
}
return true;
}
private int reverse(Integer n){
char[] digits = n.toString().toCharArray();
char[] rev = new char[digits.length];
for (int i=digits.length-1;i>=0;i--){
rev[i] = digits[digits.length -i-1];
}
return n + Integer.parseInt(String.valueOf(rev));
}
}
32. public class GroovyReversible {
final Integer max
final Integer numReversible = 0
public GroovyReversible(max){
this.max = max
this.numReversible = this.countReversible()
}
def countReversible(){
numReversible ?: (11..max).findAll{reversible(it)}.size()
}
def reversible(n){
allOdd(reverse(n))
}
def allOdd(n){
n.toString().toList().collect {it.toInteger()}.every{it % 2 == 1}
}
def reverse(n){
n + n.toString().toList().reverse().join().toInteger()
}
}
33. class RubyReversible
def initialize(max)
@max = max
@numReversible = nil
end
def allOdd(n)
digits = n.to_s.split(//)
digits.length == digits.map{|c| c.to_i}.select{|i| i % 2 == 1}.length
end
def reverse(n)
n + n.to_s.reverse.to_i
end
def reversible(n)
allOdd(reverse(n))
end
def countReversible()
@numReversible ||= (11..@max).select{|i| reversible(i)}.length
@numReversible
end
end
34. class PyReversible(object):
__slots__ = ['max','numReversible']
def __init__(self, max):
self.max = max
self.numReversible = self.countReversible()
def countReversible(self):
return len([i for i in xrange(11,self.max+1) if self.reversible(i)])
def allOdd(self,n):
for ch in str(n):
if int(ch) % 2 != 1:
return False
return True
def reverse(self,n):
return n + int(str(n)[::-1])
def reversible(self,n):
return self.allOdd(self.reverse(n))