❔ Any way to optimize this? Task.WhenAll
This takes anywhere from 6-14 seconds, Any way to make it faster?
71 Replies
not sure if my suggestions will make it faster but some things I would give a try @AntiMatter :
- try rewriting your code to use
Parallel.ForEach()
- await only when the result of the async operation is needed. You are awaiting everything directly which is not always needed, e.g. you await TextToSpeechAsync() before you do other operations even tho you need the result (phase.BotAudio) after those other operations, you can await it later when you really need the result.
- maybe you can make sync work that you have async too? such as GenerateBlobKey(), try making that async
if you're on .NET 6+, you also have access to
Parallel.ForEachAsync()
which gives you a few more under-the-hood mechanical optimizations, which might help if you have very large workloads
in your code, you're not actually running everything in parallel
you've got an await
in the first if
block that forces some or all of those elements to serialize, instead of running in parallel@AnievNekaj what do you think bout my suggestions, are they good?
if we do all three things:
1. parallelize 2. await later when result is needed 3. make sync work async too
it should get a lot faster right?
Well
what i ended up doing is what @AnievNekaj suggested
with await Parallel.ForEachAsync(_currentLesson.Phases)
cut it down to 3-4 secs
I cant paste the entire methode here
basically :
@Florian Voß anything else to add to this?
Im using .net 7 btw
looks much better now, you've fullfilled the first and second point I mentioned. Third is least important one, might potentially even make it slower
Thanks bud 😄
you too @AnievNekaj
you may also want to look into using ValueTask since there are branches in this where async work is not done (phase.BotAudio is not null and phase.BotResponseTextOnSuccess is null)
if the non-async path is the most common one then ValueTask will let it run synchronously, which can be a perf boost
valuetask comes with a lot of gotchas though, and i don't remember even half of them, so read the docs before trying it
Parallel.ForEachAsync() only supports
ValueTask
. And ValueTask
is really only valuable for work that has a high likelihood of completing synchronously. This appears to be I/O work, which has no likelihood of completing synchronously.I dont quit get that, You're saying Parallel.ForEachAsync() only supports ValueTask and thats no good for I/O work, but thats what i've implemented and it did cut down time
nono, I mean the advantage of using
ValueTask
over Task
is when the majority of them will be already-complete upon creation, I.E. you ended up not having any asynchronous work to do. In this scenario, ValueTask
avoids all the memory allocations that are associated with using a Task
, regardless of whether it completes immediately. You're seeing benefit because you weren't properly parallelizing before, not because you're using ValueTask
s. Which you might not be using, anyway. I'm not sure what the rules are for anonymous async
methods, regarding when they return ValueTask
instead of Task
, or if that's even a thing at all. I believe Task
can be implicitly cast to ValueTask
, so just because Parallel.ForEachAsync()
only accepts ValueTask
, that doesn't necessarily mean that your async
method is returning one.Gotcha
another small question
Tells me its async void basically cuz no await inside
any way to mitigate it? @AnievNekaj
the await only happens in certain scopes
if there's no
await
in the method, don't make it async
yeah then i cant use ContinueWith in the inner IF scopes, lol odd stuff
Is this warning even solvable
incorrect
also, there is no reason for you to be using
.ContinueWith()
How so?
I need the bot audio to save to the blob storage
I need the api call to finish before i pass it to be saved
because that's what
await
is forI do have this
right
do that
hm?
this is the first time im using continueWith btw
and the last
Can u elaborate or provide some small code so i can undestand what im doing wrong
unless you are a framework author, you have no reason to use
.ContinueWith()
what is the async work you need to doWell get audio from an api and save it to the blob
depending on if text is null
okay, the first part of that
what is the code to do that?
.ContinueWith
is from .NET Framework 4.0, when async/await wasn't a thing ehh its hard with partial code
here is the full:
https://pastebin.com/AA8F0Ket
Pastebin
private async Task HandlePhaseAudioFileStorage() { var t...
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
and it is, quite literally, what
await
does, just cleanerI want to optimize this as much as i can cuz its a choke point atm
yeah, I was unable to read your snippets on mpbipe already
*mobile
This is the full methode
not that long about 60 lines
anways
Wtf do i need to do, give me a specific step or w/e lol
you said it yourself, you need to retrieve audio from an API
Lol oh rly
then save it to a blob
and you had some kinda condition for doing this
And remove the
tasks
list. You're currently adding everything to a list in Parallel.ForEachAsync
without await
ing anything. This defeats the purpose of this method.Either use
Task.WhenAll
or Parallel.ForEachAsync
so
yes, we've already been over that
smth like this
going back to my original example
Yey we got there bois
hm
yeah i remember that one
whatever async work you need to do for each item goes where the
...
is
just write declarative code like you normally would
except, anything that returns a Task
, you await
that's itGotcha bud, thx alot!
if you want further context, write out this async method you need, with whatever awaits and if blocks and logic you need
then compile it and go take a look at what the compiler generates, with ILSpy
well i got to this:
and each task like this i add to the list and execute them all at the end
alternatively, you can see decompilations with sharplab.io
Yeah ik them tools, i think its built in rider
which im using
again, I really cannot read that on mobile
is that a private function inside the anonymous delegate?
SaveDefaultBotAudio()
?ahh shit smth broke
i dont get the audio files back now
yeah
`
what's the purpose of that?
Idk i though it would be faster/efficient
I guess i need to go read more about async/await
I;ll be back here tomorrow with insights.
it would be faster to declare a reusable function that isn't reused anywhere else?
or is it?
This works and kinda is fast
so gonna keep it like that for now
the azure tasks get sent all together the other ones i await
they get sent all together?
Its only used once
Well smth is working right since before it used to take 10-14 secs now its 4-6
yeah, the parallelism is probably the bulk of that
you're now starting all of the google API calls at basically the same time
and each time one of them returns, you immediately follow up with the next step (if any)
so each
gets a new thread?
and executes on it?
then comes back to the azure blob save logic?
thats the flow?
threads aren't even really a concern here
maybe, maybe not, depends on how
Parallel.ForEachAsync()
schedules thingsHow does it work, it awaits the google api, then adds a task to do smth with the result no?
then all them tasks in the list that are purely related to blobstorage
get executed together
each execution of the
async
delegate is its own "logical" threadbut
becuse of this
all the await tasks
get sent together
Im getting this correct?
yes, it terms of what you're trying to say, but no in terms of what's actually happening
I'm happy to descibe what's going on in more detail, but I'm about to be on the road for 6 hours
I'll appreciate if when u come back
you can dive in
its interesting
you can also go read up on how async/await works, mechanically
Im going off for today also
Ik it creates a state machine etc
i saw the nick chapsas videos
Anyways thx for today bud! gn and thanks again
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.