To better understand how workers can be used, here is a (fairly useless) example:
module SampleWithWorkers import java.lang.Thread import java.util.concurrent import gololang.concurrent.workers.WorkerEnvironment local function pusher = |queue, message| -> queue: offer(message) # (1) local function generator = |port, message| { # (2) foreach i in range(0, 100) { port: send(message) # (3) } } function main = |args| { let env = WorkerEnvironment.builder(): withFixedThreadPool() let queue = ConcurrentLinkedQueue() let pusherPort = env: spawn(^pusher: bindTo(queue)) let generatorPort = env: spawn(^generator: bindTo(pusherPort)) let finishPort = env: spawn(|any| -> env: shutdown()) # (4) foreach i in range(0, 10) { generatorPort: send("[" + i + "]") } Thread.sleep(2000_L) finishPort: send("Die!") # (5) env: awaitTermination(2000) println(queue: reduce("", |acc, next| -> acc + " " + next)) }
In this example, we spawn 3 workers:
the first repeats a message 100 times, | |
…forwarding them to another one, | |
…that ultimately pushes them to a concurrent queue. | |
A message is sent to a final worker, | |
…that shuts the workers environment down. |
As an aside, the example illustrates that worker functions may take further dependencies as
arguments. The pusher
function takes a queue target and generator
needs a port.
You can satisfy dependencies by pre-binding function arguments, all you need is to make sure that
each function passed to spawn
only expects a single message as its argument, as in:
^pusher: bindTo(queue)
, and
^generator: bindTo(pusherPort)
, and
env: spawn(|any| -> env: shutdown())
where the worker function is defined as a closure, and
implicitly captures its env
dependency from the surrounding context.