'Stop Using Async Await in .NET to Save Threads' | Code Cop #018

preview_player
Показать описание


Hello, everybody, I'm Nick, and in this video of Code Cop I will take a look at a newsletter post on LinkedIn that contained some pretty bad advice regarding Lists, memory and async await!

Don't forget to comment, like and subscribe :)

Social Media:

#csharp #dotnet #codecop
Рекомендации по теме
Комментарии
Автор

Stop using your PCs, save the electricity

antonmartyniuk
Автор

We actually had thread pool exhaustion in production. The reason was an Oracle-DB with EF (Core) paired with async/await. Oracles provider doesn't support true callbacks and just blocks threads, until the database operation completes (basically Task.Result under the hood). So although async/await is not the issue per se, in combination with that oracle garbage it caused massive issues for us

EikeSchwass
Автор

"Don't leave your house, you might get hit by a car"

klocugh
Автор

normal brain: List<object>
galaxy brain: List<dynamic>

(old brain: ArrayList)

tymurgubayev
Автор

11:08 "...David Fowler, who's basically, God..."

Truer words have never been said 🙌🏽

maacpiash
Автор

"Seed with random number" while there is 420 will never not crack me up :D

NickMaovich
Автор

TLDR; always use "using" with disposable objects when you can (unless you're doing something very fancy and you're fully aware how to handle these specific cases).

The idea behind "using" with disposable objects is to prevent memory leaks in several ways:
1 - people not always know what is needed to be done for a proper object cleanup, and even if they think they do, because maybe they looked inside the source for that particular disposable class, it might change in the future. In the example of sql connection it might no longer be enough to call Close(), because you're are not aware that package developers added something more in the dispose method.
2 - people might not be aware of things which can throw exceptions before they manually clean the object, thus it can lead to memory leaks with dangling handles to unmanaged resources and etc.
3 - properly implemented dispose pattern also makes destructor to call dispose method, thus GC will call it anyway for undisposed object and this can result in some unexpected behavior (this depends more on the implementation and ownership of disposable objects).

Chainerlt
Автор

Amusingly, the MS .Net 8/9 page suggests you DON'T use ArrayList but List<object>. My guess is, a lot of people used List<object> because they don't know ArrayList exists, and i won't hold it against them because IT IS counter intuitive, and now the .Net team is simply doing all work going forward on List<object> and ArrayList will be left as is.

ErazerPT
Автор

in addition to the issues with point 1), there would be no boxing involved when storing strings inside of a List<object> as strings are reference types (even though they do have some behaviours from value types), so even that example does not work

pali
Автор

I only used List<object> once when I wasn't sure what I was getting back from reflection. That was before I learned better ways to handle that situation.

ChristopherJohnsonIsAwesome
Автор

Using List<object> instead of List<string> when you know only strings will be stored doesn't make sense. However, there are many cases where List<object> or object[] makes perfect sense in .NET right now, and in fact there's no other way at times.

It seems some devs deal with a limited amount of code paths/scenarios to say they can't *ever* see any usage beyond old code, or have never used it.

Just off the top of my head, if you have any code that needs to collect data to invoke various methods via reflection, List<object> is a must for collecting values to pass into those methods.

There are other scenarios where one may build a specific serialization background service to conform objects for audit or storage where strongly typing the class makes no sense.

There are several other scenarios that make sense off the top of my head also, but I'll move on.

List<object> should only be used when it makes sense. It should never be used when the type is known, or if an interface or base class type can be used for differing types. Obviously, boxing value types *unnecessarily* should be avoided.

ThomasJones
Автор

What's comforting to learn and know is that over language's time, they've been optimized.
And what's good to remember is that during compiling. They've been so smart as to make the compiler run through the code and change your code, internally.
To what it finds more optimal. So if you use a switch statement. And it thinks "mmmh I don't think so my dude". Then it will change it to if statements if it finds it more optimal in that situation.
It makes writing fast code much easier and you get a smaller gap between safe but not optimal code, and unsafe memory but more flexible and fast code like C++.

magnusm
Автор

I use IEnumerable<dynamic> often, for the specific case of executing SQL with Dapper for which the nature of the results are not known at compile time, but I have never seen a List<object> outside of deep library corner cases.

CharlesBurnsPrime
Автор

I actually have used List<object> before.
I was converting some old codefrom ArrayList to List<> so I could actually understand what was going on, and there were collections that were being used for 2 or more distinct and completely contradictory types.
I didn't want to deal with that at the time, so ArrayList -> List<object> it was for those.

On the other hand, that refactoring also revealed about a dozen bugs before I even got around to the changes I had wanted to do, lol.

I have also used it in the form of Dictionary<string, object> when I was building a thing to load a configuration file, and use said configuration to build a completely arbitrary nested data structure.
The result of which was serialised into JSON to send off elsewhere.

billybob
Автор

#2 used to be an issue in the CLR for XNA Game Studio on the xbox 360. Using a foreach would do an allocation for each item in your collection, triggering the garbage collector far more often than you'd want. for loops were the solution. Of course that was 2009 and things are much better now.

viper
Автор

try - catch, definitely. I write tons of I/O stuff and exceptions don't always happen when you think they will. For example, you can test a file to see if it has locks (or whatever), then believe that everything will be okay when you start reading it (big file), half-way in the read, a network card crashes (or drive hiccups, or what-have-you), then your IF check is worthless, and your program crashes because you didn't use exception handling. Believe me, stability is FAR more important than SPEED. A slow program is a nuisance, but a crashing program can be a career changer!

davestorm
Автор

When the advice is so outrageous that your pullover transforms into a t-shirt

Drachencheat
Автор

I used List<object> in scenario where list was used as bucket for various objects which stored some results of various part of application and for some specific operation looped through that list checking type and perform final calculations accordinly. It was back in Window Forms and C#4.0, I think. However, I would rather say that I did it this way because I didn't know better one back than.

bslushynskyi
Автор

Actually ...

using (...) is preferable over manually disposing objects.
In case of exceptions, the scared unmanaged resources (for instance, db connections) are given back or closed,
to be used by other waiting tasks.

ryan-heath
Автор

List<object> = NO!

Autocomplete/refactoring will take care of the hassle of creating the new class(es)...use it. Create that class with a name that makes sense, then populate that nice new reference type with properties as you need...

itsallgravy_
join shbcf.ru