Repository navigation
[tracking] Experimental WebAssembly multithreading support #68162
Copy link
Copy link
Open
Labels
arch-wasmWebAssembly architectureWebAssembly architecturearea-VM-threading-monodisabled-testThe test is disabled in source code against the issueThe test is disabled in source code against the issueos-browserBrowser variant of arch-wasmBrowser variant of arch-wasmtrackingThis issue is tracking the completion of other related issues.This issue is tracking the completion of other related issues.
Milestone
Description
This is a tracking issue for adding experimental support for WebAssembly multi-threading to the browser-wasm runtime pack.
High Level Goals
The threading runtime should be distributed in the same browser-wasm runtime packThe threading runtime is in a separate.multithread.runtime pack variant. The WASM SDK chooses the correct runtime pack variant based on project properties.- Threading should be opt-in only
- The wasm bindings and runtime are thread-safe and co-op GC aware
Completed in .NET 7 RC2
The wasm-experimental workload supports threading using <WasmEnableThreads>true</WasmEnableThreads> in interp and AOT configurations when using the wasmbrowser workload. Blazor does not support threading in .NET 7
Tracking
SDK:
- Support wasm variants in NuGet packages #76959
- The browser-wasm SDK should automatically reference the threading/perf-tracing ref assemblies #72872
- Properties/targets to generate and consume AOT profiles
- Properties/targets to create and run EP instrumented apps with
dotnet-counters/dotnet-trace(viadotnet-dsrouter)
CI testing:
- Need a way to skip tests on single threaded / multi-threaded wasm configs.
- Add tests. (src/libraries). Maybe add some convenient way to add
ProjectReferences to the multi-threaded ref assemblies (the roll-upMicrosoft.NET.WebAssembly.Threading.projdoesn't seem to work) and run the normal runtime tests.
Libraries and Interop:
- JS interop should support threading #76956
- [browser][MT] Multithreading and JavaScript async interop in .NET 9 #85592
- [browser][mt] Propagate unhandled JS errors in JSWebWorker to the top level Task #76957
- [browser][mt] Do not allow blocking on the thread with JS interop: UI, JSWebWorker #76958
- [API Proposal]: RuntimeFeature.IsMultithreadingSupported #77541
- Blazor needs to provide
dotnet.worker.jsas ajs-module-threadsasset (fixed by [browser] Enable threads in Wasm SDK #85109)
Runtime and codegen:
- [browser][MT] JS Interop should respect GC pauses #76963
- AOT: tell LLVM that it's ok to use atomics if threading is enabled
Issues:
- [wasm-mt] Improved experience when SharedArrayBuffer is not available #76961
- Real multithreading in Blazor WebAssembly aspnetcore#17730
- dotnet/razor-tooling#7250
- The
Microsoft.AspNetCore.Components.WebAssembly.DevServer(used by blazorwasm fordotnet run) should serve CORS headers - Blazor should use the GC-safe API for accessing the render tree from JS
- cleanup the Node polyfill in
dotnet.worker.jsthat usesevalandrequire[wasm] proper startup sequence indotnet.worker.js#70891 - [browser][MT] Switch to multi-threaded Emscripten VFS when it is available #76964
- [wasm-mt] Option to package threaded runtime as CommonJS #76962
- [browser][mt] Upgrade emscripten #75625
- [browser][mt] Provide API to start the web workers later #75629
-
Kind of resolved - we use Emscripten's ability to pre-allocate some workers before the app starts creating threads.Thread.Start().Waitpattern on the browser threads will deadlock. Emscripten relies on the browser thread's eventloop to start threads (unless we use a dedicated "main" thread when building). After a thread start, the browser thread's eventloop must run in order for new threads to start.
Done
On the branch:
- put all modifications under conditionals
- The runtime build should be under
/p:WasmEnableThreads=true - ref assemblies should use
FeatureWasmThreadsin project files andFEATURE_WASM_THREADSin C# code to conditionally include[UnsupportedOSPlatform("browser")]guards around multi-threading APIs, and include the ref assembly inMicrosoft.NET.WebAssembly.Threading - CoreLib uses
FeatureWasmThreadsandFEATURE_WASM_THREADSto defineSystem.Thread.IsThreadStartSupported. All other code should checkSystem.Thread.IsThreadStartSupportedto throw a PNSE. There should not be[UnsupportedOSPlatform("browser")]guards in CoreLib - EventPipe and diagnostics should use
FeatureWasmPerfTracingandFEATURE_WASM_PERFTRACING(and a constant?).
- The runtime build should be under
- Add separate
browser-mtandbrowser-mt-eventpipesamples. - Land the branch changes in
main
In .NET 7 RC2
-
Build and package:
- [wasm-mt] place multi-threaded wasm build into separate artifacts folders #68506 Completed as part of Add support for building WASM variants alongside single-threaded to the build system #71054
- [wasm-mt] The
browser-wasmruntime pack should pack both single- and multi-threaded builds. #68508 completed as part of Add support for building WASM variants alongside single-threaded to the build system #71054 - The
Microsoft.NET.WebAssembly.Threading.nupkgref assemblies package should be published to the dotnet7 feed
-
Libraries and interop:
- [wasm-mt] Add a System.Runtime.InteropServices.JavaScript.BrowserSynchronizationContext #69409
-
Need a hook for frameworks to identify the location ofWe set up an asset loading framework that handles these use cases [wasm] asset loading for workers #73484dotnet.js. Emscripten relies onmainScriptUrlOrBlobproperty on the module on the main threads to be set to the URL ofdotnet.jsso that it can locatedotnet.worker.js. Frameworks like Blazor sometimes renamedotnet.jsand/or move the wasm artifacts into subdirectories. Provide a hook for them to tell the runtime where to find the files.
-
AOT
- [Wasm] AOT support for threading-enabled runtime #70489
- AOT compiler task: add an option to control safepoint generation (wrap
MONO_THREADS_SUSPEND=coopmono-aot-cross environment setting) [mono][wasm] Add a 'wasm-gc-safepoints' option to enable the generati… #70520 - emit safepoints if threading is enabled. (we want one
mono-aot-crossthat doesn't emit safepoints for single-threaded wasm, but does emit safepoints for mt) [mono][wasm] Add a 'wasm-gc-safepoints' option to enable the generati… #70520
-
CI testing:
In .NET 8
...
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
arch-wasmWebAssembly architectureWebAssembly architecturearea-VM-threading-monodisabled-testThe test is disabled in source code against the issueThe test is disabled in source code against the issueos-browserBrowser variant of arch-wasmBrowser variant of arch-wasmtrackingThis issue is tracking the completion of other related issues.This issue is tracking the completion of other related issues.
Activity
[mono] merge wasm-threading-eventpipe into main (#68232)
TheXenocide commentedon Sep 7, 2022
Ooh, just came to check in on how things were going on the mono wasm side of this and came across this tracking issue. Nice to see this being tracked on the dotnet/runtime side now. It's good to see that the browser-wasm RID was the final answer on that particular design challenge, but I remember how much discussion there was about trying to avoid adding additional runtimes unnecessarily. Trying to make sense of the current state of these tickets, are we expecting that the browser-wasm runtime will be multi-purpose and have some convention for choosing subtypes, rather than defining new RIDs for multi-threaded and perf-trace package variants? Part of me feels like the multi-thread variant would be better served by its own RID if there are plans to support both (fundamentally different) runtimes for any extended period (e.g. reference assemblies/contracts can expose different supported surface areas at compile time rather than throwing runtime exceptions).
Is there a sense of how this will work for packaging and compile MSBuild conditions? It seems like WasmEnableThreads is rather narrow and probably only impacts the application build, not so much for libraries, NuGet packaging, etc. unless the desired result is for the compiler to be able to generate all variants automatically, but it seems like there would be significant design implications there, where performance and a variety of other factors would want to be able to provide different implementations for the different environments (e.g. concurrency-safe collection types could ignore concurrency without MT but might need to leverage platform-specific no-lock behaviors, etc.) Understandable if these aren't answered yet, just trying to get a sense of how these things intend to be differentiated by component developers between the runtime and consuming developers.
I ask here mainly because it seems there are multiple possible threads that seem appropriate. Feel free to move this comment or direct me where best to move the discussion. Otherwise, glad to see there's already some experimental support running now.
sajjadarashhh commentedon Sep 19, 2022
what happend if this feature not support with browser?
knight1219 commentedon Oct 12, 2022
How, if any, effect for this have on Task based threading? If one creates multiple HttpClient.GetAsync tasks and schedules them using Task.WhenAll, will all tasks run in parallel on their own threads? Does each task need the ConfigureAwait(false) to be set?
If that is the case and you are sharing this code between Blazor WASM and Blazor Hybrid, are there any repercussions in MAUI by doing that?
kg commentedon Oct 12, 2022
Threading allows tasks to run on multiple threads, yes. Things that interact with browser APIs like HTTP are a more complex scenario, because browser APIs have thread affinity (think the nightmare of COM apartments, but worse)
baywet commentedon Nov 7, 2022
The Blazor needs to provide dotnet.worker.js as a js-module-threads asset list item probably needs its own issue for the following reasons:
The error message for visibility
Trying to poke around by finding dotnet.worker.js and copying it with the right name doesn't seem to be any use as the referencing code really expects it to be part of the bundle.
12 remaining items
pavelsavara commentedon Nov 9, 2023
I updated MT tracking issue #85592
tebeco commentedon Jan 12, 2024
hello,
Anyone know if this meta tracker could updated for net8 ? now that the release is done ?
I've seen a question on the C# Discord server, search engine found this issue as the first search result, but I can't seems to tell what changed from net7 to net8 from this tracker
pavelsavara commentedon Jan 29, 2024
There were mostly low level steps toward multi-threading during Net8, but it's not supported in Net8.
For the current progress on Net9, please have look at #85592
tebeco commentedon Jan 29, 2024
Ah cool, thx a lot for the next release tracker :)
This image is why I asked,
It was usefully showing net7.0 - RC2
and also showing net9.0 milestone, but is missing anything related net8.0 that being ultra small or bigger type of release
Now i understand that there's another one regarding Net9.0
The question is ... from an outsider point of you it would be nice to have this issue either
I'm not trying to be picky, I'm just hardly able to try to follow up cross release "Epic size" feature when there's a lot of cross over that are not listed.
There's probably other ways i suppose but this ticket title seems like the perfect candidate to list the "per release"
sbeji-fab commentedon Dec 16, 2025
Are there any updates regarding this feature?
Its been silent for long time
OptimusPi commentedon Mar 28, 2026
bump :(