Suppose we have to write down on database a list of 1000 elements, through an async flow. Is it better to await 1000 times an asynchronous insert statement, or to wrap all the 1000 inserts in one single synchronous method encapsulated into a Task.Run
statement, awaiting one single time?
For example, SqlCommand
has every method coupled with his async
version. In this case, we have an insert statement, so we can call ExecuteNonQuery
or ExecuteNonQueryAsync
.
Often, on async/await guidelines, we read that if you have an asynchronous version available for some method, you should use it. So suppose we write:
async Task Save(IEnumerable<Savable> savables)
{
foreach(var savable in savables)
{
//create SqlCommand somehow
var sqlCmd = CreateSqlCommand(savable);
//use asynchronous version
await sqlCmd.ExecuteNonQueryAsync();
}
}
This code is very clear. However, every time it goes out from the await part, it also returns on the UI thread, and then back in a background thread in the next await encountered, and so on (doesn't it?). This implies that the user can see some lag, since the UI Thread is continously interrupted by the continuation of the await
to execute the next foreach
cycle, and in that fraction of time the UI freezes a bit.
I want to know if I better write code like this:
async Task Save(IEnumerable<Savable> savables)
{
await Task.Run(() =>
{
foreach(var savable in savables)
{
//create SqlCommand somehow
var sqlCmd = CreateSqlCommand(savable);
//use synchronous version
sqlCmd.ExecuteNonQuery();
}
});
}
In this way, the whole foreach
is executed on the secondary thread, without a continuous switch between the UI thread and the secondary one.
This implies that the UI thread is free to update the View for the entire duration of the foreach
(for example a spinner or a progress bar), that is, no lag is perceived by the user.
Am I right? or am I missing something about "async all the way down"?
I'm not looking for simple opinion-based answers, I'm looking for an explanation of async/await guidelines in case like that and for the best way to resolve it.
EDIT:
I've read this question but it is not the same. THAT question is about the choice of a SINGLE await
on an async method versus a single Task.Run
await. THIS question is about the consequences of calling 1000 await
and the resources' overhead due to the continuous switching among threads.