nurseries #22
Replies: 4 comments 9 replies
-
Higher-level thread management APIs like nurseries are great ideas in general, but unfortunately they aren't a great fit for WebAssembly. Nurseries and other higher-level APIs make threading more manageable by restricting how it can be used, but that means they can't easily be used to implement the more permissive threading APIs of languages that compile to Wasm. Since WebAssembly is a compilation target, we have to consider how easy it is to compile existing languages to it, not how easy it is for programmers to use directly. |
Beta Was this translation helpful? Give feedback.
-
The idea reminds me of structured concurrency. We discussed the possibility of that early on but, like @tlively said of this idea, structured concurrency was too difficult a target for some language's concurrency model. |
Beta Was this translation helpful? Give feedback.
-
More permissive threading APIs of languages that compile to Wasm could spawn a nursery and immediately call the How much performance can be gained / would be lost? All threads operate on temporarily unshared memory. No memory fences would be required (aside from one fence after the join.) Nurseries could be a way to make that seen by the compiler. There is lots to contemplate about but regardless of having granular nurseries or not i still expect to be able to kill a |
Beta Was this translation helpful? Give feedback.
-
I propose something like these two paired threading primitives:
(type $long_task (func (param i32) (param i32)))
;; populate nursery with threads
(func $thread.fray
(param $f (ref $long_task))
(param $n i32)
(param $c i32)
(result nursery)
;; implemented by runtime
unreachable
)
;; block until all threads terminated
(func $thread.splice
(param $nursery nursery)
;; implemented by runtime
unreachable
) The (table $orphanage 100 nursery)
(global $next_free_slot (mut i32) (i32.const 0))
(func $thread.spawn
(param $f (ref $long_task))
(param $n i32)
(param $c i32)
(table.set $orphanage
(global.get $next_free_slot)
(call $thread.allocate_i32
(local.get $f)
(local.get $n)
(local.get $c)
)
)
(global.set $next_free_slot
(i32.add
(i32.const 1)
(global.get $next_free_slot)
)
)
) |
Beta Was this translation helpful? Give feedback.
-
There is a threading concept of so called nurseries [0]. Nurseries are to threads what
if/else/switch
are togoto
s. The insight is that nurseries are not a limitation but a liberation from complicated threading behavior and bugs.Having nurseries translates to having the
spawn
function returning a nursery for the spawned threads. The nursery would behave like some kind of uniqueexternref
. That means it cannot be copied and is not allowed to go out of scope. (It can be returned though!) Then there is a shutdown function that takes a nursery as an argument and waits for all the associated threads to finish before it returns.This is like having some kind of dog leash for each thread bundle. The simplest usage pattern is to have one or more nurseries propagate up the call stack until it reaches close to the entry point of an application where they are stashed. When the main thread wants to exit it has the means to take care of all spawned threads it was responsible of spawning. This way the main thread is able to reliable kill all lingering background threads.
Short-lived nurseries might give the compiler concrete information for optimizations. It can be ascertained that some concurrent but local operations are concluded by the time the shutdown function was called.
It was an excellent choice for
WebAssembly
to not allow access to the implicit call stack and therefor structure the control flow. An analog argumentation can be made for threads. I believe it is a good idea to explore structuring the parallel control flow of threads in a similar way.In my experience it is even better to restrict the mightiness of a new interface compared to introducing less features in a new interface. At some point in time there could be a
let_go_of
function that drops nurseries without waiting for all the threads in order to get the unrestricted behavior. Perhaps there might never be a need for the raw behavior.[0] https://www.youtube.com/watch?v=oLkfnc_UMcE
Beta Was this translation helpful? Give feedback.
All reactions