C# async method execute base on the first completed task - c#

I have a program that will read some values from 2 readers located at different physical locations. For one reader I know I can write like:
private async void waitForReading()
{
string result = await readFromReader1();
return result;
}
private async Task<string> readFromReader1()
{
//poll until value detected
return reader1Value;
}
private async Task<string> readFromReader2()
{
//poll until value detected
return reader2Value;
}
However, what if I read from two readers and resume execution when one of the task returned?
What I want to achieve looks like:
private async void waitForReading()
{
string result = await readFromReader1() || readFromReader2();
return result;
}
Is it possible?

The basic answer to your question is to use WhenAny:
var task1 = readFromReader1Async();
var task2 = readFromReader2Async();
return await await Task.WhenAny(task1, task2);
However, there are a few additional considerations.
You mention "polling" in your implementation. This is the kind of operation that you'd probably want to cancel if the other reader has already returned a value. Consider using CancellationToken to enable cancellation.
Think about how to model the data coming from your "reader devices". If you always just want to query them on demand, then an async approach is fine. However, if their data can change at any time (which I suspect is the case), then you might want to consider setting up a permanent poll and consume it as an event stream; in this case, Reactive Extensions would be a more appropriate model.

How about Task.WaitAny
Task<String> task1 = readFromReader1();
Task<String> task2 = readFromReader2();
String result = Task.WhenAny(new Task[]{task1, task2}).Result;

By looking into a similar question:
Run two async tasks in parallel and collect results in .NET 4.5
I get inspired by Task.WhenAll method posted by bart, and find that Task.WhenAny(Task[]) is what I need.

Related

Does it make sense to call only one `async` method and `await` for it in another `async` method?

Does it make sense to call only one async private method and await for it in another async method?
Example:
private async Task<string> ReadMyFileAsync()
{
var streamReader = new StreamReader(#"c:\myFile.txt")
return await streamReader.ReadToEndAsync(); // <-- Does it make sense for me here to await for only onething, while the caller of the method ReadMyFileAsync is already an async method?
// By ignoring that the stream should be disposed...
}
private string ReadMyFile()
{
var streamReader = new StreamReader(#"c:\myFile.txt")
return streamReader.ReadToEnd();
// By ignoring that the stream should be disposed...
}
public async void OnFileChangedHandler()
{
// Some work...
var myText = await ReadMyFileAsync(); <-- Does it make any difference whether I called `await ReadMyFileAsync()` or `ReadMyFile()`?
var someThingElse = await SomeThingElse(...);
// Some work...
}
In the scenario above, what I guess, even if the method ReadMyFileAsync was called in its syncronous version (without using async and by using ReadToEnd() instead of await ReadToEndAsync()), it will keep acting the same, because the caller method is an async method. Which means in my opinion, this will make sense only if I am trying to read multiple files in paralell (see the following as example), is that right?
private async Task<string> ReadMyFileAsync() // <-- This makes sense for me
{
var streamReader1 = new StreamReader(#"c:\myFile1.txt");
var streamReader2 = new StreamReader(#"c:\myFile2.txt");
var streamReader3 = new StreamReader(#"c:\myFile3.txt");
var myText1Task = streamReader1.ReadToEndAsync();
var myText2Task = streamReader2.ReadToEndAsync();
var myText3Task = streamReader3.ReadToEndAsync();
return await myText1Task + await myText2Task + await myText3Task;
// By ignoring that the streams should be disposed...
}
So the question is simply, in the first block of code, does it make any difference whether I called ReadMyFileAsync or ReadMyFile?
Update: The whole question simplified is:
If I am going to await for the async method ReadMyFileAsync inside my async method OnFileChangedHandler, why would I use ReadMyFileAsync over ReadMyFile?
It depends. If you really only call one other method and you have no side effects, then you could just return the Task instead of awaiting it and returning the result wrapped in a task.
However, even in your example, you have side effects. You need to .Dispose something and you need to know when to do that. So you cannot just return the task, you need to wait until it's finished, then dispose your resources and then return the result of the finished task. Since it's "not that simple" even in your own boiled down example, the answer is: it does make sense. You have to decide case-by-case.
Sometimes you can just pass the task along, then the method does not need to be async at all, it just needs to return a Task and sometimes you need to do things based on the timing of tasks (i.e. do this only after that other thing is finished) and then you need to use async methods because you want to await results.
Yes, you should prefer async methods over sync because async methods doesn't block the executing thread. In UI apps it means that UI won't freeze. In Server apps it means that your server will be able to run more concurrent work without starving the threads.

Handle result returned by async call within async method

Imagine this is a method performing a DB query and returning a result, which in case of null is replaced with a default value (Null object pattern).
public ResultObj Get()
{
var result = dbContext.GetSomeResult();
return result ?? ResultObj.NullValue;
}
Imagine this DB query is a long-running process, so I would use async/await to execute this process in a separate thread. Suppose that the dbContext.GetSomeResultAsync() method is available.
How can be this method converted in an asynchronous one so that I can write something like this?
var resultTask = GetAsync();
var otherResultTask = GetSomethingElseAsync();
Task.WaitAll(resultTask, otherResultTask);
var myResult = resultTask.Result;
var myOtherResult = otherResultTask.Result;
I tried this solution.
public async Task<ResultObj> GetAsync()
{
var result = await dbContext.GetSomeResultAsync();
return result ?? ResultObj.NullValue;
}
First, I'm wondering why this code compiles: why can I return ResultObj when Task<ResultObj> is expected?
Second, this code predictably results in a deadlock, as clearly explained by the great number of resources about async deadlocks anti-patterns. The deadlock can be prevented by using .ConfigureAwait(false) method after the async call. Is this the right way to go? Are there any hidden drawbacks in this case? Is it a general rule?
I also tried this.
public async Task<ResultObj> GetAsync()
{
return await Task.Run(() => {
var result = dbContext.GetSomeResult();
return result ?? ResultObj.NullValue;
});
}
This results in a deadlock, too. This time I cannot even figure out why.
Edit: possible solution
Finally, after having read this, I found a solution to my problem.
My generic query wrapper method is like this.
public async Task<ResultObj> GetAsync()
{
var result = await dbContext.GetSomeResultAsync();
return result ?? ResultObj.NullValue;
}
On calling method, I use this pattern.
public async Task<CollectedResults> CollectAsync()
{
var resultTask = GetAsync();
var otherResultTask = GetSomethingElseAsync();
//here both queries are being executed.
//...in the while, optionally, here some other synchronous actions
//then, await results
var result = await resultTask;
var otherResult = await otherResultTask;
//here process collected results and return
return new CollectedResults(...);
}
It is worth mentioning that the above code, wrapped in a domain class, is called by a Controller action. In order for this to work I had to make async the methods all the way up, until Controller action, which now appears as follows.
public async Task<CollectedResults> Get()
{
return await resultsCollector.CollectAsync();
}
This way, deadlock doesn't happen anymore and execution time greatly improves with respect to the synchronous version.
I don't know if this is the canonical way of executing parallel queries. But it works and I don't see particular pitfalls in the code.
First of all, regarding :
so I would use async/await to execute this process in a separate thread.
There is no new thread created when we use async and await
Secondly:
why can I return ResultObj when Task is expected?
the Task<TResult> as return type of method tells that it returns a Task of type TResult but we need to return object of type that TResult back from it so the method can be awaited and when using Task<TResult> as reutrn type we should be using async and await to do the work.
Lastly:
this code predictably results in a deadlock
You are using async keyword with method signatures and also await the next async method call being done from within the method. So apparently it looks like the code in first example you have posted shouldn't be deadlocked, if the method GetSomeResultAsync you are consuming is really a async method and is properly implemented.
I suggest to study more about the async await before getting in to it, following is a good article to start with:
https://blog.stephencleary.com/2012/02/async-and-await.html

EF Async Methods - best practices / improvements

Sorry for a subjective question like this:
I current have a sequential loading method which was extremely slow, I have converted this into a async method:
public async void LoadData(int releaseId, int projectId, bool uiThread)
Within this method I start up an Await task (and set the ConfigureAwait to be false) as it does not need to capture and resume from this context.
await Task.Run(() =>
{
//make several DB calls as below
}).ConfigureAwait(False);
Within this task I make several async calls to EF / the database, each call looks something like this:
public async virtual Task<List<X>> FindXAsync()
{
var q = from c in context.X
select c;
return await q.ToListAsync();
}
But in the task I am awaiting the response by using result see below:
X = sm.FindXAsync().Result;
From my limited knowledge of using asynchronous programming with EF would each call run sequentially from inside the task?
Will the current set up return multiple return sets concurrently or would I have to create multiple tasks and await them separatly.
Again sorry for the vague question but i'm sure you guys are a lot more experienced on this topic than me ^^
Edit: I release there wasn't really a proper question in there, I guess what I am wondering is would x,y and z return concurrently or sequentially from within the task.
await Task.Run(() =>
{
x = sm.FindXAsync().Result;
y = new ObservableCollection<Y>(sm.FindYAsync().Result);
z = new ObservableCollection<Z>(sm.FindZAsync().Result);
}).ConfigureAwait(False)
Thanks,
Chris
Yes, the will run sequentially when you use the Result property. Also they will run sequentially with the following code: `
x = await sm.FindXAsync().ConfigureAwait(False);
y = new ObservableCollection<Y>( await sm.FindYAsync().ConfigureAwait(False));
z = new ObservableCollection<Z>(await sm.FindZAsync().ConfigureAwait(False));
Also update
public async void LoadData to return Task -> `public async Task LoadData`.
If you want to run all code in parallel add the taks in an array and then call await Task.WhenAll(tasks)

await task inside another task

I'm working on a C# console application that will be responsible for running an array of tasks. The basic structure for that is as follows:
var tasks = workItems.Select(x => Task.Factory.StartNew(() =>
{
DoSomeWork(x);
})).ToArray();
Task.WaitAll(tasks);
The problem is that DoSomeWork() is an async method which awaits the result of another task, which also needs to await a call to the Facebook API.
http://facebooksdk.net/docs/reference/SDK/Facebook.FacebookClient.html#GetTaskAsync(string)
public async void DoSomeWork(WorkItem item)
{
var results = await GetWorkData();
}
public async Task<List<WorkData>> GetWorkData()
{
var fbClient = new FacebookClient();
var task = fbClient.GetTaskAsync("something");
var fbResults = await task;
};
I thought I would be able to support this notion of nested tasks with the call to Task.WaitAll() but the execution of the parent tasks finishes almost immediately. Putting a Console.ReadLine() at the end of the application to prevent it from early execution shows that the result will indeed come back later from Facebook.
Am I missing something obvious or is there a better way to block for my Task collection that will allow for this kind of scenario?
DoSomeWork needs to not return void. The by not returning a Task the caller has no way of knowing when if finishes.
Additionally, it's already asynchronous, so there is no reason to use StartNew here. Just call DoSomeWork directly, since it should be returning a Task.

Continuation tasks not executing in correct order

Been trying to execute tasks sequentially but they are executed in a random order instead.
Appending .Unwrap after .ContinueWith doesn't help
Returning a Task of T from these methods instead of Task and assigning their result in the caller doesn't work either
Not sure about signature of my methods, whether they should contain async/await or not.
Sequencing tasks :
Task biographies = LoadArtistBiographies(apiKey);
Task blogs = LoadArtistBlogs(apiKey);
Task familiarity = LoadArtistFamiliarity(apiKey);
Task hottness = LoadArtistHottness(apiKey);
Task images = LoadArtistImages(apiKey);
await biographies.ContinueWith(b => blogs);
await blogs.ContinueWith(f => familiarity);
await familiarity.ContinueWith(h => hottness);
await hottness.ContinueWith(i => images);
await images;
Sample of executed methods :
private async Task LoadArtistBiographies(string apiKey)
{
var parameters = new ArtistBiographiesParameters();
parameters.SetDefaultValues();
parameters.ApiKey = apiKey;
parameters.Id = _artistId;
ArtistBiographies biographies = await Queries.ArtistBiographies(parameters);
ItemsControlBiographies.ItemsSource = biographies.Biographies;
}
The Queries.* methods are also asynchronous :
public static async Task<ArtistBlogs> ArtistBlogs(ArtistBlogsParameters parameters)
What is the correct syntax for chaining tasks that themselves are executing asynchronous tasks ?
If you want to execute the tasks in a specific order, you should await them directly:
await LoadArtistBiographies(apiKey);
await LoadArtistBlogs(apiKey);
await LoadArtistFamiliarity(apiKey);
await LoadArtistHottness(apiKey);
await LoadArtistImages(apiKey);
This will cause the second task (LoadArtistBlogs) to be scheduled after the first task completes.
Right now, the tasks are executing "in random order" because you've assigned them to Task instances, which allows each to be executed simultaneously.
That being said, I would actually recommend changing your methods around to returning the values, instead of assigning them to the datasource within the method:
private async Task<Biographies> LoadArtistBiographiesAsync(string apiKey)
{
var parameters = new ArtistBiographiesParameters();
parameters.SetDefaultValues();
parameters.ApiKey = apiKey;
parameters.Id = _artistId;
var bio = await Queries.ArtistBiographies(parameters);
return bio.Biographies;
}
You could then write these as:
ItemsControlBiographies.ItemsSource = await LoadArtistBiographiesAsync(apiKey);
// Other methods below, with await as this example
This makes the intent as the logic flows through the async methods a bit more clear, in my opinion.
Your example code will start executing all the tasks without waiting for each one to complete. It then waits for them to complete in order.
The key is that an async method starts when you call it. So if you don't want to start it yet, don't call the method yet:
await LoadArtistBiographies(apiKey);
await LoadArtistBlogs(apiKey);
await LoadArtistFamiliarity(apiKey);
await LoadArtistHottness(apiKey);
await LoadArtistImages(apiKey);
await will wait for the given task to complete, it will not start the task. Your Load*-methods all most likely start a task. All five tasks are running in an arbitrary order.
At the point when you get to await, your task may already has finished or not. It does not matter. You call ContinueWith on it, telling your task it should continue with this method once finished. This will return a new Task, on which you finally await.
Actually I've just found a way but without ContinueWith :
ArtistBiographies biographies = await LoadArtistBiographies(apiKey);
ItemsControlBiographies.ItemsSource = biographies.Biographies;
ArtistBlogs blogs = await LoadArtistBlogs(apiKey);
ItemsControlBlogs.ItemsSource = blogs.Blogs;
ArtistFamiliarity familiarity = await LoadArtistFamiliarity(apiKey);
ContentControlFamiliarity.Content = familiarity.artist;
ArtistHotttnesss hottness = await LoadArtistHottness(apiKey);
ContentControlHottness.Content = hottness.Artist;
ArtistImages images = await LoadArtistImages(apiKey);
ItemsControlImages.ItemsSource = images.Images;
Curious if someone could provide the answer using ContinueWith.

Categories