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.
Related
i'm trying to make this code works in async way, but i got some doubts.
public async Task<string> GetAsync(string inputA, string inputB)
{
var result = await AnotherGetAsync(inputA, inputB)
.ConfigureAwait(false);
return result.Enabled
? inputB
: string.Empty;
}
I got some string input collection, and i would like to run this method on them.
Then i would do Task.WhenAll, and filter for non empty strings.
But it won't be async as inside the method i'm already awaiting for the result right?
I assumed the real question is:
If a single item is awaited inside method A, will this run sequential if I use Task.WhenAll for a range of items calling method A?
They will be run simultaneous with Task.WhenAll.
Perhaps it is best explained with an example:
void Main()
{
Test().GetAwaiter().GetResult();
}
private async Task<bool> CheckEmpty(string input)
{
await Task.Delay(200);
return String.IsNullOrEmpty(input);
}
private async Task Test()
{
var list = new List<string>
{
"1",
null,
"2",
""
};
var stopwatch = new Stopwatch();
stopwatch.Start();
// This takes aprox 4 * 200ms == 800ms to complete.
foreach (var itm in list)
{
Console.WriteLine(await CheckEmpty(itm));
}
Console.WriteLine(stopwatch.Elapsed);
Console.WriteLine();
stopwatch.Reset();
stopwatch.Start();
// This takes aprox 200ms to complete.
var tasks = list.Select(itm => CheckEmpty(itm));
var results = await Task.WhenAll(tasks); // Runs all at once.
Console.WriteLine(String.Join(Environment.NewLine, results));
Console.WriteLine(stopwatch.Elapsed);
}
My test results:
False
True
False
True
00:00:00.8006182
False
True
False
True
00:00:00.2017568
If we break this down:
AnotherGetAsync(inputA, inputB)
Returns a Task. Using the await keyword implicitly returns another Task to the code calling GetAsync(string inputA, string inputB).
Using the await keyword will free up the current thread, which is what makes the code asynchronous.
once the Task returned by AnotherGetAsync(inputA, inputB) is complete, result will be set to that Task.Result.
The remainder of the method will then resume:
return result.Enabled
? inputB
: string.Empty;
Setting the Task.Result of the Task returned from GetAsync.
If GetAsync is to be run multiple times, you can use Task.WhenAll to wait for each resulting Task to complete:
Task.WhenAll(yourStringCollection.Select(s => GetAsync(s, "another string"));
Task.WhenAll itself returns another Task that will complete when all the GetAsync tasks have completed:
var strings = await Task.WhenAll(yourStringCollection.Select(s => GetAsync(s, "another string"));
var nonEmptyStrings = strings.Where(s => s != string.Empty);
No, it will be async. When you await a task inside an async method, the task will be awaited when the async method is invoked. Here is your example simplified, using explicit variables for the created tasks:
public async Task<string> GetAsync()
{
var innerTask = InnerGetAsync();
var result = await innerTask;
var stringResult = result.ToString();
return stringResult;
}
Later you create two tasks by invoking the GetAsync() method:
var task1 = GetAsync();
var task2 = GetAsync();
At this point the two tasks are running concurrently. Each one has invoked internally the InnerGetAsync() method, which means that the two innerTasks are also up and running, and awaited. Any code that follows the await will not run before the innerTask is completed.
The completion of each outer task (task1 and task2) is dependent on the completion of its innerTask. Any code that will await task1, will also implicitly await innerTask as well.
After creating the two tasks, you combine them with Task.WhenAll, then do something else, then await the combined task, and finally process the results:
Task<string[]> whenAllTask = Task.WhenAll(task1, task2);
DoSomethingElse();
string[] results = await whenAllTask;
ProcessResults(results);
It is important that the DoSomethingElse() method will run before the two tasks are completed. So at this point three things will be happening concurrently, the DoSomethingElse() and the two active tasks. The await inside the GetAsync() method is local to this method, and does not mean that the generated outer task will be automatically awaited upon creation. To process the results of task1 and task2 you must first await them as well.
How can i run 2 tasks in parallel and get notified when one specific task ends (in my case the first task in the list)
Currently i am using this code:
await Task.WhenAny(A.Play(cancel), B.Play(cancel));
the code should return when A.Play(cancel) ends but not when b.Play(cancel) ends.
WhenAny does not work because it could happen that B ends before A.
WhenAll does not work because it could be that B is an endless Task.
I believe this will do what you want. The tasks will run in parallel, but you await aTask first, so it returns only when aTask returns. You can then include seperate logic to await bTask.
Task aTask = A.Play(cancel);
Task bTask = B.Play(cancel);
// will return only when A is complete.
await aTask;
// await bTask seperately.
you can use
B.Play()
without await to run B without waiting for it to end and then do
await A.Play()
You can wrap 'A.Play' in a new task method that does whatever you want after 'A.Play' completes.
async Task CallingMethod()
{
await Task.WhenAny(WrapperA(), B.Play(cancel));
}
async Task WrapperA()
{
await A.Play(cancel)
// Here you can fire an event or set the cancellation token
// Or whatever you want.
}
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.
I need to run multiple async tasks in a console application, and wait for them all to complete before further processing.
There's many articles out there, but I seem to get more confused the more I read. I've read and understand the basic principles of the Task library, but I'm clearly missing a link somewhere.
I understand that it's possible to chain tasks so that they start after another completes (which is pretty much the scenario for all the articles I've read), but I want all my Tasks running at the same time, and I want to know once they're all completed.
What's the simplest implementation for a scenario like this?
Both answers didn't mention the awaitable Task.WhenAll:
var task1 = DoWorkAsync();
var task2 = DoMoreWorkAsync();
await Task.WhenAll(task1, task2);
The main difference between Task.WaitAll and Task.WhenAll is that the former will block (similar to using Wait on a single task) while the latter will not and can be awaited, yielding control back to the caller until all tasks finish.
More so, exception handling differs:
Task.WaitAll:
At least one of the Task instances was canceled -or- an exception was thrown during the execution of at least one of the Task instances. If a task was canceled, the AggregateException contains an OperationCanceledException in its InnerExceptions collection.
Task.WhenAll:
If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state, where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.
If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state.
If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state.
If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion state before it's returned to the caller.
You could create many tasks like:
List<Task> TaskList = new List<Task>();
foreach(...)
{
var LastTask = new Task(SomeFunction);
LastTask.Start();
TaskList.Add(LastTask);
}
Task.WaitAll(TaskList.ToArray());
You can use WhenAll which will return an awaitable Task or WaitAll which has no return type and will block further code execution simular to Thread.Sleep until all tasks are completed, canceled or faulted.
WhenAll
WaitAll
Any of the supplied tasks completes in a faulted state
A task with the faulted state will be returned. The exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.
An AggregateException will be thrown.
None of the supplied tasks faulted but at least one of them was canceled
The returned task will end in the TaskStatus.Canceled state
An AggregateException will be thrown which contains an OperationCanceledException in its InnerExceptions collection
An empty list was given
An ArgumentException will be thrown
The returned task will immediately transition to a TaskStatus.RanToCompletion State before it's returned to the caller.
Doesn't block the current thread
Blocks the current thread
Example
var tasks = new Task[] {
TaskOperationOne(),
TaskOperationTwo()
};
Task.WaitAll(tasks);
// or
await Task.WhenAll(tasks);
If you want to run the tasks in a particular/specific order you can get inspiration from this answer.
The best option I've seen is the following extension method:
public static Task ForEachAsync<T>(this IEnumerable<T> sequence, Func<T, Task> action) {
return Task.WhenAll(sequence.Select(action));
}
Call it like this:
await sequence.ForEachAsync(item => item.SomethingAsync(blah));
Or with an async lambda:
await sequence.ForEachAsync(async item => {
var more = await GetMoreAsync(item);
await more.FrobbleAsync();
});
Yet another answer...but I usually find myself in a case, when I need to load data simultaneously and put it into variables, like:
var cats = new List<Cat>();
var dog = new Dog();
var loadDataTasks = new Task[]
{
Task.Run(async () => cats = await LoadCatsAsync()),
Task.Run(async () => dog = await LoadDogAsync())
};
try
{
await Task.WhenAll(loadDataTasks);
}
catch (Exception ex)
{
// handle exception
}
Do you want to chain the Tasks, or can they be invoked in a parallel manner?
For chaining
Just do something like
Task.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
and don't forget to check the previous Task instance in each ContinueWith as it might be faulted.
For the parallel manner
The most simple method I came across: Parallel.Invoke
Otherwise there's Task.WaitAll or you can even use WaitHandles for doing a countdown to zero actions left (wait, there's a new class: CountdownEvent), or ...
This is how I do it with an array Func<>:
var tasks = new Func<Task>[]
{
() => myAsyncWork1(),
() => myAsyncWork2(),
() => myAsyncWork3()
};
await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Async
Task.WaitAll(tasks.Select(task => task()).ToArray()); //Or use WaitAll for Sync
I prepared a piece of code to show you how to use the task for some of these scenarios.
// method to run tasks in a parallel
public async Task RunMultipleTaskParallel(Task[] tasks) {
await Task.WhenAll(tasks);
}
// methode to run task one by one
public async Task RunMultipleTaskOneByOne(Task[] tasks)
{
for (int i = 0; i < tasks.Length - 1; i++)
await tasks[i];
}
// method to run i task in parallel
public async Task RunMultipleTaskParallel(Task[] tasks, int i)
{
var countTask = tasks.Length;
var remainTasks = 0;
do
{
int toTake = (countTask < i) ? countTask : i;
var limitedTasks = tasks.Skip(remainTasks)
.Take(toTake);
remainTasks += toTake;
await RunMultipleTaskParallel(limitedTasks.ToArray());
} while (remainTasks < countTask);
}
There should be a more succinct solution than the accepted answer. It shouldn't take three steps to run multiple tasks simultaneously and get their results.
Create tasks
await Task.WhenAll(tasks)
Get task results (e.g., task1.Result)
Here's a method that cuts this down to two steps:
public async Task<Tuple<T1, T2>> WhenAllGeneric<T1, T2>(Task<T1> task1, Task<T2> task2)
{
await Task.WhenAll(task1, task2);
return Tuple.Create(task1.Result, task2.Result);
}
You can use it like this:
var taskResults = await Task.WhenAll(DoWorkAsync(), DoMoreWorkAsync());
var DoWorkResult = taskResults.Result.Item1;
var DoMoreWorkResult = taskResults.Result.Item2;
This removes the need for the temporary task variables. The problem with using this is that while it works for two tasks, you'd need to update it for three tasks, or any other number of tasks. Also it doesn't work well if one of the tasks doesn't return anything. Really, the .Net library should provide something that can do this
If you're using the async/await pattern, you can run several tasks in parallel like this:
public async Task DoSeveralThings()
{
// Start all the tasks
Task first = DoFirstThingAsync();
Task second = DoSecondThingAsync();
// Then wait for them to complete
var firstResult = await first;
var secondResult = await second;
}
I am not an advanced developer. I'm just trying to get a hold on the task library and just googling. I've never used the class SemaphoreSlim so I would like to know what it does. Here I present code where SemaphoreSlim is used with async & await but which I do not understand. Could someone help me to understand the code below.
1st set of code
await WorkerMainAsync();
async Task WorkerMainAsync()
{
SemaphoreSlim ss = new SemaphoreSlim(10);
while (true)
{
await ss.WaitAsync();
// you should probably store this task somewhere and then await it
var task = DoPollingThenWorkAsync();
}
}
async Task DoPollingThenWorkAsync(SemaphoreSlim semaphore)
{
var msg = Poll();
if (msg != null)
{
await Task.Delay(3000); // process the I/O-bound job
}
// this assumes you don't have to worry about exceptions
// otherwise consider try-finally
semaphore.Release();
}
Firstly, the WorkerMainAsync will be called and a SemaphoreSlim is used. Why is 10 passed to the constructor of SemaphoreSlim?
When does the control come out of the while loop again?
What does ss.WaitAsync(); do?
The DoPollingThenWorkAsync() function is expecting a SemaphoreSlim but is not passed anything when it is called. Is this typo?
Why is await Task.Delay(3000); used?
They could simply use Task.Delay(3000) but why do they use await here instead?
2nd set of code for same purpose
async Task WorkerMainAsync()
{
SemaphoreSlim ss = new SemaphoreSlim(10);
List<Task> trackedTasks = new List<Task>();
while (DoMore())
{
await ss.WaitAsync();
trackedTasks.Add(Task.Run(() =>
{
DoPollingThenWorkAsync();
ss.Release();
}));
}
await Task.WhenAll(trackedTasks);
}
void DoPollingThenWorkAsync()
{
var msg = Poll();
if (msg != null)
{
Thread.Sleep(2000); // process the long running CPU-bound job
}
}
Here is a task & ss.Release added to a list. I really do not understand how tasks can run after adding to a list?
trackedTasks.Add(Task.Run(async () =>
{
await DoPollingThenWorkAsync();
ss.Release();
}));
I am looking forward for a good explanation & help to understand the two sets of code. Thanks
why 10 is passing to SemaphoreSlim constructor.
They are using SemaphoreSlim to limit to 10 tasks at a time. The semaphore is "taken" before each task is started, and each task "releases" it when it finishes. For more about semaphores, see MSDN.
they can use simply Task.Delay(3000) but why they use await here.
Task.Delay creates a task that completes after the specified time interval and returns it. Like most Task-returning methods, Task.Delay returns immediately; it is the returned Task that has the delay. So if the code did not await it, there would be no delay.
just really do not understand after adding task to list how they can run?
In the Task-based Asynchronous Pattern, Task objects are returned "hot". This means they're already running by the time they're returned. The await Task.WhenAll at the end is waiting for them all to complete.