-
Notifications
You must be signed in to change notification settings - Fork 10k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make Blazor WebAssembly work on multithreaded runtime #54365
Comments
Regarding the non-blocking behavior of JS interop.
Regarding blocking
In last month or so, we switched the implementation of JS interop dispatch from
I'm not clear how you would ship 2 different flavors of the components, if you start using |
Are you really going to enable multi-threading at the cost of performance, serialization round-trip can potentially greatly reduce the amount of components displayed on screen before it's unresponsive to users, I saw UI frameworks using blazor having their VirtualDOM and render their VirtualDOM in a for loop recognizing the elements in the VirtualDOM and creating a component for every elements, these framework allows dev to compose and generate a large number of components, potentially every button has multiple components and every cell in a calender has multiple components and that is adding up to a lot components for blazor to render quickly, if blazor is sacrificing a lot performance in large quantity of components being rendered, I worry it would be cutting off an entire line of UI frameworks that compose the UI their way to use .NET through blazor and that's a crowd of audience |
No, we're not open to sacrificing any performance from the single-threaded build. This was mentioned in the issue description:
|
This shows how many scenarios would have to be avoided if we don't allow blocking .Wait It seems that's too many.
This enables blocking Our team conclusion so far is, that we wish to disable synchronous |
it would be good to make following
So that we could disable support for synchronous JSExport completely. If we are unable to do that, please be aware that any managed code inside of those calls will
|
Hi @SteveSandersonMS and team, Our production Blazor app is working and performing nearly perfect! I'm sure Blazor WASM multi-threading is difficult due to violating single-threaded assumptions. As a short-term solution ... Have you considered starting Blazor on a single non-blocking background thread? SSR is working beautifully... only prob is Total Blocking Time (TBT) from Blazor.start() blocking UI thread. https://eatinglove.com/recipe-boost/1096211/The-Easiest-Beef-Pho Presumably Blazor could start() on a background thread, then marshal to UI thread when WASM state is completely loaded? At worse DOM flickers but TBT should be reduced to under a second for normal scenarios. While Blazor background thread loads, DOM simply behaves as normal HTML page. This might be favorable performance profile for any app optimized for SSR. Would love to hear your thoughts! |
Here is a demo how to start wasm single-threaded runtime on separate thread dotnet/runtime#95452 |
has anyone demo calling Blazor.start() from Web Worker separate thread? Not sure it's even possible but great performance enhancement. |
I don't think it will work because i believe you cannot access DOM directly from Web Worker. They may try make "proxy" to streamline changes (possibly use same technology as for server-side interactive mode?). But hard to say how fast it would be. And it would be nice, BUT when they actually introduce multi-thread support for blazor this mode becomes obsolved (?). Also, this change would only demo because it will break many nugget packages. |
Currently, Blazor WebAssembly's internals make use of the historical JS/WASM single-threadedness guarantees as a performance optimization. For example:
At first glance, it appears to work with
<WasmEnableThreads>true</WasmEnableThreads>
, but that's a mirage: it does not guarantee correctness in that mode, because the core single-threadedness assumption is violated. For example, JS might raise event 2 before event 1 finished processing, and by the time event 1 is done, there might not even be an event 2 handler any more and then you have an error.Why we're only just encountering this now
Ensuring correctness
We've already solved all these problems in our other hosting environments, Server and WebView, because they've always been innately asynchronous from the beginning. We would need to generalize/port all these mechanisms so they are shared with or copied by the WebAssembly renderer, JS interop, eventing system, etc.:
UpdateDisplayAsync
returns aTask
that doesn't complete until the JS side sends back an explicit acknowledgement of that renderbatchApproach
As a broad strategy, I think we can:
WebRenderer
subclass called something likeAsyncWebRenderer
that holds the common logic around serializing renderbatches and accepting the async renderbatch acknowledgements from JS. This can then be used by all of Server, WebView, and multithreaded-WebAssembly.I suspect it's not necessary to have two different builds of
Microsoft.AspNetCore.Components.WebAssembly
. The total amount of code that should differ between the threaded and not-threaded won't be very much. I expect we can just have two differentRenderer
subclasses and some if/else branches in the JS code.The text was updated successfully, but these errors were encountered: