Reputation: 11116
Let's say i have few file formats i can read from. eg. xml, yaml and json. For each format i have specific reader but i do not know until runtime which file was placed so i try to read file with all of these readers. This whole process is currently async.
All i want is a proper way to return only 'FileReaderTask' which completed with result.
So far i came with this but i don't like it too much. Especially the part where i return null
public async Task<ReadResponse> Read(string id)
{
var readerDetails = _readerDetailsRepository.GetAll();
var tasks = readerDetails.Select(readerDetail => _reader.ReadAsync(readerDetail, id)).ToList();
foreach (var result in await Task.WhenAll(tasks))
{
if (!string.IsNullOrEmpty(result)) // only one will have the response !
{
return await HandleResponse(_jsonConverter.Convert<ReadResponse>(result), id);
}
}
return null; // ?? seems pretty bad
}
Upvotes: 3
Views: 71
Reputation: 726639
Your process is asynchronous, but it is not using multiple threads.In this case it is a good thing, because the threads reading the same file would be competing with each other.
Your current approach uses WhenAll
, which waits for all tasks to complete before picking the result. This is fine, assuming that all failing tasks complete first. You don't have to wait for all tasks, and process them as they complete instead:
var tasks = readerDetails.Select(readerDetail =>
_reader.ReadAsync(readerDetail, id).ConfigureAwait(false)
).ToList();
foreach (var task in tasks) {
var result = await task;
if (!string.IsNullOrEmpty(result)) {
return await HandleResponse(_jsonConverter.Convert<ReadResponse>(result), id);
}
}
The loop awaits individual tasks one-by-one, so if the successful task completes ahead of an unsuccessful one, your code wouldn't wait for completion of the remaining tasks before handling the response.
Upvotes: 3