Need Blazor Wasm Performance Improvement on CPU Intensive Calculations
Asked Answered
S

8

9

I have a c# WinForms app that I have been converting to Blazor Wasm. It needs to perform a set cpu-intensive calculations (i.e. no IO or UI interaction) after most user inputs. The calculations entail repetitively (30-50 times) invoking a number of methods in a set of 25-35 C# class objects depending on the scenario. The same calculation code runs in the WinForms and Blazor apps.

I am seeing a ~20 fold degradation in performance under Blazor (e.g. 350ms in WinForms vs 7000ms in Blazor). Does that level of degradation make sense? Is a big part of it inherent to running within a browser? Is Blazor Wasm a big part of it somehow? I have confirmed that the degradation is spread across the calculations, not in isolated spots. Are there any ways to significantly reduce the degradation? The objects that perform the calculations could be put in a class library if that might help for some reason.

I have posted this question in the AspNetCore Discussions in GitHub, but have had no responses. I am using VS Community 2019 v16.8.2, AspNetCore 5.0, and Chrome v

Thanks. Steve

Sebi answered 28/11, 2020 at 17:7 Comment(5)
Yes that's expected perfomance degradation. Blazor wasm runs in interpreter mode right now (though subject to change in near future), which means only runtime itself is compiled to wasm. Then that runtime downloads and interprets IL from your dlls, and this is quite slow compared to scenario where your assemblies are compiled directly to WASM. Soon it should be possible to compile to WASM directly, and it should provide some perfomance improvement (though it will not reach the level of native .NET application anyway)Imperfection
Ugh. I was hoping that wouldn't be the answer. I have a fair amount of time to wait for compiling to be implemented, but it would help to have some perspective on how much degradation versus native .NET there might be after that improvement. A factor of 2-3 times slower might be viable (perhaps with some logic compromises), but 5+ may be a show-stopper. Anyway, thanks for the perspective.Sebi
Hard to say (for me) what speedup exactly this will achieve, might be possible that it will be just 3 times slower indeed. However, Blazor wasm also doesn't support multi-threading, even though WASM itself does (at least in some browsers, and more will support it eventually). While compilation directly to wasm is around the corner - I'm not aware of any plans regarding multithreading in near future. And for CPU intensive computations that might give even more power to native .NET.Imperfection
I realise this is a couple of weeks old, but thought I would just check whether your calculations involve any asynchronous calls - are you awaiting anything? Do you update the UI during the calculations? Are you debouncing user input, preventing calculations running simultaneously on a single thread over async?Outpoint
The calculations do none of what you ask. It’s pure cpu processing. There’s an instantiated singleton that controls the calculations by invoking various methods in a set of 40 or so objects. All of these objects are instantiated on startup and reused each time a new round of calculations are required.Sebi
P
3

This is a very late response to this question, but would web workers help to resolve this issue? This should bring some multi-threaded capability to the table. I can't speak to implementing this myself, but here's one helper library that appears to bring this into Blazor fairly easily:

https://github.com/Tewr/BlazorWorker

In native JavaScript you can access the core count of the browser through the Navigator Api:

const coreCount = window.navigator.hardwareConcurrency;
console.log(`Your computer has ${coreCount} cores!`);
Phox answered 22/1, 2021 at 16:41 Comment(1)
Thanks for the suggestion. I can see how it might be helpful for some needs, but in my case, the calculation needs to be fully synchronous.Sebi
S
2

Blazor now supports ahead-of-time (AOT) compilation of the whole codebase to WASM, not just the runtime. This option is only available in Release build. (See: https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/webassembly?view=aspnetcore-6.0) This improves the performance over the previous model of running the .NET assemblies in a WASM interpreter, which is still the model in Debug build.

Saw answered 15/6, 2022 at 15:20 Comment(0)
J
1

Blazor Wasm does not support multi threading + frequent actions like mouse event handling are very 'heavy' for processing in a browser. Try to push action handlers in a queue and process them in background.

Judicatory answered 28/11, 2020 at 19:54 Comment(1)
I'm afraid I may need to completely rethink the way it works from the user's perspective if direct compiling doesn't improve performance enough. I'm afraid pushing things onto a queue for background processing isn't a solution. Thanks for the thought anyway.Sebi
N
1

If you have a .NET backend, you can easily execute the code there instead. With a few milliseconds overhead, you get almost the same performance as before. One of the benefits of using the same language on both sides.

Northumberland answered 18/12, 2020 at 19:24 Comment(1)
I appreciate the thought and may have to go down that path. My hope is to make/keep the app client-side only for several reasons, the primary one being able to claim that the user’s info is kept entirely on their computer. Technically, the app persists it in an IndexedDB. If that proves infeasible due to performance, then I will consider going client-server.Sebi
M
0

There are two hosting models with Blazor: Blazor CLient and Blazor Server model. Details here: Blazor Hosting Models I would expect such degradation if you use Blazor Client side but would not expect it in Blazor Server.

Moreland answered 2/12, 2020 at 14:0 Comment(0)
H
0

If it's purely computational then why not use a WASM language (e.g. Rust) and just invoke it from JavaScript? As Josef pointed out you could also use server side Blazor or simply invoke a web service end point.

Harping answered 2/12, 2020 at 14:32 Comment(2)
Thanks to all for the suggestions. There is a fairly hefty amount of code already written and debugged in C#, so converting to some other language is not a very attractive option. Shifting to a Blazor Server model is an option, though I have been trying to avoid that due to the additional variables that adds. I started down the Blazor Wasm path for both of these reasons, C# and client-side only.Sebi
I'm hoping compiled Blazor will work well enough. I have posted an issue in AspNetCore GitHub (github.com/dotnet/runtime/issues/45363) to see what those who are managing the development have to say.Sebi
K
0

It may not be fair to compare a program running in a Browser against a program running natively in OS. I rather compare Blazor against JavaScript as they both run on Browsers. The advantage of a program that can run in Browsers is that it can run in most devices, from PC to most mobiles. Besides, it is in a form of MSIL, which is harder to reverse engineer than JavaScript. However, there is a price to pay, which is performance (MSIL in Mono -> WASM -> Native).

Keshiakesia answered 17/12, 2020 at 13:55 Comment(1)
Thanks for the perspective. I am comparing the WinForms vs Blazor performance because I have that code, not a JS version of it. In the end, what I need is much better performance under Blazor.Sebi
S
0

As time has marched on, .Net and WASM have improved such that the initial problem I was seeing is now gone. My WASM app now has a user experience that's as fast as the WinForms version.

The key has been to publish the app on .Net 8 or higher with AOT compilation. Put the directive below in a Property Group in the project file. To edit the project file, double click the project name or right click it and select "Edit Project File."

<RunAOTCompilation>true</RunAOTCompilation>
Sebi answered 23/7 at 14:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.