I agree with all the comments; it's not about what you do with the result and when, it's about what the thread that was executing your code is allowed to go off and do elsewise while the Async operation is working out. If the Stuff is a complex view in the DB based on a query that takes 5 minutes to run then Any will block your thread for 5 minutes. AnyAsync could let that thread serve tens of thousands of requests to your webserver in that time. If you've blocked one thread the webserver will have to spin up another to serve the other people and threads are expensive.
Async isn't about "better performance" in the sense of "make it async and it runs faster" - the code executes at the same rate. Async is about "better use of resources" - you need fewer threads and they're more busy/less sitting around doing nothing waiting for e.g IO to complete
If it were an office it's analogous to making a coffee while you're on hold on the phone; imagine you get put on hold to the gas company and your boss shouts saying he wants a coffee. If you're async you'll put it on speaker, get up while you're on hold and make the coffee, waiting to be called back by the sound of the hold music stopping and the gas company saying "hello". If you're sync you'll sit there ignoring the boss' request while someone else makes the coffee (which means the boss has to employ someone else). It's more expensive to have you sitting around doing nothing just waiting, and have to hire someone else, than have you reach a point with job x and then go do something else. If you're async you'll go and refill the printer while you're waiting for the kettle to boil. If you're sync on hold and the office junior is sync waiting for the kettle to boil, the boss will have to employ yet another person to fill the printer..
Whether it's you or someone else that picks up the call to the gas company when they finally take you off hold depends on whether you're done making the coffee and available and/or whether you've ConfigureAwait'd to indicate it has to be you that picks up the call (true) or whether anyone in the office can continue it (false)
comments: I'm comparing it to using IEnumerable immediately followed by e.g. Count(), which will iterate through the whole shabang anyway. In that case, we may go T[] right away with no deteriorated performance. What's your thought on that?
It depends on what else you will do with the result. If you need to repeatedly ask your result for its length and random access it then sure, use ToArrayAsync
to turn it into an array and then do all your work with it as locally cached data. Unless it's a query that is two terabytes big as a result
If you literally only need the count once, then it doesn't make sense to spend all that memory allocating an array and getting its length; just do the CountAsync
Neither of these seem entirely relevant to the question of "Async or no?" - if your IEnumerable is coming over a slow network and is some huge slow query it still goes back to "let the thread go off and make busy doing something else so you don't have to spin up more threads". Note that "slow" here could mean even tens of milliseconds. We don't have to be talking minute ops to see a benefit from async
Very fast operations sure, you can do them sync to save on the minuscule cost of setting up the state machine but be certain of the tipping point between the cost of setting up the state machine so the thread can do something else versus making it wait amount of time; the machine costs very little. Faced with the choice, I'd generally choose async if available, especially if any IO is involved
how to prove/refute whether it matters.
You'll have to race the horses for every case; how quickly does the op complete sync, how long does it take to do the async state management. It'd probably be quite a wearisome to do for an entire codebase which is why I tend to proceed on an "if async is available and isn't just available for async's sake, then probably someone has reasoned that using async is sensible, so we should use it" basis. Async all the way up spreading through a codebase is perhaps a good thing if you use its presence in a library as an indicator that you should leverage it in your code (which then indicates to users of your code that they should..)