Pi

  • 694 views
Uploaded on

Java to JRuby translation of Akka's first tutorial to compute Pi using Madhava-Leibniz series. (http://akka.io/docs/akka/1.1.2/intro/getting-started-first-java.html)

Java to JRuby translation of Akka's first tutorial to compute Pi using Madhava-Leibniz series. (http://akka.io/docs/akka/1.1.2/intro/getting-started-first-java.html)

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
694
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
2
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. pi.rb Page 1 of 3 1: #! /usr/bin/env jruby 2: 3: # First things first. 4: # Load Java integration support 5: require "java" 6: 7: # Add ’lib’ in the same directory as this file to the load path 8: $: << File.join(File.dirname(__FILE__), ’lib’) 9: 10: # Load Java libraries 11: require ’scala-library’ 12: require ’akka/akka-actor-1.1.2’ 13: 14: # Here, we import Java classes so that we don’t have to prefix them 15: # with Java::. 16: java_import ’akka.actor.Actors’ 17: java_import ’akka.actor.ActorRef’ 18: java_import ’akka.actor.UntypedActor’ 19: java_import ’akka.actor.UntypedActorFactory’ 20: java_import ’akka.routing.CyclicIterator’ 21: java_import ’akka.routing.InfiniteIterator’ 22: java_import ’akka.routing.Routing’ 23: java_import ’akka.routing.UntypedLoadBalancer’ 24: # Java’s built-in classes don’t need to be quoted (for a String) 25: java_import java.util.concurrent.CountDownLatch 26: 27: # Convenience method for creating an Actor 28: def actorOf(&code) 29: Actors.actorOf(Class.new do 30: include UntypedActorFactory 31: define_method(:create) do |*args| 32: code[*args] 33: end 34: end.new) 35: end 36: 37: class Calculate; end 38: # Struct.new(...) creates an instance having the instance variables 39: # passed 40: class Work < Struct.new(:start, :nrOfElements); end 41: class Result < Struct.new(:value); end 42: 43: class Worker < UntypedActor 44: # needed by actorOf 45: def self.create(*args) 46: new *args 47: end 48: 49: # define the work 50: def calculatePiFor(start, nrOfElements) 51: # Here, we are using the identity 52: # Pi = 4 * sum_{k=0}^{infty} (-1)^k/(2 k + 1) 53: # We divide the work into chunks of nrOfElements 54: # Enumerable#inject may be a little foreign for Java programmers, but 55: # it can be thought of as a shorthand for looping and re-assigning 56: # the value of the block inside to the memo varialbe ("acc" in this case) 57: # "M...N" means a Range starting at M, ending *1 before* N. 58: ((start * nrOfElements)...((start + 1) * nrOfElements)).inject(0) do |acc,i| 59: acc + 4.0 * (1 - (i.modulo 2) * 2) / (2 * i + 1) 60: end 61: end 62: 63: # message handler 64: def onReceive(message) 65: # examining the class of an object is not very Ruby-esque.
  • 2. pi.rb Page 2 of 3 66: # in generatl, Rubyists prefer duck typing 67: if message.kind_of? Work 68: work = message 69: 70: # perform the work 71: result = calculatePiFor(work.start, work.nrOfElements) 72: 73: # reply with the result 74: context.replyUnsafe(Result.new(result)) 75: 76: else 77: raise IllegalArgumentException.new "Unknown message [#{message + b}]" 78: end 79: end 80: end 81: 82: class PiRouter < UntypedLoadBalancer 83: attr_reader :seq 84: 85: def initialize(workers) 86: super() # make sure the underlying Java proxy is properly initialized 87: @seq = CyclicIterator.new(workers) 88: end 89: end 90: 91: class Master < UntypedActor 92: def initialize(nrOfWorkers, nrOfMessages, nrOfElements, latch) 93: super() 94: @nrOfMessages, @nrOfElements, @latch = nrOfMessages, nrOfElements, latch 95: @nrOfResults, @pi = 0, 0.0 96: 97: # create the workers 98: workers = java.util.ArrayList.new 99: nrOfWorkers.times { workers << Actors.actorOf(Worker).start } 100: 101: # wrap them with a load-balancing router 102: @router = actorOf { PiRouter.new(workers) }.start 103: end 104: 105: # message handler 106: def onReceive(message) 107: if message.kind_of? Calculate 108: # schedule work 109: @nrOfMessages.times do |start| 110: @router.sendOneWay(Work.new(start, @nrOfElements), context) 111: end 112: 113: # send a PoisonPill to all workers telling them to shut down themselves 114: @router.sendOneWay(Routing::Broadcast.new(Actors.poisonPill)) 115: 116: # send a PoisonPill to the router, telling him to shut himself down 117: @router.sendOneWay Actors.poisonPill 118: elsif message.kind_of? Result # handle result from the worker 119: @pi += message.value 120: @nrOfResults += 1 121: context.stop if @nrOfResults == @nrOfMessages 122: else 123: raise IllegalArgumentException.new "Unknown message [#{message}]" 124: end 125: end 126: 127: def preStart 128: @start = java.lang.System.currentTimeMillis 129: end 130:
  • 3. pi.rb Page 3 of 3 131: def postStop 132: # tell the world that the calculation is complete 133: puts format("ntPi estimate: tt%sntCalculation time: t%s millis", 134: @pi, (java.lang.System.currentTimeMillis - @start)) 135: @latch.countDown 136: end 137: end 138: 139: 140: class Pi 141: def self.calculate(nrOfWorkers, nrOfElements, nrOfMessages) 142: # this latch is only plumbing to know when the calculation is completed 143: latch = CountDownLatch.new(1) 144: 145: # create the master 146: master = Actors.actorOf do 147: Master.new(nrOfWorkers.to_i, nrOfMessages.to_i, nrOfElements.to_i, latch) 148: end.start 149: master.sendOneWay(Calculate.new) # start the calculation 150: latch.await # wait for master to shut down 151: end 152: end 153: 154: # Ready to do the real work 155: if (ARGV.length < 3) 156: exit "Usage: $0 num_workers num_elements num_messages" 157: end 158: 159: Pi.calculate(*ARGV[0..2])