Skip to content
FutureBlitz

    Install

    The tour, 10 of 11

    Threads and coroutines

    Spawn and Parallel For on every core, Async and Await on one thread, and the checks that keep them safe.

    FutureBlitz has two kinds of “at the same time”: threads, which run on every core, for work that takes time; and coroutines, which take turns on the main thread, for things that wait.

    Spawn and Task

    Spawn runs a Function on the worker pool, one thread per core, and gives a Task; Wait() gives its result, waiting for it if it isn’t done.

    Import std.core
    
    Function SumTo(n: Int): Long
        Local total: Long = 0
        For i = 1 To n
            total += i
        End For
        Return total
    End Function
    
    Local a = Spawn(Function() => SumTo(1_000_000))
    Local b = Spawn(Function() => SumTo(2_000_000))
    Print(a.Wait() + b.Wait())
    Output
    2500001500000

    Parallel For

    A Parallel For splits its iterations over the pool. Each one has to stand alone, as each writing only its own element does.

    Import std.core
    
    Local squares: Long[] = []
    For i = 0 Until 1000
        squares.Add(0)
    End For
    
    Parallel For i = 0 Until 1000
        squares[i] = (i As Long) * i
    End For
    
    Print(squares[999])
    Output
    998001

    The compiler checks what threads share

    What another thread’s work uses has to be Sendable: numbers, Strings, Structs of them, and Shared Classes, whose Fields are ReadOnly, Atomic, or behind a Mutex. Handing an ordinary Class to another thread, or a Local that could change while it runs, is a compile error, so a data race doesn’t build.

    Import std.core
    
    Shared Class Stats
        Field hits: Atomic<Int>
    End Class
    
    Const stats = Stats()
    Parallel For i = 0 Until 100
        stats.hits.Add(1)
    End For
    Print(stats.hits.Load())
    Output
    100

    Coroutines

    An Async Function can Await a Task without blocking its thread: it gives the thread back, and goes on where it was when the Task is done. With std.time’s Wait, a sequence that takes seconds is written as the steps it is.

    Import std.core
    Import std.time
    
    Async Function Countdown(name: String, from: Int)
        For i = from To 1 Step -1
            Print("{name}: {i}")
            Await Wait(100.Milliseconds)
        End For
        Print("{name}: go")
    End Function
    
    Countdown("race", 3)
    Print("the countdown runs while the main code goes on")
    Output
    race: 3
    the countdown runs while the main code goes on
    race: 2
    race: 1
    race: go

    The program waits for its coroutines once its top-level code ends. In a game, the frame loop’s Flip() resumes them each frame. Next: modules and packages.

    Next: Modules and packages

    Report an issue with this page or with FutureBlitz on GitHub.