|
raminasi posted:I sure wish that whoever wrote that originally had cared about performance. The fact that someone doesn't realise that repeated naive string concatenations will result in bad performance doesn't imply that they don't care about performance. It's surely a pretty common trap to fall into at least once in a programming career (I know I have, but in my case it was picked up before the code was being used in anger) - although surely it's more usual to run into it by writing a loop that updates the string, rather than just loads of concatenations, since then the problem can be missed when working with toy examples. If someone is repeatedly making that mistake, as opposed to making it once and taking it as a learning experience, there's something a bit wrong.
|
# ? Mar 2, 2022 11:56 |
|
|
# ? Jun 6, 2024 13:09 |
|
I've had the most success in keeping code reasonably performant and readable with the advice of "use the currently recommended standard library API first". Everyone has their own definition of "easy" and "simple" (and often that definition is "stuff I already know") but it's hard to argue with the 1st party .NET docs saying "use async/await, not .Wait() or .Result" or "use DateTimeOffset instead of DateTime". In the case of string concatenation, I think you can make the case that all of these are fine if you follow "use the currently recommended standard library API first": C# code:
C# code:
ThePeavstenator fucked around with this message at 04:06 on Mar 3, 2022 |
# ? Mar 3, 2022 04:02 |
|
The right answer is to use a log method that accepts a format string, so it doesn't even need to do the formatting if there's no log sink connected that would receive the message.
|
# ? Mar 3, 2022 05:40 |
|
Someone needs to tell Microsoft that when someone types "Debug" into the Visual Studio C# text editor and then types a full stop, they do not in fact want the "Debug" they typed to be changed to "DebugSettingsReader". Nobody has ever wanted that.
|
# ? Mar 3, 2022 17:32 |
|
Jabor posted:The right answer is to use a log method that accepts a format string, so it doesn't even need to do the formatting if there's no log sink connected that would receive the message. Bingo -- string.Format has a place, and that's in resx files. If you are hardcoding your format string, that needs to be something else, because string.Format *is* slow. code:
edit: .NET6 added. I thought I was supposed to get a freebie insta fucked around with this message at 18:45 on Mar 3, 2022 |
# ? Mar 3, 2022 18:14 |
|
The compiler (pre- and post-.NET 6) will convert an interpolated string to a string literal or a string.Concat call if the parameters line up, so it isn't all bad. The main thing in .NET 6 is fewer heap allocations for the non-trivial cases (edit: and exposing some types that allow methods to consume interpolated strings and do stuff themselves).
No Pants fucked around with this message at 19:47 on Mar 3, 2022 |
# ? Mar 3, 2022 19:38 |
|
No Pants posted:The compiler (pre- and post-.NET 6) will convert an interpolated string to a string literal or a string.Concat call if the parameters line up, so it isn't all bad. The main thing in .NET 6 is fewer heap allocations for the non-trivial cases (edit: and exposing some types that allow methods to consume interpolated strings and do stuff themselves). I know the compiler converts simple, compile-time string concats into a string.Concat call -- but I'm seriously surprised it can't figure out how to do that for the Interpolated example in my code.
|
# ? Mar 3, 2022 21:00 |
|
insta posted:I know the compiler converts simple, compile-time string concats into a string.Concat call -- but I'm seriously surprised it can't figure out how to do that for the Interpolated example in my code. iirc interpolation uses the current thread culture at runtime, or something like that
|
# ? Mar 3, 2022 21:18 |
|
redleader posted:iirc interpolation uses the current thread culture at runtime, or something like that Looks accurate -- changing my code above to use string Digits = "eight" gives the following: code:
|
# ? Mar 3, 2022 22:37 |
|
insta posted:I know the compiler converts simple, compile-time string concats into a string.Concat call -- but I'm seriously surprised it can't figure out how to do that for the Interpolated example in my code. Yeah, I was talking about $""-type string interpolation. The earlier behavior where $"" is a shortcut for string.Format was more desirable because using string.Concat would allocate an extra string for the formatted int.
|
# ? Mar 3, 2022 23:40 |
|
Now do the benchmarks with something more complex than that extremely trivial example. StringBuilder is obviously the wrong solution for that use case.
|
# ? Mar 3, 2022 23:53 |
|
zokie posted:Now do the benchmarks with something more complex than that extremely trivial example. I'm happy to try them out if you have suggestions. This was the example from earlier in the thread.
|
# ? Mar 4, 2022 00:27 |
|
Hey, insta, what in the world are your workloads that you need to care so much about the minutiae of string concatenation?
|
# ? Mar 4, 2022 23:05 |
|
.NET 6 can improve interpolated string perf only if the interpolated string is used as an argument for an "interpolated string builder" parameter. This compiles down into basically a sequence of append calls for all the literal and interpolated chunks of data in the interpolated string. A bunch of the standard logging/building methods take such arguments now in .NET 6, but if you convert the interpolated string to 'string' as in your benchmark, you won't see any of the perf improvement from it.
|
# ? Mar 5, 2022 07:34 |
|
The C# 10 compiler can lower an interpolated string to using the DefaultInterpolatedStringHandler type, too. Like this C# code:
C# code:
|
# ? Mar 5, 2022 15:37 |
|
Munkeymon posted:Hey, insta, what in the world are your workloads that you need to care so much about the minutiae of string concatenation? I do a lot of backend data ETL processing stuff, but mostly in general wherever I go as a job I'm usually tasked with solving performance problems. There's a lot of developers who simply don't understand that similar constructs are wildly different in performance, especially once you scale it up to the millions or billions of records in production. If you work in a team who does understand that inside and out, I'm glad for you. There's usually a couple things I see that are easy to change on the C# side that dramatically improve performance, List.Contains when they really wanted HashSet.Contains, string concatenation, .Any() vs .Count() > 1, etc. I guess I don't understand the call to wait until it's slow before you write the faster code? If you really want .Any(), but you see it as .Count() > 1 in the pull request, why would you not call it out right then? Why do you need to wait for the profiler to call that a hot path?
|
# ? Mar 6, 2022 20:18 |
|
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.
|
# ? Mar 6, 2022 20:38 |
|
insta posted:.Any() vs .Count() > 1, etc. Defect spotted
|
# ? Mar 6, 2022 21:15 |
|
insta posted:If you really want .Any(), but you see it as .Count() > 1 in the pull request, why would you not call it out right then? Why do you need to wait for the profiler to call that a hot path? Those aren't equivalent although I get that you mean > 0. However, IIRC it will be optimized to use the Count property if the underlying collection has it so it might not even be a problem in the first place.
|
# ? Mar 6, 2022 21:21 |
|
SirViver posted:Defect spotted rageposting got me
|
# ? Mar 6, 2022 21:24 |
|
Man I wish we had performance problems as subtle as that. I'm dealing with legacy code continuously being glued together in new and terrifying ways, and we keep finding code that performs a database lookup per record, which itself usually comes from an initial database lookup.
rarbatrol fucked around with this message at 21:43 on Mar 6, 2022 |
# ? Mar 6, 2022 21:41 |
|
rarbatrol posted:Man I wish we had performance problems as subtle as that. I'm dealing with legacy code continuously being glued together in new and terrifying ways, and we keep finding code that performs a database lookup per record, which itself usually comes from an initial database lookup. ah, you’re me, good to know.
|
# ? Mar 6, 2022 22:25 |
|
I’ve been using .Any() versus .Count > 1 (or .Count() > 1 for IEnumerable) since it was actually recommended that I do so by Intellisense (or Intellicode, some kind of “Intelli…”). Should I not? Also, I try not to hard code (some) strings preferring .resx files, so end up with things like C# code:
Should I be using something different? string.Concat for example? TIA
|
# ? Mar 7, 2022 00:36 |
|
rarbatrol posted:Man I wish we had performance problems as subtle as that. I'm dealing with legacy code continuously being glued together in new and terrifying ways, and we keep finding code that performs a database lookup per record, which itself usually comes from an initial database lookup. Oh man that reminded me. Some time ago we received a project made in C# that we were supposed to add new stuff to. To get around the natural limitations wrt cross-database queries and get nice simple LINQ queries, they'd tacked a ToList() to every DbSet call. Before any applicable Wheres, of course. We didn't fix every instance, because it was out of scope and out of budget and frankly I'd've left it as-is as a "go gently caress yourself", but it was so drat slow to test I'd have to fix some anyways just to get things done in time. Kyte fucked around with this message at 00:43 on Mar 7, 2022 |
# ? Mar 7, 2022 00:41 |
|
LongSack posted:I’ve been using .Any() versus .Count > 1 (or .Count() > 1 for IEnumerable) since it was actually recommended that I do so by Intellisense (or Intellicode, some kind of “Intelli…”). Any() is the correct way to check if a collection is empty or not. Count() requires it to iterate the entire collection to perform the comparison, even though knowing there's a single thing in there is enough. This is very bad for lazy loaded collections. Count() will skip iterating and go check the Count property if it's a materialized collection like List or ICollection that has a Count property, but Any() is still safest and best to use. And remember, Any() is equivalent to Count > 0, not 1. Aldo Count is fine -- it's a property with no overhead. Count() is a LINQ extension method that will iterate the entire collection to get the count of items in it, except in the aforementioned scenario I mentioned above. New Yorp New Yorp fucked around with this message at 01:38 on Mar 7, 2022 |
# ? Mar 7, 2022 01:36 |
|
New Yorp New Yorp posted:And remember, Any() is equivalent to Count > 0, not 1. Of course it is, and I knew that Also, thanks for your response. I never really considered the implications of Count(), but upon reflection (no pun intended) it makes sense. LongSack fucked around with this message at 03:40 on Mar 7, 2022 |
# ? Mar 7, 2022 03:34 |
|
LongSack posted:
Yeah I got it wrong in the rant, and decided to keep it since it was quoted like 5 times. There are many things like this, that show up in other constructs you wouldn't think of: str1.ToUpperInvariant() == str2.ToUpperInvariant() vs string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase), I find this all the time, for random reasons. On the surface, they look functionally equivalent. The first one allocates 2 new strings and will traverse the length of both of them to build the culture-invariant uppercase version, then do an equality check. The second will first short-circuit by testing length, then will go character-by-character with an ordinal case-insensitive comparison (which itself is faster than invariant culture, if that's applicable), and fail as early as it can. I'm going to stick with my method of converting the former to the latter, even if they're not on a hot-spot in a profiler. There is no case where the first one is better, and it will prolong the time until it does show up on a hot-spot in a profiler. It's something I can do on auto-pilot as I'm in the rest of the code, and if nothing else it helps me read it better since "string.Equals" is more appropriate to the logic instead of "ToUpperInvariant()"
|
# ? Mar 7, 2022 22:00 |
|
I don't really deal with ASPNet much, but i'm having a simple issue that I'm hoping someone knows what i'm doing wrong. I'm using RestSharp to try to hit a API and then trying to serialize that data with the following:code:
code:
code:
|
# ? Mar 8, 2022 01:17 |
|
worms butthole guy posted:The issue i'm running into though is that whn I try to run it, I get a Internal Server Error of the following: You are currently casting the json data to a singular instance of Catdata. code:
code:
|
# ? Mar 8, 2022 01:37 |
|
insta posted:Yeah I got it wrong in the rant, and decided to keep it since it was quoted like 5 times. There are many things like this, that show up in other constructs you wouldn't think of: The relative efficiency of the two isn't nearly as relevant as the fact they are not actually equivalent. Some languages do weird things with case conversions. ToUpper == ToUpper is less correct than Equals(IgnoreCase).
|
# ? Mar 8, 2022 07:22 |
|
Freaksaus posted:You are currently casting the json data to a singular instance of Catdata. Thank you for this answer! It got my program running but now when I run it I get: code:
|
# ? Mar 8, 2022 14:45 |
|
worms butthole guy posted:Thank you for this answer! It got my program running but now when I run it I get: That's normal. A List<T>.ToString() gives you that, since it doesn't (want to) know how to convert the contents to a string. Options: 1) Create a DisplayTemplate for CatData and then use @Html.DisplayFor(list) (it will automatically iterate across the list) 2) Create a DisplayTemplate for CatData, then foreach across the list and use @Html.DisplayFor(item) (if you want to customize the stuff around/between each item 3) Use JsonConverter.Serialize() to get a JSON representation you can throw to the screen. 4) Roll your own thing using foreach and whatnot.
|
# ? Mar 8, 2022 14:56 |
|
Kyte posted:The relative efficiency of the two isn't nearly as relevant as the fact they are not actually equivalent. Some languages do weird things with case conversions. ToUpper == ToUpper is less correct than Equals(IgnoreCase). That's why I said ToUpperInvariant(), and any case I've seen it used has been where they are just trying to compare strings like database column names or something. I'm seriously jealous of all of you who get to work with nothing but absolute geniuses in C# and never inherit code with any of these issues.
|
# ? Mar 8, 2022 16:31 |
Your team, a team of intellectuals: Have we considered doing a benchmark test of string concatenation methods to identify the most efficient way to generate our log files? We could increase performance by up to 4%! My team: code:
|
|
# ? Mar 8, 2022 17:34 |
|
Kyte posted:That's normal. A List<T>.ToString() gives you that, since it doesn't (want to) know how to convert the contents to a string. Thank you. My complaint about ASP.NET is that this stuff isn't ever really explained well and you have to figure it out on your own or ask people. It's also feels like a different programming language at times from C#
|
# ? Mar 8, 2022 18:00 |
|
What do people think of Umbraco? After struggling so much with DB stuff in my last learning project I kinda like the idea of trying a CMS that will handle all that stuff for me for a while. But it looks like it's very much geared towards old school blogs and ecommerce sites rather than anything "app"-like. Am I gonna be fighting against it if I want to do something that's a bit more like an SPA? Is it worth trying out as part of a general .NET / C# learning journey, or is too much of its own little ecosystem to be widely applicable? Is it a good thing to have for job prospects? Any thoughts appreciated. e: actually reading and thinking a bit more maybe what I actually want is a headless CMS? Then I can keep building on the Blazor frontend stuff I've been doing and maybe get less bogged down in DB stuff e2: ok maybe I don't actually know what a headless CMS is... fuf fucked around with this message at 18:55 on Mar 8, 2022 |
# ? Mar 8, 2022 18:27 |
|
insta posted:I do a lot of backend data ETL processing stuff, but mostly in general wherever I go as a job I'm usually tasked with solving performance problems. There's a lot of developers who simply don't understand that similar constructs are wildly different in performance, especially once you scale it up to the millions or billions of records in production. If you work in a team who does understand that inside and out, I'm glad for you. I was just curious because I figure if I profile the shambling monolith I support I'm sure it'd look like it's spending a lot of time doing string manipulation since we're rendering HTML and JSON in the Framework, but I know that most of the wall clock wait time is due to EF I thought maybe I'd find out you were stressing about the string concatenation performance in MVC or whatever. Munkeymon fucked around with this message at 20:42 on Mar 8, 2022 |
# ? Mar 8, 2022 20:40 |
|
fuf posted:What do people think of Umbraco? What are you trying to do? I'd lean against learning too many things at once, there's probably something simple you can do in the first iteration
|
# ? Mar 8, 2022 21:58 |
|
Munkeymon posted:I was just curious because I figure if I profile the shambling monolith I support I'm sure it'd look like it's spending a lot of time doing string manipulation since we're rendering HTML and JSON in the Framework, but I know that most of the wall clock wait time is due to EF If I'm not doing backend ETL, I'm producing an API for JS-based SPAs, so all performance gains are good there. Surprisingly, the database code has usually been optimized pretty well by the time I get there, which might be why I see the goofy C# poo poo left over.
|
# ? Mar 8, 2022 23:44 |
|
|
# ? Jun 6, 2024 13:09 |
|
distortion park posted:What are you trying to do? Honestly? I'm trying to learn enough .NET and C# so that I can switch jobs and get a mid-level developer role somewhere. Which short term means trying to come up with random projects to keep up some motivation. I think you're right about learning too many things at once. Umbraco is a branch too far at this stage. I think the wall I hit with my Blazor app wasn't anything technical, but more to do with design patterns and just not really knowing how and where to structure all the business logic. Blazor components / front end views? Fine with all that Database operations? Difficult but I know what I'm trying to do But the layer in between where, you know, the actual app is meant to do its thing? That's where I was really clueless about the best way to structure things. Everything got too mixed together and I would make changes that would cascade and break a bunch of other things. I hit a point where instead of being excited to keep hacking away my heart would sink at the mess of different files. Because Blazor is new most of the learning resources are like "here is what is new and specific about Blazor components" but not much "here is how to structure an application in general". It also doesn't help that every tutorial course is like "how to add an employee to your list of employees". Or some of them get really adventurous and are like "how to add a car to your list of cars". But none of them really seem to do do anything with the data. fuf fucked around with this message at 12:16 on Mar 9, 2022 |
# ? Mar 9, 2022 12:09 |