Using threads in WebAssembly

Background

While the WebAssembly spec defines atomic operations, it does not define a way to create threads. This means that WebAssembly modules can't create threads themselves, and the host environment must provide a way to create threads and run WebAssembly modules on them.

wasi-threads proposal

The WebAssembly System Interface (WASI) had a proposal for adding thread creation APIs to WASI. The proposal was implemented in several WASI host runtimes, including Wasmtime and wasm-micro-runtime, but it was withdrawn in August 2023 in favor of shared-everything-threads proposal. However, the shared-everything-threads proposal is still in the early stages of development and is not yet available in any WASI host runtime. So, for now, we are employing the wasi-threads ABI in SwiftWasm to provide thread support immediately.

The wasi-threads feature is only available in the wasm32-unknown-wasip1-threads target triple, which is explicitly distinct from the wasm32-unknown-wasi target triple.

The wasm32-unknown-wasip1-threads target triple is only available in the nightly Swift SDK for WebAssembly.

You can run WebAssembly programs built with the wasm32-unknown-wasip1-threads target by using the wasmtime runtime with the --wasi threads flag. Check a recent nightly Swift SDK release and how to install it here.

# Assume you are using swift-DEVELOPMENT-SNAPSHOT-2024-12-04-a toolchain
$ swift sdk install https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-12-05-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-12-05-a-wasm32-unknown-wasip1-threads.artifactbundle.zip --checksum 1796ae86f3c90b45d06ee29bb124577aa4135585bbd922430b6d1786f855697d
$ swift build --swift-sdk wasm32-unknown-wasip1-threads
# Enable the `wasi-threads` feature in wasmtime
$ wasmtime --wasi threads .build/debug/Example.wasm

Note that even with the wasi-threads feature, the default concurrency execution model is still single-threaded as we have not yet ported libdispatch. The wasi-threads feature is only used to provide a low-level pthread API for creating threads.

WebWorkerTaskExecutor - shared-everything concurrency

We provide WebWorkerTaskExecutor, a TaskExecutor implementation that runs Tasks in a Web Worker. This allows you to run Swift code concurrently in a Web Worker sharing the same memory space.

This feature is available in the JavaScriptKit package and you need to use wasm32-unkonwn-wasip1-threads target and SharedArrayBuffer to use it.

See more details in the following links:

WebWorkerKit - shared-nothing concurrency

If you can't use SharedArrayBuffer or want to run Swift code in a separate memory space, you can use WebWorkerKit. WebWorkerKit is a library that provides a way to run Swift Distributed Actors in their own worker "thread" in a Web Worker. It's message-passing based and allows you to run Swift code concurrently in a Web Worker without sharing memory space.

Check the repository for more details: swiftwasm/WebWorkerKit: A way of running Swift Distributed Actors in their own worker "thread"