await task inside another task - c#

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.

Related

Why Task.WhenAll requires a manually created Task to be started when the same doesn't require for async methods?

Ex, the following code manually instantiates a Task and passes to a Task.WhenAll in a List<T>
public async Task Do3()
{
var task1 = new Task(async () => { await Task.Delay(2000); Console.WriteLine("########## task1"); });
var taskList = new List<Task>() { task1};
taskList[0].Start();
var taskDone = Task.WhenAll(taskList);
await taskDone;
}
without starting the Task it doesn't work, it hangs forever calling from a console app, but the below works just fine without starting it
public async Task Do3()
{
//var task1 = new Task(async () => { await Task.Delay(2000); Console.WriteLine("########## task1"); });
var taskList = new List<Task>() { SubDo1() };
//taskList[0].Start();
var taskDone = Task.WhenAll(taskList);
await taskDone;
}
public async Task SubDo1()
{
await Task.Delay(2000);
Console.WriteLine("########## task1");
}
Task is used in two completely different ways here; when you call an async method: you are starting it yourself; at this point, two things can happen:
it can run to completion (eventually) without ever reaching a truly asynchronous state, and return a completed (or faulted) task to the caller
it can reach an incomplete awaitable (in this case await Task.Delay), at which point it creates a state machine that represents the current position, schedules a completion operation on that incomplete awaitable (to do whatever comes next), and then returns an incomplete task to the caller
It is not "not started"; to return anything to the caller: we have started it. However, unlike Task.Start(), we start that work on our current thread - not an external worker thread - with other threads only getting involved based on how that incomplete awaitable schedules the completion callbacks that the compiler gives it.
This is very different to the new Task(...) scenario, where nothing is initially started. That's why they behave differently. Note also the Remarks section of the Task constructor here - it is a very niche API, and honestly: not hugely recommended.
Additionally: when you don't immediately await an async method, you're essentially going into concurrent territory (assuming the awaitable won't always complete synchronously). In some cases, this matters, and may cause threading problems re race-conditions. It shouldn't matter much in this case, though.

Should I be using await inside my Task.Run()?

** I've summarised this question at the bottom with an edit **
This has been asked before but I think my circumstances are different.
I am processing multiple requests simultaneously.
This is my code to do that, it runs in a loop. I've removed a bit of code that handles the taskAllocated variable for brevity.
while (!taskAllocated)
{
lock (_lock)
{
// Find an empty slot in the task queue to insert this task
for (i = 0; i < MaxNumTasks; i++)
{
if (_taskQueue[i] == null)
{
_taskQueue[i] = Task.Run(() => Process());
_taskQueue[i].ContinueWith(ProcessCompleted);
break;
}
}
}
}
Process is a typical async Task Process() { CpuIntensiveStuff(); } method.
I've been running the above code, and it has been working fine. It multithreads nicely. Whenever an item comes in, it will find an empty slot in the task queue, and kick it off. When the task completes, the ProcessCompleted method runs, and frees up the slot.
But then I thought, shouldn't I be using await inside my Task.Run? Something like:
_taskQueue[i] = Task.Run(async () => await Process());
After thinking about it, I'm not sure. ContinueWith triggers correctly, when the task has completed, so perhaps it's not necessary.
I ask because I wanted to monitor and log how long each task takes to complete.
So Instead of Process(), I would make another method like:
async Task DoProcess()
{
var sw = Stopwatch.StartNew();
Process();
sw.Stop();
Log(sw.ElapsedMilliseconds);
}
And it occurred to me that if I did that, I wasn't sure if I'd need to await Process(); or not, in addition to not knowing if I should await inside the Task.Run()
I'm in a bit of a tizz about this. Can anyone offer guidance?
Edit:
To summarise:
If Somemethod is:
void SomeMethod() { }
Then
Task.Run(() => SomeMethod()); is great, calls SomeMethod on a new 'thread' (not technically, but you know what I mean).
However, my SomeMethod is actually:
async Task SomeMethod() { }
Do you need to do anything special with Task.Run()?
My code, I am not, I am just straight up ignoring that it's an async Task, and that seems to work:
Task.Run(() => SomeMethod()); // SomeMethod is async Task but I am ignoring that
But I'm not convinced that it a) should work or b) is a good idea. The alternative could be to do:
Task.Run(async() => await SomeMethod());
But is there any point? And this is compounded by the fact I want to really do:
Task.Run(() =>
{
someCode();
var x = startTimer();
SomeMethod();
var y = stopTimer();
someMoreCode()
});
but without await I'm not sure it will wait for somemethod to finish and the timer will be wrong.
Things become more clear if you do not use anonymous methods. For example,
Task.Run(() => Process())
is equivalent to this:
Task.Run(DoSomething);
Task DoSomething() {
return Process();
}
Whereas
Task.Run(async () => await Process())
is equivalent to this:
Task.Run(DoSomething);
async Task DoSomething() {
await Process();
}
In most cases, there is no functional difference between return SomethingThatReturnsATask() and return await SomethingThatReturnsATask(), and you usually want to return the Task directly and not use await (for reasons described here). When used inside Task.Run, things could easily go bad if the .NET team didn't have your back.
It is important to note that asynchronous methods start running on the same thread just like any other method. The magic happens at the first await that acts on an incomplete Task. At that point, await returns its own incomplete Task. That's important - it returns, with a promise to do the rest later.
This could have meant that the Task returned from Task.Run would complete whenever Process() returns a Task. And since Process() returns a Task at the first await, that would happen when it has not yet totally completed.
The .NET team has your back
That is not the case however, because Task.Run has a specific overload for when you give it a method returning a Task. And if you look at the code, it returns a Task *that is tied to the Task you return.
That means that the Task returned from Task.Run(() => Process()) will not complete until the Task returned from Process() has completed.
So your code is fine the way it is.

Task.WaitAll() deadlocking

I want to call an asynchronous method multiple times in a xUnit test and wait for all calls to complete before I continue execution. I read that I can use Task.WhenAll() and Task.WaitAll() for precisely this scenario. For some reason however, the code is deadlocking.
[Fact]
public async Task GetLdapEntries_ReturnsLdapEntries()
{
var ldapEntries = _fixture.CreateMany<LdapEntryDto>(2).ToList();
var creationTasks = new List<Task>();
foreach (var led in ldapEntries)
{
var task = _attributesServiceClient.CreateLdapEntry(led);
task.Start();
creationTasks.Add(task);
}
Task.WaitAll(creationTasks.ToArray()); //<-- deadlock(?) here
//await Task.WhenAll(creationTasks);
var result = await _ldapAccess.GetLdapEntries();
result.Should().BeEquivalentTo(ldapEntries);
}
public async Task<LdapEntryDto> CreateLdapEntry(LdapEntryDto ldapEntryDto)
{
using (var creationResponse = await _httpClient.PostAsJsonAsync<LdapEntryDto>("", ldapEntryDto))
{
if (creationResponse.StatusCode == HttpStatusCode.Created)
{
return await creationResponse.Content.ReadAsAsync<LdapEntryDto>();
}
throw await buildException(creationResponse);
}
}
The system under test is a wrapper around an HttpClient that calls a web service, awaits the response, and possibly awaits reading the response's content that is finally deserialized and returned.
When I change the foreach part in the test to the following (ie, don't use Task.WhenAll() / WaitAll()), the code is running without a deadlock:
foreach (var led in ldapEntries)
{
await _attributesServiceClient.CreateLdapEntry(led);
}
What exactly is happening?
EDIT: While this question has been marked as duplicate, I don't see how the linked question relates to this one. The code examples in the link all use .Result which, as far as I understand, blocks the execution until the task has finished. In contrast, Task.WhenAll() returns a task that can be awaited and that finishes when all tasks have finished. So why is awaiting Task.WhenAll() deadlocking?
The code you posted cannot possibly have the behavior described. The first call to Task.Start would throw an InvalidOperationException, failing the test.
I read that I can use Task.WhenAll() and Task.WaitAll() for precisely this scenario.
No; to asynchronously wait on multiple tasks, you must use Task.WhenAll, not Task.WaitAll.
Example:
[Fact]
public async Task GetLdapEntries_ReturnsLdapEntries()
{
var ldapEntries = new List<int> { 0, 1 };
var creationTasks = new List<Task>();
foreach (var led in ldapEntries)
{
var task = CreateLdapEntry(led);
creationTasks.Add(task);
}
await Task.WhenAll(creationTasks);
}
public async Task<string> CreateLdapEntry(int ldapEntryDto)
{
await Task.Delay(500);
return "";
}
Task.WaitAll() will deadlock simply because it blocks the current thread while the tasks are not finished (and since you are using async/await and not threads, all of your tasks are running on the same thread, and you are not letting your awaited tasks to go back to the calling point because the thread they are running in -the same one where you called Task.WaitAll()-, is blocked).
Not sure why WhenAll is also deadlocking for you here though, it definitely shouldn't.
PS: you don't need to call Start on tasks returned by an async method: they are "hot" (already started) already upon creation

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.

await AsyncMethod() versus await await Task.Factory.StartNew<TResult>(AsyncMethod)

Given the following method:
public async Task<MyObject> DoSomethingAsync() {
// do some work
await OpenSomeFileAsync();
return new MyObject();
}
Is there a difference between:
public async void SomeEventHandler(EventArgs args) {
var myObject = await await Task.Factory.StartNew<Task<MyObject>>( DoSomethingAsync);
// do something with myObject
}
and:
public async void SomeEventHandler(EventArgs args) {
var myObject = await DoSomethingAsync();
// do something with myObject
}
I was thinking that the "do some work" part of DoSomethingAsync would happen immediately in a new task in the first case, but to be honest I don't really understand fully how Tasks, async and await are working, and I'm pretty sure I'm just overcomplicating things for myself.
EDIT:
This question came about from looking at this Metro example:
http://code.msdn.microsoft.com/windowsapps/Sharing-Content-Target-App-e2689782
Specifically in MainPage.xaml.cs, they have this:
var unused = Task.Factory.StartNew(async () => { // some work... });
// unused is of type Task<TResult>
I was trying to rework it without using an anonymous async function and I started wondering, why not just write an async method and await it, instead of calling StartNew and handing in an async function?
Most of the time, adding another Task is not useful, but in some cases, it can be.
The difference is if you're on the UI thread (or something similar) and execute DoSomethingAsync() directly, its first part (// do some work) will also execute on the UI thread, and so will any continuation parts of the method (unless they use ConfigureAwait()). On the other hand, if you start another Task, both the first part and any following parts of DoSomethingAsync() will execute on the ThreadPool.
If DoSomethingAsync() is written correctly, adding another Task shouldn't give you any advantages (and will give you the disadvantage of more overhead), but I can imagine there are cases where it will make a difference.
Also, instead of using Task.Factory.StartNew() and two awaits, you could write:
await Task.Run(DoSomethingAsync);
Yes, there is a difference: in the first form, you have an extra level of Task, which brings absolutely nothing useful.
The first form is basically equivalent to this:
Task<Task<MyObject>> task1 = Task.Factory.StartNew<Task<MyObject>>( DoSomethingAsync);
Task<MyObject>> task2 = await task1;
var myObject = await task2;
So it doesn't really make sense: you're creating a task that just... creates another task.

Categories