14.4. A complete and useless example

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:

(2)

the first repeats a message 100 times,

(3)

…forwarding them to another one,

(1)

…that ultimately pushes them to a concurrent queue.

(5)

A message is sent to a final worker,

(4)

…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: