Cleaned up formatting in tutorials
This commit is contained in:
commit
902fe7be0c
15 changed files with 922 additions and 804 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -46,5 +46,6 @@ multiverse.log
|
||||||
.eprj
|
.eprj
|
||||||
.*.swp
|
.*.swp
|
||||||
akka-docs/_build/
|
akka-docs/_build/
|
||||||
|
*.pyc
|
||||||
akka-tutorials/akka-tutorial-first/project/boot/
|
akka-tutorials/akka-tutorial-first/project/boot/
|
||||||
akka-tutorials/akka-tutorial-first/project/plugins/project/
|
akka-tutorials/akka-tutorial-first/project/plugins/project/
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -56,8 +56,9 @@ trait ListenerManagement {
|
||||||
val iterator = listeners.iterator
|
val iterator = listeners.iterator
|
||||||
while (iterator.hasNext) {
|
while (iterator.hasNext) {
|
||||||
val listener = iterator.next
|
val listener = iterator.next
|
||||||
if (listener.isShutdown) iterator.remove()
|
// Uncomment if those exceptions are so frequent as to bottleneck
|
||||||
else try {
|
// if (listener.isShutdown) iterator.remove() else
|
||||||
|
try {
|
||||||
listener ! msg
|
listener ! msg
|
||||||
} catch {
|
} catch {
|
||||||
case e : ActorInitializationException =>
|
case e : ActorInitializationException =>
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,24 @@ SPHINXOPTS =
|
||||||
SPHINXBUILD = sphinx-build
|
SPHINXBUILD = sphinx-build
|
||||||
PAPER =
|
PAPER =
|
||||||
BUILDDIR = _build
|
BUILDDIR = _build
|
||||||
|
EASYINSTALL = easy_install
|
||||||
|
LOCALPACKAGES = $(shell pwd)/$(BUILDDIR)/site-packages
|
||||||
|
PYGMENTSDIR = pygments
|
||||||
|
|
||||||
# Internal variables.
|
# Internal variables.
|
||||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
PAPEROPT_letter = -D latex_paper_size=letter
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
.PHONY: help clean html singlehtml latex pdf
|
# Set python path to include local packages for pygments styles.
|
||||||
|
PYTHONPATH += $(LOCALPACKAGES)
|
||||||
|
export PYTHONPATH
|
||||||
|
|
||||||
|
.PHONY: help clean pygments html singlehtml latex pdf
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Please use \`make <target>' where <target> is one of"
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
|
@echo " pygments to locally install the custom pygments styles"
|
||||||
@echo " html to make standalone HTML files"
|
@echo " html to make standalone HTML files"
|
||||||
@echo " singlehtml to make a single large HTML file"
|
@echo " singlehtml to make a single large HTML file"
|
||||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
|
|
@ -24,7 +32,15 @@ help:
|
||||||
clean:
|
clean:
|
||||||
-rm -rf $(BUILDDIR)/*
|
-rm -rf $(BUILDDIR)/*
|
||||||
|
|
||||||
html:
|
pygments:
|
||||||
|
mkdir -p $(LOCALPACKAGES)
|
||||||
|
$(EASYINSTALL) --install-dir $(LOCALPACKAGES) $(PYGMENTSDIR)
|
||||||
|
-rm -rf $(PYGMENTSDIR)/*.egg-info $(PYGMENTSDIR)/build $(PYGMENTSDIR)/temp
|
||||||
|
@echo
|
||||||
|
@echo "Custom pygments styles have been installed."
|
||||||
|
@echo
|
||||||
|
|
||||||
|
html: pygments
|
||||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||||
|
|
@ -41,9 +57,8 @@ latex:
|
||||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||||
"(use \`make latexpdf' here to do that automatically)."
|
"(use \`make latexpdf' here to do that automatically)."
|
||||||
|
|
||||||
pdf:
|
pdf: pygments
|
||||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
@echo "Running LaTeX files through pdflatex..."
|
@echo "Running LaTeX files through pdflatex..."
|
||||||
make -C $(BUILDDIR)/latex all-pdf
|
make -C $(BUILDDIR)/latex all-pdf
|
||||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ import sys, os
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
extensions = ['sphinx.ext.todo']
|
sys.path.append(os.path.abspath('exts'))
|
||||||
|
extensions = ['sphinx.ext.todo', 'includecode']
|
||||||
|
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
source_suffix = '.rst'
|
source_suffix = '.rst'
|
||||||
|
|
@ -19,7 +20,7 @@ copyright = u'2009-2011, Scalable Solutions AB'
|
||||||
version = '1.1'
|
version = '1.1'
|
||||||
release = '1.1'
|
release = '1.1'
|
||||||
|
|
||||||
pygments_style = 'akka'
|
pygments_style = 'simple'
|
||||||
highlight_language = 'scala'
|
highlight_language = 'scala'
|
||||||
add_function_parentheses = False
|
add_function_parentheses = False
|
||||||
show_authors = True
|
show_authors = True
|
||||||
|
|
|
||||||
138
akka-docs/exts/includecode.py
Normal file
138
akka-docs/exts/includecode.py
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
import os
|
||||||
|
import codecs
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
from docutils.parsers.rst import Directive, directives
|
||||||
|
|
||||||
|
class IncludeCode(Directive):
|
||||||
|
"""
|
||||||
|
Include a code example from a file with sections delimited with special comments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
has_content = False
|
||||||
|
required_arguments = 1
|
||||||
|
optional_arguments = 0
|
||||||
|
final_argument_whitespace = False
|
||||||
|
option_spec = {
|
||||||
|
'section': directives.unchanged_required,
|
||||||
|
'comment': directives.unchanged_required,
|
||||||
|
'marker': directives.unchanged_required,
|
||||||
|
'include': directives.unchanged_required,
|
||||||
|
'exclude': directives.unchanged_required,
|
||||||
|
'hideexcludes': directives.flag,
|
||||||
|
'linenos': directives.flag,
|
||||||
|
'language': directives.unchanged_required,
|
||||||
|
'encoding': directives.encoding,
|
||||||
|
'prepend': directives.unchanged_required,
|
||||||
|
'append': directives.unchanged_required,
|
||||||
|
}
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
document = self.state.document
|
||||||
|
arg0 = self.arguments[0]
|
||||||
|
(filename, sep, section) = arg0.partition('#')
|
||||||
|
|
||||||
|
if not document.settings.file_insertion_enabled:
|
||||||
|
return [document.reporter.warning('File insertion disabled',
|
||||||
|
line=self.lineno)]
|
||||||
|
env = document.settings.env
|
||||||
|
if filename.startswith('/') or filename.startswith(os.sep):
|
||||||
|
rel_fn = filename[1:]
|
||||||
|
else:
|
||||||
|
docdir = path.dirname(env.doc2path(env.docname, base=None))
|
||||||
|
rel_fn = path.join(docdir, filename)
|
||||||
|
try:
|
||||||
|
fn = path.join(env.srcdir, rel_fn)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
# the source directory is a bytestring with non-ASCII characters;
|
||||||
|
# let's try to encode the rel_fn in the file system encoding
|
||||||
|
rel_fn = rel_fn.encode(sys.getfilesystemencoding())
|
||||||
|
fn = path.join(env.srcdir, rel_fn)
|
||||||
|
|
||||||
|
encoding = self.options.get('encoding', env.config.source_encoding)
|
||||||
|
codec_info = codecs.lookup(encoding)
|
||||||
|
try:
|
||||||
|
f = codecs.StreamReaderWriter(open(fn, 'U'),
|
||||||
|
codec_info[2], codec_info[3], 'strict')
|
||||||
|
lines = f.readlines()
|
||||||
|
f.close()
|
||||||
|
except (IOError, OSError):
|
||||||
|
return [document.reporter.warning(
|
||||||
|
'Include file %r not found or reading it failed' % filename,
|
||||||
|
line=self.lineno)]
|
||||||
|
except UnicodeError:
|
||||||
|
return [document.reporter.warning(
|
||||||
|
'Encoding %r used for reading included file %r seems to '
|
||||||
|
'be wrong, try giving an :encoding: option' %
|
||||||
|
(encoding, filename))]
|
||||||
|
|
||||||
|
comment = self.options.get('comment', '//')
|
||||||
|
marker = self.options.get('marker', comment + '#')
|
||||||
|
lenm = len(marker)
|
||||||
|
if not section:
|
||||||
|
section = self.options.get('section')
|
||||||
|
include_sections = self.options.get('include', '')
|
||||||
|
exclude_sections = self.options.get('exclude', '')
|
||||||
|
include = set(include_sections.split(',')) if include_sections else set()
|
||||||
|
exclude = set(exclude_sections.split(',')) if exclude_sections else set()
|
||||||
|
hideexcludes = 'hideexcludes' in self.options
|
||||||
|
if section:
|
||||||
|
include |= set([section])
|
||||||
|
within = set()
|
||||||
|
res = []
|
||||||
|
excluding = False
|
||||||
|
for line in lines:
|
||||||
|
index = line.find(marker)
|
||||||
|
if index >= 0:
|
||||||
|
section_name = line[index+lenm:].strip()
|
||||||
|
if section_name in within:
|
||||||
|
within ^= set([section_name])
|
||||||
|
if excluding and not (exclude & within):
|
||||||
|
excluding = False
|
||||||
|
else:
|
||||||
|
within |= set([section_name])
|
||||||
|
if not excluding and (exclude & within):
|
||||||
|
excluding = True
|
||||||
|
if not hideexcludes:
|
||||||
|
res.append(' ' * index + comment + ' ' + section_name.replace('-', ' ') + ' ...\n')
|
||||||
|
elif not (exclude & within) and (not include or (include & within)):
|
||||||
|
res.append(line)
|
||||||
|
lines = res
|
||||||
|
|
||||||
|
def countwhile(predicate, iterable):
|
||||||
|
count = 0
|
||||||
|
for x in iterable:
|
||||||
|
if predicate(x):
|
||||||
|
count += 1
|
||||||
|
else:
|
||||||
|
return count
|
||||||
|
|
||||||
|
nonempty = filter(lambda l: l.strip(), lines)
|
||||||
|
tabcounts = map(lambda l: countwhile(lambda c: c == ' ', l), nonempty)
|
||||||
|
tabshift = min(tabcounts) if tabcounts else 0
|
||||||
|
|
||||||
|
if tabshift > 0:
|
||||||
|
lines = map(lambda l: l[tabshift:] if len(l) > tabshift else l, lines)
|
||||||
|
|
||||||
|
prepend = self.options.get('prepend')
|
||||||
|
append = self.options.get('append')
|
||||||
|
if prepend:
|
||||||
|
lines.insert(0, prepend + '\n')
|
||||||
|
if append:
|
||||||
|
lines.append(append + '\n')
|
||||||
|
|
||||||
|
text = ''.join(lines)
|
||||||
|
retnode = nodes.literal_block(text, text, source=fn)
|
||||||
|
retnode.line = 1
|
||||||
|
retnode.attributes['line_number'] = self.lineno
|
||||||
|
if self.options.get('language', ''):
|
||||||
|
retnode['language'] = self.options['language']
|
||||||
|
if 'linenos' in self.options:
|
||||||
|
retnode['linenos'] = True
|
||||||
|
document.settings.env.note_dependency(rel_fn)
|
||||||
|
return [retnode]
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
app.require_sphinx('1.0')
|
||||||
|
app.add_directive('includecode', IncludeCode)
|
||||||
|
|
@ -6,74 +6,75 @@ Contents
|
||||||
|
|
||||||
manual/getting-started-first-scala
|
manual/getting-started-first-scala
|
||||||
manual/getting-started-first-java
|
manual/getting-started-first-java
|
||||||
pending/actor-registry-java
|
|
||||||
pending/actor-registry-scala
|
|
||||||
pending/actors-scala
|
|
||||||
pending/agents-scala
|
|
||||||
pending/articles
|
|
||||||
pending/benchmarks
|
|
||||||
pending/building-akka
|
|
||||||
pending/buildr
|
|
||||||
pending/cluster-membership
|
|
||||||
pending/companies-using-akka
|
|
||||||
pending/configuration
|
|
||||||
pending/dataflow-java
|
|
||||||
pending/dataflow-scala
|
|
||||||
pending/deployment-scenarios
|
|
||||||
pending/developer-guidelines
|
|
||||||
pending/dispatchers-java
|
|
||||||
pending/dispatchers-scala
|
|
||||||
pending/event-handler
|
|
||||||
pending/external-sample-projects
|
|
||||||
pending/fault-tolerance-java
|
|
||||||
pending/fault-tolerance-scala
|
|
||||||
pending/Feature Stability Matrix
|
|
||||||
manual/fsm-scala
|
manual/fsm-scala
|
||||||
pending/futures-scala
|
|
||||||
pending/getting-started
|
.. pending/actor-registry-java
|
||||||
pending/guice-integration
|
.. pending/actor-registry-scala
|
||||||
pending/Home
|
.. pending/actors-scala
|
||||||
pending/http
|
.. pending/agents-scala
|
||||||
pending/issue-tracking
|
.. pending/articles
|
||||||
pending/language-bindings
|
.. pending/benchmarks
|
||||||
pending/licenses
|
.. pending/building-akka
|
||||||
pending/logging
|
.. pending/buildr
|
||||||
pending/Migration-1.0-1.1
|
.. pending/cluster-membership
|
||||||
pending/migration-guide-0.10.x-1.0.x
|
.. pending/companies-using-akka
|
||||||
pending/migration-guide-0.7.x-0.8.x
|
.. pending/configuration
|
||||||
pending/migration-guide-0.8.x-0.9.x
|
.. pending/dataflow-java
|
||||||
pending/migration-guide-0.9.x-0.10.x
|
.. pending/dataflow-scala
|
||||||
pending/migration-guides
|
.. pending/deployment-scenarios
|
||||||
pending/Recipes
|
.. pending/developer-guidelines
|
||||||
pending/release-notes
|
.. pending/dispatchers-java
|
||||||
pending/remote-actors-java
|
.. pending/dispatchers-scala
|
||||||
pending/remote-actors-scala
|
.. pending/event-handler
|
||||||
pending/routing-java
|
.. pending/external-sample-projects
|
||||||
pending/routing-scala
|
.. pending/fault-tolerance-java
|
||||||
pending/scheduler
|
.. pending/fault-tolerance-scala
|
||||||
pending/security
|
.. pending/Feature Stability Matrix
|
||||||
pending/serialization-java
|
.. pending/futures-scala
|
||||||
pending/serialization-scala
|
.. pending/getting-started
|
||||||
pending/servlet
|
.. pending/guice-integration
|
||||||
pending/slf4j
|
.. pending/Home
|
||||||
pending/sponsors
|
.. pending/http
|
||||||
pending/stm
|
.. pending/issue-tracking
|
||||||
pending/stm-java
|
.. pending/language-bindings
|
||||||
pending/stm-scala
|
.. pending/licenses
|
||||||
pending/team
|
.. pending/logging
|
||||||
pending/test
|
.. pending/Migration-1.0-1.1
|
||||||
pending/testkit
|
.. pending/migration-guide-0.10.x-1.0.x
|
||||||
pending/testkit-example
|
.. pending/migration-guide-0.7.x-0.8.x
|
||||||
pending/third-party-integrations
|
.. pending/migration-guide-0.8.x-0.9.x
|
||||||
pending/transactors-java
|
.. pending/migration-guide-0.9.x-0.10.x
|
||||||
pending/transactors-scala
|
.. pending/migration-guides
|
||||||
pending/tutorial-chat-server-java
|
.. pending/Recipes
|
||||||
pending/tutorial-chat-server-scala
|
.. pending/release-notes
|
||||||
pending/typed-actors-java
|
.. pending/remote-actors-java
|
||||||
pending/typed-actors-scala
|
.. pending/remote-actors-scala
|
||||||
pending/untyped-actors-java
|
.. pending/routing-java
|
||||||
pending/use-cases
|
.. pending/routing-scala
|
||||||
pending/web
|
.. pending/scheduler
|
||||||
|
.. pending/security
|
||||||
|
.. pending/serialization-java
|
||||||
|
.. pending/serialization-scala
|
||||||
|
.. pending/servlet
|
||||||
|
.. pending/slf4j
|
||||||
|
.. pending/sponsors
|
||||||
|
.. pending/stm
|
||||||
|
.. pending/stm-java
|
||||||
|
.. pending/stm-scala
|
||||||
|
.. pending/team
|
||||||
|
.. pending/test
|
||||||
|
.. pending/testkit
|
||||||
|
.. pending/testkit-example
|
||||||
|
.. pending/third-party-integrations
|
||||||
|
.. pending/transactors-java
|
||||||
|
.. pending/transactors-scala
|
||||||
|
.. pending/tutorial-chat-server-java
|
||||||
|
.. pending/tutorial-chat-server-scala
|
||||||
|
.. pending/typed-actors-java
|
||||||
|
.. pending/typed-actors-scala
|
||||||
|
.. pending/untyped-actors-java
|
||||||
|
.. pending/use-cases
|
||||||
|
.. pending/web
|
||||||
|
|
||||||
Links
|
Links
|
||||||
=====
|
=====
|
||||||
|
|
|
||||||
129
akka-docs/manual/examples/Pi.scala
Normal file
129
akka-docs/manual/examples/Pi.scala
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
//#imports
|
||||||
|
package akka.tutorial.scala.first
|
||||||
|
|
||||||
|
import akka.actor.{Actor, PoisonPill}
|
||||||
|
import Actor._
|
||||||
|
import akka.routing.{Routing, CyclicIterator}
|
||||||
|
import Routing._
|
||||||
|
|
||||||
|
import System.{currentTimeMillis => now}
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
//#imports
|
||||||
|
|
||||||
|
//#app
|
||||||
|
object Pi extends App {
|
||||||
|
|
||||||
|
calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000)
|
||||||
|
|
||||||
|
//#actors-and-messages
|
||||||
|
// ====================
|
||||||
|
// ===== Messages =====
|
||||||
|
// ====================
|
||||||
|
//#messages
|
||||||
|
sealed trait PiMessage
|
||||||
|
case object Calculate extends PiMessage
|
||||||
|
case class Work(start: Int, nrOfElements: Int) extends PiMessage
|
||||||
|
case class Result(value: Double) extends PiMessage
|
||||||
|
//#messages
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// ===== Worker =====
|
||||||
|
// ==================
|
||||||
|
//#worker
|
||||||
|
class Worker extends Actor {
|
||||||
|
|
||||||
|
//#calculate-pi
|
||||||
|
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
|
||||||
|
var acc = 0.0
|
||||||
|
for (i <- start until (start + nrOfElements))
|
||||||
|
acc += 4 * math.pow(-1, i) / (2 * i + 1)
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
//#calculate-pi
|
||||||
|
|
||||||
|
def receive = {
|
||||||
|
case Work(start, nrOfElements) =>
|
||||||
|
self reply Result(calculatePiFor(start, nrOfElements)) // perform the work
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#worker
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// ===== Master =====
|
||||||
|
// ==================
|
||||||
|
//#master
|
||||||
|
class Master(
|
||||||
|
nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch)
|
||||||
|
extends Actor {
|
||||||
|
|
||||||
|
var pi: Double = _
|
||||||
|
var nrOfResults: Int = _
|
||||||
|
var start: Long = _
|
||||||
|
|
||||||
|
//#create-workers
|
||||||
|
// create the workers
|
||||||
|
val workers = Vector.fill(nrOfWorkers)(actorOf[Worker].start())
|
||||||
|
|
||||||
|
// wrap them with a load-balancing router
|
||||||
|
val router = Routing.loadBalancerActor(CyclicIterator(workers)).start()
|
||||||
|
//#create-workers
|
||||||
|
|
||||||
|
//#master-receive
|
||||||
|
// message handler
|
||||||
|
def receive = {
|
||||||
|
//#message-handling
|
||||||
|
case Calculate =>
|
||||||
|
// schedule work
|
||||||
|
for (i <- 0 until nrOfMessages) router ! Work(i * nrOfElements, nrOfElements)
|
||||||
|
|
||||||
|
// send a PoisonPill to all workers telling them to shut down themselves
|
||||||
|
router ! Broadcast(PoisonPill)
|
||||||
|
|
||||||
|
// send a PoisonPill to the router, telling him to shut himself down
|
||||||
|
router ! PoisonPill
|
||||||
|
|
||||||
|
case Result(value) =>
|
||||||
|
// handle result from the worker
|
||||||
|
pi += value
|
||||||
|
nrOfResults += 1
|
||||||
|
if (nrOfResults == nrOfMessages) self.stop()
|
||||||
|
//#message-handling
|
||||||
|
}
|
||||||
|
//#master-receive
|
||||||
|
|
||||||
|
override def preStart {
|
||||||
|
start = now
|
||||||
|
}
|
||||||
|
|
||||||
|
override def postStop {
|
||||||
|
// tell the world that the calculation is complete
|
||||||
|
println(
|
||||||
|
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
|
||||||
|
.format(pi, (now - start)))
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#master
|
||||||
|
//#actors-and-messages
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// ===== Run it =====
|
||||||
|
// ==================
|
||||||
|
def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) {
|
||||||
|
|
||||||
|
// this latch is only plumbing to know when the calculation is completed
|
||||||
|
val latch = new CountDownLatch(1)
|
||||||
|
|
||||||
|
// create the master
|
||||||
|
val master = actorOf(
|
||||||
|
new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch)).start()
|
||||||
|
|
||||||
|
// start the calculation
|
||||||
|
master ! Calculate
|
||||||
|
|
||||||
|
// wait for master to shut down
|
||||||
|
latch.await()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#app
|
||||||
|
|
||||||
|
|
@ -104,9 +104,9 @@ Downloading and installing Maven
|
||||||
|
|
||||||
Maven is an excellent build system that can be used to build both Java and Scala projects. If you want to use Maven for this tutorial then follow the following instructions, if not you can skip this section and the next.
|
Maven is an excellent build system that can be used to build both Java and Scala projects. If you want to use Maven for this tutorial then follow the following instructions, if not you can skip this section and the next.
|
||||||
|
|
||||||
First browse to the `Maven download page <http://maven.apache.org/download.html>`_ and download the ``3.0.3`` distribution.
|
First browse to `http://maven.apache.org/download.html <http://maven.apache.org/download.html>`_ and download the ``3.0.3`` distribution.
|
||||||
|
|
||||||
To install Maven it is easiest to follow the instructions on `this page <http://maven.apache.org/download.html#Installation>`_.
|
To install Maven it is easiest to follow the instructions on `http://maven.apache.org/download.html#Installation <http://maven.apache.org/download.html#Installation>`_.
|
||||||
|
|
||||||
Creating an Akka Maven project
|
Creating an Akka Maven project
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
@ -378,7 +378,8 @@ Here is the master actor::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Master(int nrOfWorkers, int nrOfMessages, int nrOfElements, CountDownLatch latch) {
|
public Master(
|
||||||
|
int nrOfWorkers, int nrOfMessages, int nrOfElements, CountDownLatch latch) {
|
||||||
this.nrOfMessages = nrOfMessages;
|
this.nrOfMessages = nrOfMessages;
|
||||||
this.nrOfElements = nrOfElements;
|
this.nrOfElements = nrOfElements;
|
||||||
this.latch = latch;
|
this.latch = latch;
|
||||||
|
|
@ -470,7 +471,7 @@ Now the only thing that is left to implement is the runner that should bootstrap
|
||||||
pi.calculate(4, 10000, 10000);
|
pi.calculate(4, 10000, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void calculate(final int nrOfWorkers, final int nrOfElements, final int nrOfMessages)
|
public void calculate(int nrOfWorkers, int nrOfElements, int nrOfMessages)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
// this latch is only plumbing to know when the calculation is completed
|
// this latch is only plumbing to know when the calculation is completed
|
||||||
|
|
@ -601,7 +602,9 @@ Before we package it up and run it, let's take a look at the full code now, with
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Master(int nrOfWorkers, int nrOfMessages, int nrOfElements, CountDownLatch latch) {
|
public Master(
|
||||||
|
int nrOfWorkers, int nrOfMessages, int nrOfElements, CountDownLatch latch) {
|
||||||
|
|
||||||
this.nrOfMessages = nrOfMessages;
|
this.nrOfMessages = nrOfMessages;
|
||||||
this.nrOfElements = nrOfElements;
|
this.nrOfElements = nrOfElements;
|
||||||
this.latch = latch;
|
this.latch = latch;
|
||||||
|
|
@ -664,7 +667,7 @@ Before we package it up and run it, let's take a look at the full code now, with
|
||||||
// ==================
|
// ==================
|
||||||
// ===== Run it =====
|
// ===== Run it =====
|
||||||
// ==================
|
// ==================
|
||||||
public void calculate(final int nrOfWorkers, final int nrOfElements, final int nrOfMessages)
|
public void calculate(int nrOfWorkers, int nrOfElements, int nrOfMessages)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
// this latch is only plumbing to know when the calculation is completed
|
// this latch is only plumbing to know when the calculation is completed
|
||||||
|
|
@ -702,9 +705,11 @@ First we need to compile the source file. That is done with Java's compiler ``ja
|
||||||
|
|
||||||
When we have compiled the source file we are ready to run the application. This is done with ``java`` but yet again we need to add the ``akka-actor-1.1.jar`` and the ``scala-library.jar`` JAR files to the classpath as well as the classes we compiled ourselves::
|
When we have compiled the source file we are ready to run the application. This is done with ``java`` but yet again we need to add the ``akka-actor-1.1.jar`` and the ``scala-library.jar`` JAR files to the classpath as well as the classes we compiled ourselves::
|
||||||
|
|
||||||
$ java -cp dist/akka-actor-1.1.jar:scala-library.jar:tutorial akka.tutorial.java.first.Pi
|
$ java \
|
||||||
AKKA_HOME is defined as [/Users/jboner/src/akka-stuff/akka-core], loading config from \
|
-cp dist/akka-actor-1.1.jar:scala-library.jar:tutorial \
|
||||||
[/Users/jboner/src/akka-stuff/akka-core/config/akka.conf].
|
akka.tutorial.java.first.Pi
|
||||||
|
AKKA_HOME is defined as [/Users/jboner/src/akka-stuff/akka-core]
|
||||||
|
loading config from [/Users/jboner/src/akka-stuff/akka-core/config/akka.conf].
|
||||||
|
|
||||||
Pi estimate: 3.1435501812459323
|
Pi estimate: 3.1435501812459323
|
||||||
Calculation time: 822 millis
|
Calculation time: 822 millis
|
||||||
|
|
|
||||||
|
|
@ -124,9 +124,9 @@ Downloading and installing SBT
|
||||||
|
|
||||||
SBT, short for 'Simple Build Tool' is an excellent build system written in Scala. It uses Scala to write the build scripts which gives you a lot of power. It has a plugin architecture with many plugins available, something that we will take advantage of soon. SBT is the preferred way of building software in Scala and is probably the easiest way of getting through this tutorial. If you want to use SBT for this tutorial then follow the following instructions, if not you can skip this section and the next.
|
SBT, short for 'Simple Build Tool' is an excellent build system written in Scala. It uses Scala to write the build scripts which gives you a lot of power. It has a plugin architecture with many plugins available, something that we will take advantage of soon. SBT is the preferred way of building software in Scala and is probably the easiest way of getting through this tutorial. If you want to use SBT for this tutorial then follow the following instructions, if not you can skip this section and the next.
|
||||||
|
|
||||||
First browse to the `SBT download page<http://code.google.com/p/simple-build-tool/downloads/list>`_ and download the ``0.7.6.RC0`` distribution.
|
First browse to `http://code.google.com/p/simple-build-tool/downloads/list <http://code.google.com/p/simple-build-tool/downloads/list>`_ and download the ``0.7.6.RC0`` distribution.
|
||||||
|
|
||||||
To install SBT and create a project for this tutorial it is easiest to follow the instructions on `this page <http://code.google.com/p/simple-build-tool/wiki/Setup>`_.
|
To install SBT and create a project for this tutorial it is easiest to follow the instructions on `http://code.google.com/p/simple-build-tool/wiki/Setup <http://code.google.com/p/simple-build-tool/wiki/Setup>`_.
|
||||||
|
|
||||||
Now we need to create our first Akka project. You could add the dependencies manually to the build script, but the easiest way is to use Akka's SBT Plugin, covered in the next section.
|
Now we need to create our first Akka project. You could add the dependencies manually to the build script, but the easiest way is to use Akka's SBT Plugin, covered in the next section.
|
||||||
|
|
||||||
|
|
@ -184,7 +184,7 @@ Now it's about time to start hacking.
|
||||||
|
|
||||||
We start by creating a ``Pi.scala`` file and adding these import statements at the top of the file::
|
We start by creating a ``Pi.scala`` file and adding these import statements at the top of the file::
|
||||||
|
|
||||||
package akka.tutorial.scala.first
|
package akka.tutorial.first.scala
|
||||||
|
|
||||||
import akka.actor.{Actor, PoisonPill}
|
import akka.actor.{Actor, PoisonPill}
|
||||||
import Actor._
|
import Actor._
|
||||||
|
|
@ -275,7 +275,8 @@ Now we have a router that is representing all our workers in a single abstractio
|
||||||
|
|
||||||
Here is the master actor::
|
Here is the master actor::
|
||||||
|
|
||||||
class Master(nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch)
|
class Master(
|
||||||
|
nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch)
|
||||||
extends Actor {
|
extends Actor {
|
||||||
|
|
||||||
var pi: Double = _
|
var pi: Double = _
|
||||||
|
|
@ -291,12 +292,14 @@ Here is the master actor::
|
||||||
def receive = { ... }
|
def receive = { ... }
|
||||||
|
|
||||||
override def preStart {
|
override def preStart {
|
||||||
start = now
|
start = System.currentTimeMillis
|
||||||
}
|
}
|
||||||
|
|
||||||
override def postStop {
|
override def postStop {
|
||||||
// tell the world that the calculation is complete
|
// tell the world that the calculation is complete
|
||||||
println("\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis".format(pi, (now - start)))
|
println(
|
||||||
|
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
|
||||||
|
.format(pi, (System.currentTimeMillis - start)))
|
||||||
latch.countDown()
|
latch.countDown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -371,7 +374,7 @@ That's it. Now we are done.
|
||||||
|
|
||||||
But before we package it up and run it, let's take a look at the full code now, with package declaration, imports and all::
|
But before we package it up and run it, let's take a look at the full code now, with package declaration, imports and all::
|
||||||
|
|
||||||
package akka.tutorial.scala.first
|
package akka.tutorial.first.scala
|
||||||
|
|
||||||
import akka.actor.{Actor, PoisonPill}
|
import akka.actor.{Actor, PoisonPill}
|
||||||
import Actor._
|
import Actor._
|
||||||
|
|
@ -449,14 +452,14 @@ But before we package it up and run it, let's take a look at the full code now,
|
||||||
}
|
}
|
||||||
|
|
||||||
override def preStart {
|
override def preStart {
|
||||||
start = now
|
start = System.currentTimeMillis
|
||||||
}
|
}
|
||||||
|
|
||||||
override def postStop {
|
override def postStop {
|
||||||
// tell the world that the calculation is complete
|
// tell the world that the calculation is complete
|
||||||
println(
|
println(
|
||||||
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
|
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
|
||||||
.format(pi, (now - start)))
|
.format(pi, (System.currentTimeMillis - start)))
|
||||||
latch.countDown()
|
latch.countDown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -492,9 +495,11 @@ First we need to compile the source file. That is done with Scala's compiler ``s
|
||||||
|
|
||||||
When we have compiled the source file we are ready to run the application. This is done with ``java`` but yet again we need to add the ``akka-actor-1.1.jar`` JAR file to the classpath, and this time we also need to add the Scala runtime library ``scala-library.jar`` and the classes we compiled ourselves::
|
When we have compiled the source file we are ready to run the application. This is done with ``java`` but yet again we need to add the ``akka-actor-1.1.jar`` JAR file to the classpath, and this time we also need to add the Scala runtime library ``scala-library.jar`` and the classes we compiled ourselves::
|
||||||
|
|
||||||
$ java -cp dist/akka-actor-1.1.jar:scala-library.jar:tutorial akka.tutorial.scala.first.Pi
|
$ java \
|
||||||
AKKA_HOME is defined as [/Users/jboner/src/akka-stuff/akka-core], loading config from \
|
-cp dist/akka-actor-1.1.jar:scala-library.jar:tutorial \
|
||||||
[/Users/jboner/src/akka-stuff/akka-core/config/akka.conf].
|
akka.tutorial.first.scala.Pi
|
||||||
|
AKKA_HOME is defined as [/Users/jboner/src/akka-stuff/akka-core]
|
||||||
|
loading config from [/Users/jboner/src/akka-stuff/akka-core/config/akka.conf].
|
||||||
|
|
||||||
Pi estimate: 3.1435501812459323
|
Pi estimate: 3.1435501812459323
|
||||||
Calculation time: 858 millis
|
Calculation time: 858 millis
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ Downloading and installing SBT
|
||||||
|
|
||||||
SBT, short for 'Simple Build Tool' is an excellent build system written in Scala. It uses Scala to write the build scripts which gives you a lot of power. It has a plugin architecture with many plugins available, something that we will take advantage of soon. SBT is the preferred way of building software in Scala and is probably the easiest way of getting through this tutorial. If you want to use SBT for this tutorial then follow the following instructions, if not you can skip this section and the next.
|
SBT, short for 'Simple Build Tool' is an excellent build system written in Scala. It uses Scala to write the build scripts which gives you a lot of power. It has a plugin architecture with many plugins available, something that we will take advantage of soon. SBT is the preferred way of building software in Scala and is probably the easiest way of getting through this tutorial. If you want to use SBT for this tutorial then follow the following instructions, if not you can skip this section and the next.
|
||||||
|
|
||||||
First browse to the `SBT download page<http://code.google.com/p/simple-build-tool/downloads/list>`_ and download the ``0.7.6.RC0`` distribution.
|
First browse to the `SBT download page <http://code.google.com/p/simple-build-tool/downloads/list>`_ and download the ``0.7.6.RC0`` distribution.
|
||||||
|
|
||||||
To install SBT and create a project for this tutorial it is easiest to follow the instructions on `this page <http://code.google.com/p/simple-build-tool/wiki/Setup>`_.
|
To install SBT and create a project for this tutorial it is easiest to follow the instructions on `this page <http://code.google.com/p/simple-build-tool/wiki/Setup>`_.
|
||||||
|
|
||||||
|
|
@ -172,17 +172,9 @@ Start writing the code
|
||||||
|
|
||||||
Now it's about time to start hacking.
|
Now it's about time to start hacking.
|
||||||
|
|
||||||
We start by creating a ``Pi.scala`` file and adding these import statements at the top of the file::
|
We start by creating a ``Pi.scala`` file and adding these import statements at the top of the file:
|
||||||
|
|
||||||
package akka.tutorial.scala.first
|
.. includecode:: examples/Pi.scala#imports
|
||||||
|
|
||||||
import akka.actor.{Actor, PoisonPill}
|
|
||||||
import Actor._
|
|
||||||
import akka.routing.{Routing, CyclicIterator}
|
|
||||||
import Routing._
|
|
||||||
import akka.dispatch.Dispatchers
|
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
|
|
||||||
If you are using SBT in this tutorial then create the file in the ``src/main/scala`` directory.
|
If you are using SBT in this tutorial then create the file in the ``src/main/scala`` directory.
|
||||||
|
|
||||||
|
|
@ -199,49 +191,30 @@ With this in mind, let's now create the messages that we want to have flowing in
|
||||||
- ``Work`` -- sent from the ``Master`` actor to the ``Worker`` actors containing the work assignment
|
- ``Work`` -- sent from the ``Master`` actor to the ``Worker`` actors containing the work assignment
|
||||||
- ``Result`` -- sent from the ``Worker`` actors to the ``Master`` actor containing the result from the worker's calculation
|
- ``Result`` -- sent from the ``Worker`` actors to the ``Master`` actor containing the result from the worker's calculation
|
||||||
|
|
||||||
Messages sent to actors should always be immutable to avoid sharing mutable state. In scala we have 'case classes' which make excellent messages. So let's start by creating three messages as case classes. We also create a common base trait for our messages (that we define as being ``sealed`` in order to prevent creating messages outside our control)::
|
Messages sent to actors should always be immutable to avoid sharing mutable state. In scala we have 'case classes' which make excellent messages. So let's start by creating three messages as case classes. We also create a common base trait for our messages (that we define as being ``sealed`` in order to prevent creating messages outside our control):
|
||||||
|
|
||||||
sealed trait PiMessage
|
.. includecode:: examples/Pi.scala#messages
|
||||||
|
|
||||||
case object Calculate extends PiMessage
|
|
||||||
|
|
||||||
case class Work(start: Int, nrOfElements: Int) extends PiMessage
|
|
||||||
|
|
||||||
case class Result(value: Double) extends PiMessage
|
|
||||||
|
|
||||||
Creating the worker
|
Creating the worker
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Now we can create the worker actor. This is done by mixing in the ``Actor`` trait and defining the ``receive`` method. The ``receive`` method defines our message handler. We expect it to be able to handle the ``Work`` message so we need to add a handler for this message::
|
Now we can create the worker actor. This is done by mixing in the ``Actor`` trait and defining the ``receive`` method. The ``receive`` method defines our message handler. We expect it to be able to handle the ``Work`` message so we need to add a handler for this message:
|
||||||
|
|
||||||
class Worker extends Actor {
|
.. includecode:: examples/Pi.scala#worker
|
||||||
def receive = {
|
:exclude: calculate-pi
|
||||||
case Work(start, nrOfElements) =>
|
|
||||||
self reply Result(calculatePiFor(start, nrOfElements)) // perform the work
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
As you can see we have now created an ``Actor`` with a ``receive`` method as a handler for the ``Work`` message. In this handler we invoke the ``calculatePiFor(..)`` method, wrap the result in a ``Result`` message and send it back to the original sender using ``self.reply``. In Akka the sender reference is implicitly passed along with the message so that the receiver can always reply or store away the sender reference for future use.
|
As you can see we have now created an ``Actor`` with a ``receive`` method as a handler for the ``Work`` message. In this handler we invoke the ``calculatePiFor(..)`` method, wrap the result in a ``Result`` message and send it back to the original sender using ``self.reply``. In Akka the sender reference is implicitly passed along with the message so that the receiver can always reply or store away the sender reference for future use.
|
||||||
|
|
||||||
The only thing missing in our ``Worker`` actor is the implementation on the ``calculatePiFor(..)`` method. While there are many ways we can implement this algorithm in Scala, in this introductory tutorial we have chosen an imperative style using a for comprehension and an accumulator::
|
The only thing missing in our ``Worker`` actor is the implementation on the ``calculatePiFor(..)`` method. While there are many ways we can implement this algorithm in Scala, in this introductory tutorial we have chosen an imperative style using a for comprehension and an accumulator:
|
||||||
|
|
||||||
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
|
.. includecode:: examples/Pi.scala#calculate-pi
|
||||||
var acc = 0.0
|
|
||||||
for (i <- start until (start + nrOfElements))
|
|
||||||
acc += 4 * math.pow(-1, i) / (2 * i + 1)
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
|
|
||||||
Creating the master
|
Creating the master
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
The master actor is a little bit more involved. In its constructor we need to create the workers (the ``Worker`` actors) and start them. We will also wrap them in a load-balancing router to make it easier to spread out the work evenly between the workers. Let's do that first::
|
The master actor is a little bit more involved. In its constructor we need to create the workers (the ``Worker`` actors) and start them. We will also wrap them in a load-balancing router to make it easier to spread out the work evenly between the workers. Let's do that first:
|
||||||
|
|
||||||
// create the workers
|
.. includecode:: examples/Pi.scala#create-workers
|
||||||
val workers = Vector.fill(nrOfWorkers)(actorOf[Worker].start())
|
|
||||||
|
|
||||||
// wrap them with a load-balancing router
|
|
||||||
val router = Routing.loadBalancerActor(CyclicIterator(workers)).start()
|
|
||||||
|
|
||||||
As you can see we are using the ``actorOf`` factory method to create actors, this method returns as an ``ActorRef`` which is a reference to our newly created actor. This method is available in the ``Actor`` object but is usually imported::
|
As you can see we are using the ``actorOf`` factory method to create actors, this method returns as an ``ActorRef`` which is a reference to our newly created actor. This method is available in the ``Actor`` object but is usually imported::
|
||||||
|
|
||||||
|
|
@ -253,33 +226,10 @@ Now we have a router that is representing all our workers in a single abstractio
|
||||||
- ``nrOfMessages`` -- defining how many number chunks to send out to the workers
|
- ``nrOfMessages`` -- defining how many number chunks to send out to the workers
|
||||||
- ``nrOfElements`` -- defining how big the number chunks sent to each worker should be
|
- ``nrOfElements`` -- defining how big the number chunks sent to each worker should be
|
||||||
|
|
||||||
Here is the master actor::
|
Here is the master actor:
|
||||||
|
|
||||||
class Master(nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch)
|
.. includecode:: examples/Pi.scala#master
|
||||||
extends Actor {
|
:exclude: message-handling
|
||||||
|
|
||||||
var pi: Double = _
|
|
||||||
var nrOfResults: Int = _
|
|
||||||
var start: Long = _
|
|
||||||
|
|
||||||
// create the workers
|
|
||||||
val workers = Vector.fill(nrOfWorkers)(actorOf[Worker].start())
|
|
||||||
|
|
||||||
// wrap them with a load-balancing router
|
|
||||||
val router = Routing.loadBalancerActor(CyclicIterator(workers)).start()
|
|
||||||
|
|
||||||
def receive = { ... }
|
|
||||||
|
|
||||||
override def preStart {
|
|
||||||
start = now
|
|
||||||
}
|
|
||||||
|
|
||||||
override def postStop {
|
|
||||||
// tell the world that the calculation is complete
|
|
||||||
println("\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis".format(pi, (now - start)))
|
|
||||||
latch.countDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
A couple of things are worth explaining further.
|
A couple of things are worth explaining further.
|
||||||
|
|
||||||
|
|
@ -296,170 +246,27 @@ The ``Calculate`` handler is sending out work to all the ``Worker`` actors and a
|
||||||
|
|
||||||
The ``Result`` handler is simpler, here we get the value from the ``Result`` message and aggregate it to our ``pi`` member variable. We also keep track of how many results we have received back, and if that matches the number of tasks sent out, the ``Master`` actor considers itself done and shuts down.
|
The ``Result`` handler is simpler, here we get the value from the ``Result`` message and aggregate it to our ``pi`` member variable. We also keep track of how many results we have received back, and if that matches the number of tasks sent out, the ``Master`` actor considers itself done and shuts down.
|
||||||
|
|
||||||
Let's capture this in code::
|
Let's capture this in code:
|
||||||
|
|
||||||
// message handler
|
.. includecode:: examples/Pi.scala#master-receive
|
||||||
def receive = {
|
|
||||||
case Calculate =>
|
|
||||||
// schedule work
|
|
||||||
for (i <- 0 until nrOfMessages) router ! Work(i * nrOfElements, nrOfElements)
|
|
||||||
|
|
||||||
// send a PoisonPill to all workers telling them to shut down themselves
|
|
||||||
router ! Broadcast(PoisonPill)
|
|
||||||
|
|
||||||
// send a PoisonPill to the router, telling him to shut himself down
|
|
||||||
router ! PoisonPill
|
|
||||||
|
|
||||||
case Result(value) =>
|
|
||||||
// handle result from the worker
|
|
||||||
pi += value
|
|
||||||
nrOfResults += 1
|
|
||||||
if (nrOfResults == nrOfMessages) self.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
Bootstrap the calculation
|
Bootstrap the calculation
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Now the only thing that is left to implement is the runner that should bootstrap and run the calculation for us. We do that by creating an object that we call ``Pi``, here we can extend the ``App`` trait in Scala, which means that we will be able to run this as an application directly from the command line.
|
Now the only thing that is left to implement is the runner that should bootstrap and run the calculation for us. We do that by creating an object that we call ``Pi``, here we can extend the ``App`` trait in Scala, which means that we will be able to run this as an application directly from the command line.
|
||||||
|
|
||||||
The ``Pi`` object is a perfect container module for our actors and messages, so let's put them all there. We also create a method ``calculate`` in which we start up the ``Master`` actor and wait for it to finish::
|
The ``Pi`` object is a perfect container module for our actors and messages, so let's put them all there. We also create a method ``calculate`` in which we start up the ``Master`` actor and wait for it to finish:
|
||||||
|
|
||||||
object Pi extends App {
|
.. includecode:: examples/Pi.scala#app
|
||||||
|
:exclude: actors-and-messages
|
||||||
calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000)
|
|
||||||
|
|
||||||
... // actors and messages
|
|
||||||
|
|
||||||
def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) {
|
|
||||||
|
|
||||||
// this latch is only plumbing to know when the calculation is completed
|
|
||||||
val latch = new CountDownLatch(1)
|
|
||||||
|
|
||||||
// create the master
|
|
||||||
val master = actorOf(
|
|
||||||
new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch)).start()
|
|
||||||
|
|
||||||
// start the calculation
|
|
||||||
master ! Calculate
|
|
||||||
|
|
||||||
// wait for master to shut down
|
|
||||||
latch.await()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
That's it. Now we are done.
|
That's it. Now we are done.
|
||||||
|
|
||||||
But before we package it up and run it, let's take a look at the full code now, with package declaration, imports and all::
|
But before we package it up and run it, let's take a look at the full code now, with package declaration, imports and all:
|
||||||
|
|
||||||
package akka.tutorial.scala.first
|
.. includecode:: examples/Pi.scala
|
||||||
|
|
||||||
import akka.actor.{Actor, PoisonPill}
|
|
||||||
import Actor._
|
|
||||||
import akka.routing.{Routing, CyclicIterator}
|
|
||||||
import Routing._
|
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
|
|
||||||
object Pi extends App {
|
|
||||||
|
|
||||||
calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000)
|
|
||||||
|
|
||||||
// ====================
|
|
||||||
// ===== Messages =====
|
|
||||||
// ====================
|
|
||||||
sealed trait PiMessage
|
|
||||||
case object Calculate extends PiMessage
|
|
||||||
case class Work(start: Int, nrOfElements: Int) extends PiMessage
|
|
||||||
case class Result(value: Double) extends PiMessage
|
|
||||||
|
|
||||||
// ==================
|
|
||||||
// ===== Worker =====
|
|
||||||
// ==================
|
|
||||||
class Worker extends Actor {
|
|
||||||
|
|
||||||
// define the work
|
|
||||||
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
|
|
||||||
var acc = 0.0
|
|
||||||
for (i <- start until (start + nrOfElements))
|
|
||||||
acc += 4 * math.pow(-1, i) / (2 * i + 1)
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
|
|
||||||
def receive = {
|
|
||||||
case Work(start, nrOfElements) =>
|
|
||||||
self reply Result(calculatePiFor(start, nrOfElements)) // perform the work
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================
|
|
||||||
// ===== Master =====
|
|
||||||
// ==================
|
|
||||||
class Master(
|
|
||||||
nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch)
|
|
||||||
extends Actor {
|
|
||||||
|
|
||||||
var pi: Double = _
|
|
||||||
var nrOfResults: Int = _
|
|
||||||
var start: Long = _
|
|
||||||
|
|
||||||
// create the workers
|
|
||||||
val workers = Vector.fill(nrOfWorkers)(actorOf[Worker].start())
|
|
||||||
|
|
||||||
// wrap them with a load-balancing router
|
|
||||||
val router = Routing.loadBalancerActor(CyclicIterator(workers)).start()
|
|
||||||
|
|
||||||
// message handler
|
|
||||||
def receive = {
|
|
||||||
case Calculate =>
|
|
||||||
// schedule work
|
|
||||||
//for (arg <- 0 until nrOfMessages) router ! Work(arg, nrOfElements)
|
|
||||||
for (i <- 0 until nrOfMessages) router ! Work(i * nrOfElements, nrOfElements)
|
|
||||||
|
|
||||||
// send a PoisonPill to all workers telling them to shut down themselves
|
|
||||||
router ! Broadcast(PoisonPill)
|
|
||||||
|
|
||||||
// send a PoisonPill to the router, telling him to shut himself down
|
|
||||||
router ! PoisonPill
|
|
||||||
|
|
||||||
case Result(value) =>
|
|
||||||
// handle result from the worker
|
|
||||||
pi += value
|
|
||||||
nrOfResults += 1
|
|
||||||
if (nrOfResults == nrOfMessages) self.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
override def preStart {
|
|
||||||
start = now
|
|
||||||
}
|
|
||||||
|
|
||||||
override def postStop {
|
|
||||||
// tell the world that the calculation is complete
|
|
||||||
println(
|
|
||||||
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
|
|
||||||
.format(pi, (now - start)))
|
|
||||||
latch.countDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================
|
|
||||||
// ===== Run it =====
|
|
||||||
// ==================
|
|
||||||
def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) {
|
|
||||||
|
|
||||||
// this latch is only plumbing to know when the calculation is completed
|
|
||||||
val latch = new CountDownLatch(1)
|
|
||||||
|
|
||||||
// create the master
|
|
||||||
val master = actorOf(
|
|
||||||
new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch)).start()
|
|
||||||
|
|
||||||
// start the calculation
|
|
||||||
master ! Calculate
|
|
||||||
|
|
||||||
// wait for master to shut down
|
|
||||||
latch.await()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Run it as a command line application
|
Run it as a command line application
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
|
||||||
19
akka-docs/pygments/setup.py
Normal file
19
akka-docs/pygments/setup.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
"""
|
||||||
|
Akka syntax styles for Pygments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
entry_points = """
|
||||||
|
[pygments.styles]
|
||||||
|
simple = styles.simple:SimpleStyle
|
||||||
|
"""
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name = 'akkastyles',
|
||||||
|
version = '0.1',
|
||||||
|
description = __doc__,
|
||||||
|
author = "Akka",
|
||||||
|
packages = ['styles'],
|
||||||
|
entry_points = entry_points
|
||||||
|
)
|
||||||
0
akka-docs/pygments/styles/__init__.py
Normal file
0
akka-docs/pygments/styles/__init__.py
Normal file
|
|
@ -3,7 +3,7 @@
|
||||||
pygments.styles.akka
|
pygments.styles.akka
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Akka style for Scala highlighting.
|
Simple style for Scala highlighting.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pygments.style import Style
|
from pygments.style import Style
|
||||||
|
|
@ -11,9 +11,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \
|
||||||
Number, Operator, Generic, Whitespace
|
Number, Operator, Generic, Whitespace
|
||||||
|
|
||||||
|
|
||||||
class AkkaStyle(Style):
|
class SimpleStyle(Style):
|
||||||
"""
|
"""
|
||||||
Akka style for Scala highlighting.
|
Simple style for Scala highlighting.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
background_color = "#f0f0f0"
|
background_color = "#f0f0f0"
|
||||||
|
|
@ -9,6 +9,7 @@ import Actor._
|
||||||
import akka.routing.{Routing, CyclicIterator}
|
import akka.routing.{Routing, CyclicIterator}
|
||||||
import Routing._
|
import Routing._
|
||||||
|
|
||||||
|
import System.{currentTimeMillis => now}
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue