Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Concurrency

A program that does one thing at a time leaves most of the machine idle. With concurrency, several pieces of work run at once: on different cores, or while another piece waits for a disk, a network or a timer.

#import "std/tasks"
#cmdline "-mt"

'' Add up one slice of the range and send the answer back.
sub SumRange( byval lo as int64, byval hi as int64, _
              byval results as tasks.SendChan( of int64 ) )
    dim as int64 total = 0
    for i as int64 = lo to hi
        total += i
    next
    results.Send( total )
end sub

'' Four goroutines, a quarter of the work each.
var results = tasks.Channel( of int64 )( 4 )
for part as int32 = 0 to 3
    spawn SumRange( part * 250000 + 1, ( part + 1 ) * 250000, results )
next

'' The parts arrive in any order; their sum does not depend on it.
dim as int64 total = 0, partial
for part as int32 = 1 to 4
    results.Receive( partial )
    total += partial
next
print "sum of 1 to 1000000:"; total

Output

sum of 1 to 1000000: 500000500000

spawn SumRange( ... ) starts a goroutine: the call runs alongside the rest of the program, and spawn returns at once. A goroutine has no return value, so each one sends its partial sum down a channel, and the main program receives four of them. They can arrive in any order, which is why the program adds them up rather than printing each one.

A program that uses goroutines needs two lines at its top:

#import "std/tasks"
#cmdline "-mt"

std/tasks holds goroutines, channels and the tools for coordinating them. -mt builds the program with the runtime that is safe to call from several threads at once. You have to ask for it yourself: std/tasks refuses to compile without it, with TKO0309: #error: "std/tasks needs the multithreaded runtime: build with -mt".

A program that starts threads of its own, without std/tasks, gets the thread-safe runtime without asking. When the compiler sees a call to threadcreate, it links that runtime by itself. Mutexes and condition variables alone do not count: a program with no second thread does not need the thread-safe runtime. Writing #cmdline "-mt" in such a program does no harm, and the examples in this section all carry it.

The section has two levels:

LevelPages
Goroutines and channels, from std/tasksspawn, channels, select, worker pool, cancellation
Operating-system threads and shared memorythreads, mutexes, condition variables, atomics

Reach for goroutines and channels first: values move between them by copy, and the order of events is visible in the code. Threads and locks are the foundation underneath, for the cases that need them.

Activities

  1. Split the work into eight goroutines instead of four.
  2. Print each partial sum as it arrives, run the program a few times, and watch the order change while the total does not.