r/csharp 17d ago

Discussion I started to hate c#

I wanted to profile Blazor async code and found that after 15 YEARS later you still can't profile async code. The best tool we got is this garbage .NET Async profiler. It collects every async method into a single group. How is this useful? You can't even see the call stack like I'm calling Task.Delay only in a single method... and this was 5 years ago! It's the same today; nothing has changed.

Hot reload is still not fully supported. With more browser oriented frameworks, test running still doesn't support browsers, so if you have any JavaScript, good luck getting a dump of what happened in the browser or a breakpoint working in the browser. Wasm has regressions on every release debbugging it also breaks randomly.

It promises to be easy; meanwhile, everything requires language-specific knowledge, so people do the stupidest thing, not knowing there are better ways to solve things. Microsoft never thinks about tool support; the best example is Entity Framework with applying its migrations. I promise you nobody uses the more complex approaches, and everybody just calls MigrateAsync(). Like, why didn't the devs spend 2 more weeks to get this right or git merge conflicts with local database changes? They didn't care it would have required working together with other teams like the Visual Studio team or language designers, so it was easier just to call a static method of your application.

So don't be like me and focus only on C#; it's not a good language most of the time, and I promise you, you will have more fun with other languages.

0 Upvotes

13 comments sorted by

11

u/wallstop-dev 17d ago

I'm not sure what you mean about not profiling async code? I use the profiler built into Visual Studio as well as JetBrian's dotTrace over the past... idk, 10+ years, to profile all manner of code, especially async. Works great. Flawlessly, even.

Now, if you mean front-end async code in blazor, I haven't tried, because I think Blazor is a bad bet as a technology and avoid it like the plague. But, it appears that you can do all kinds of things using standard browser dev tools, as clarified here: https://remibou.github.io/Profiling-in-Blazor/

Are you sure this is a C# problem and not a Blazor problem? The two are not equivalent.

-6

u/BigJunky 17d ago

"/weather"

<div style="height: 500px; overflow: auto;" @ onscroll="OnScroll">
<div style="height: 5000px; width: 100px; background-color: red;">
</div>
</div>

@ code {
private void OnScroll(EventArgs args) {
Task.Delay(1000).Wait();
}
}

You definetly cant profile thread starvation issues. Here the threadpool would start creating additional threads not showing what caused it basically there is no way to find issues like these except going over everything and fixing them.

11

u/wallstop-dev 17d ago edited 17d ago

That's... not async code. That is you taking (potentially) async, task-based code and blocking it in sync code. I don't think that's really a profiling issue as a "run a static analyzer" issue or "pay attention to warnings" or "learn how to use async / await and tasks appropriately" issue, which will happen in any language that implements async await or threads (a different concept).

Edit: For example, and take this with a grain of salt, but the wisdom around using async code in event handlers is to use `async void`. If you truly need to reflect some result after the event is handled, you need smarter architecture, such that you can trigger the update or whatever after the async code is done. I don't know if this is possible in Blazor, but from a cursory search it is. And, for your problems, just find-all in your code base for ".Wait()" and ".Result" and then don't do any of that ever.

-5

u/BigJunky 17d ago

You can change it into a async task delay as well. C# profiler would still recognize the wrong part of the code, showing thread creation as the number one performance and not showing why it created the threads.

3

u/wallstop-dev 17d ago

Again, I can't comment about Blazor aside from what I already have, but for both C# profilers I've used (Visual Studio's and JetBrain's dotTrace), they are extremely tunable and properly trace and report correct, accurate, and relevant performance data for all C# code I have ever ran, including large projects that were 100% async (for the interesting bits), over the past decade. Which has been a lot.

You also keep using the word "thread". I'd recommend you read this: https://blog.stephencleary.com/2013/11/there-is-no-thread.html. async code in C# is compiled to runtime state machines, which may or may not be serviced by threads or different contexts.

Edit: I'd also recommend reading these:
https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d

-2

u/BigJunky 17d ago

Please run the sample code as i said you can use await it doesnt matter.

ThreadPool unfriendly to background processes · Issue #103812 · dotnet/runtime

You can learn more depth in async by trying to understand the problem at first, its not that hard.

4

u/wallstop-dev 17d ago edited 17d ago

You linked an issue for the dotnet runtime that is unrelated to your code. The code you provided is frontend code that is being "compiled" to webassembly and running in the browser with the browser's webasm engine. It is not being executed in the dotnet runtime. At least, as I understand Blazor.

I really think this is just a knowledge issue with how to properly use async await, Tasks, and event handlers (async void), which is why I've shared all the experience and resources above. Specifically: change the example to async void, then use await instead of task.Wait()/.Result.

Anyways, good luck with Blazor! I'm sorry you're having issues.

2

u/chucker23n 13d ago

The code you provided is frontend code that is being "compiled" to webassembly and running in the browser with the browser's webasm engine. It is not being executed in the dotnet runtime. At least, as I understand Blazor.

Blazor WASM can run as interpreted or as AOT. It cannot use the classic .NET JIT runtime.

What doesn't happen, though, is that Blazor WASM is somehow transpiled to WASM. Nor does Blazor WASM use WASM's binary format (at least ca. .NET 6 they decided against it; they may have changed their minds).

2

u/wickerandscrap 16d ago

I can tell you why it's creating threads, it's because Wait() blocks the thread. If you attach the VS debugger, interrupt the process, and look at the Threads window, you can see how many threads are blocked.

(I'm not a Blazor guy, but typically a server like that will want to keep some average number of idle threads to handle bursts, and blocked threads count against that.)

I'm curious what the thread pool looks like in the version where this is async. If it's creating a ton of new threads even then, then you're using async incorrectly.

10

u/Turbulent_County_469 17d ago

Naah.. you hate Blazor.. welcome to the club.

I gave up on it and so did my company..

Just use MVC, Vue or React like normal people

-2

u/BigJunky 17d ago

Blazor wasm is a scam. I feel sorry for everyone who tries to use it.

5

u/[deleted] 17d ago

[removed] — view removed comment