Task.Run does not work like Thread.start - c#

I've been developing an application which I need to run some methods as parallel and not blocking. first I used Task.Run, but IN DEBUG MODE, I see that the operation blocks and just waits for the result. I do not want this, I want all method , which call in a foreach loop, run asynchronously.
public async void f()
{
foreach (var item in childrenANDparents)
{
await Task.Run(() => SendUpdatedSiteInfo(item.Host,site_fr));
// foreach loop does not work until the task return and continues
}
}
So I changed the task.run to thread.start and it works great!
public async void f()
{
foreach (var item in childrenANDparents)
{
Thread t = new Thread(() => SendUpdatedSiteInfo(item.Host, site_fr));
t.Start();
// foreach loop works regardless of the method, in debug mode it shows me
// they are working in parallel
}
}
Would you explain what is the difference and why ? I expect the same behavior from both code and it seems they are different.
thanks

I want all method , which call in a foreach loop, run asynchronously.
It seems that you're confusing async/sync calls with parallelization.
A quote from MSDN:
Data parallelism: A form of parallel processing where the same
computation executes in parallel on different data. Data parallelism
is supported in the Microsoft .NET Framework by the Parallel.For and
Parallel.ForEach methods and by PLINQ. Compare to task parallelism.
Asynchronous operation: An operation that that does not block the current thread
of control when the operation starts.
Let's have a closer look at your code again:
foreach (var item in childrenANDparents)
{
await Task.Run(() => SendUpdatedSiteInfo(item.Host,site_fr));
}
The await keyword will cause compiler to create a StateMachine that will handle the method execution.
It's like if you say to compiler:"Start this async operation without blocking any threads and when it's completed - execute the rest of the stuff".
After Task finishes execution this thread will be released and returned to a ThreadPool and it will execute the rest of the code on a first available thread from a ThreadPool and will make attempt to execute it in a thread in which it had started the method execution (unless .ConfigureAwait(false) is used in which case it's more like 'fire and forget' mode when we don't really care which thread will do the continuation).
When you create a separate Thread you do parallelism by delegating some code to run in a separate Thread. So depending on the code itself it may or may not be executed asynchronously.
It's like if you say to compiler:"Take this piece of work start a new thread and do it there"
If you still want to use Tasks with parallelism you could create an array of tasks in a loop and then wait for all of them to finish execution:
var tasks = new[]
{
childrenANDparents.Select(item=> Task.Run(() => SendUpdatedSiteInfo(item.Host,site_fr)));
}
await Task.WhenAll(tasks);
P.S.
And yes you may as well use TPL (Task Parallel Library) and specifically Parallel loops.

You could use a simple Parallel.ForEach or PLinq
Parallel.ForEach(childrenANDparents, (item) =>
{
SendUpdatedSiteInfo(item.Host,site_fr)
});
To better understand async and await its best to start reading some docos, its a large topic, but its worth your while
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

Related

Not sure if code runs in parallel. Tasks in console application

I have this code:
var dt = new DeveloperTest();
var tasks = readers.Select(dt.ProcessReaderAsync).ToList();
var printCounterTask = new Task(() => dt.DelayedPrint(output));
printCounterTask.Start();
Task.WhenAll(tasks).ContinueWith(x => dt.Print(output).ContinueWith(_ =>
{
dt.Finished = true;
})).Wait();
printCounterTask.Wait();
What this does is preparing tasks that will be run and then start a (I think ) parallel execution which starts with:
printCounterTask.Start();
this is what delayed print does:
public async Task DelayedPrint(IOutputResult output)
{
while (true)
{
if (!Finished)
{
//every 10 seconds should print.
//at least one print even if the execution is less than 10 seconds
//as this starts in paralel with the processing
Task.Delay(10 * 1000).Wait();
await Print(output);
}
else
{
#if DEBUG
Console.WriteLine("Finished with printing");
#endif
break;
}
}
}
Basically is printing some output that is delayed every 10 seconds, then when all the tasks are complete stops the infinite loop.
if you want to see the whole code is here https://github.com/velchev/Exclaimer-Test
I am not sure if this
Task.WhenAll(tasks).ContinueWith(x => dt.Print(output).ContinueWith(_ =>
{
dt.Finished = true;
})).Wait();
runs in parallel with printCounterTask.Start();
When I debut it seems it does as a breakpoint in the !Finished code is hit and then in the else clause too. As far as I know when you start a task it runs in parallel so all the tasks should run in parallel. A task is a representation of a thread which syntactically is easier to control compared to the old syntax. So all this threads running and because of the better syntax is easier to say - wait till all finish and then change the flag. Any helpful explanation will be appreciated. Thank you mates.
The code is mostly correct as written, but there are some nuances around the Task constructor and ContinueWith that make it difficult to understand, and make it easy to break. For example, printCounterTask.Wait() will not wait until DelayedPrint completes, because the Task constructor does not understand asynchronous delegates.
To make the code fully correct and much easier to read and reason about, replace new Task/Start with Task.Run, and replace ContinueWith with await:
var dt = new DeveloperTest();
var tasks = readers.Select(dt.ProcessReaderAsync).ToList();
var printCounterTask = Task.Run(() => dt.DelayedPrint(output));
await Task.WhenAll(tasks);
await dt.Print(output);
dt.Finished = true;
await printCounterTask;
You will also find your code to be clearer if you follow the convention of suffixing asynchronous methods with Async.
A task is a representation of a thread which syntactically is easier to control compared to the old syntax.
No, not at all. A task is a Future - a representation of an operation that may complete sometime in the future. This "operation" does not necessarily require a thread. Task.Run does queue work to the thread pool, but in this example, the task does not always use a thread pool thread (specifically, it doesn't use a thread pool thread during the await Task.Delay).
You are partly right.
The tasks will run in parallel with
printCounterTask
as expected.
However a task is not a representation of a thread and not a syntactic sugaring which easier to control over thread.
Here you can find a useful information:
https://www.dotnetforall.com/difference-task-and-thread/
In general it's important for you to understand that Tasks are using Threads from the ThreadPool.
A task is a representation of a method you wish to execute as a background work (you don't want to block the current execution), and a task needs a thread in order to operate, but it's not true that a task is a thread.
You may have more tasks than available threads in the thread pool, which will lead to them waiting in the queue for available thread in order to be executed.
Also take in consideration that Task.WhenAll will not execute the tasks for you, you'll have to execute them yourself (implementation of ProcessReaderAsync is missing, but if you're using Task.Run it's OK).

How to make this sequence printed asynchronously? [duplicate]

Ok, so basically I have a bunch of tasks (10) and I want to start them all at the same time and wait for them to complete. When completed I want to execute other tasks. I read a bunch of resources about this but I can't get it right for my particular case...
Here is what I currently have (code has been simplified):
public async Task RunTasks()
{
var tasks = new List<Task>
{
new Task(async () => await DoWork()),
//and so on with the other 9 similar tasks
}
Parallel.ForEach(tasks, task =>
{
task.Start();
});
Task.WhenAll(tasks).ContinueWith(done =>
{
//Run the other tasks
});
}
//This function perform some I/O operations
public async Task DoWork()
{
var results = await GetDataFromDatabaseAsync();
foreach (var result in results)
{
await ReadFromNetwork(result.Url);
}
}
So my problem is that when I'm waiting for tasks to complete with the WhenAll call, it tells me that all tasks are over even though none of them are completed. I tried adding Console.WriteLine in my foreach and when I have entered the continuation task, data keeps coming in from my previous Tasks that aren't really finished.
What am I doing wrong here?
You should almost never use the Task constructor directly. In your case that task only fires the actual task that you can't wait for.
You can simply call DoWork and get back a task, store it in a list and wait for all the tasks to complete. Meaning:
tasks.Add(DoWork());
// ...
await Task.WhenAll(tasks);
However, async methods run synchronously until the first await on an uncompleted task is reached. If you worry about that part taking too long then use Task.Run to offload it to another ThreadPool thread and then store that task in the list:
tasks.Add(Task.Run(() => DoWork()));
// ...
await Task.WhenAll(tasks);
If you want to run those task's parallel in different threads using TPL you may need something like this:
public async Task RunTasks()
{
var tasks = new List<Func<Task>>
{
DoWork,
//...
};
await Task.WhenAll(tasks.AsParallel().Select(async task => await task()));
//Run the other tasks
}
These approach parallelizing only small amount of code: the queueing of the method to the thread pool and the return of an uncompleted Task. Also for such small amount of task parallelizing can take more time than just running asynchronously. This could make sense only if your tasks do some longer (synchronous) work before their first await.
For most cases better way will be:
public async Task RunTasks()
{
await Task.WhenAll(new []
{
DoWork(),
//...
});
//Run the other tasks
}
To my opinion in your code:
You should not wrap your code in Task before passing to Parallel.ForEach.
You can just await Task.WhenAll instead of using ContinueWith.
Essentially you're mixing two incompatible async paradigms; i.e. Parallel.ForEach() and async-await.
For what you want, do one or the other. E.g. you can just use Parallel.For[Each]() and drop the async-await altogether. Parallel.For[Each]() will only return when all the parallel tasks are complete, and you can then move onto the other tasks.
The code has some other issues too:
you mark the method async but don't await in it (the await you do have is in the delegate, not the method);
you almost certainly want .ConfigureAwait(false) on your awaits, especially if you aren't trying to use the results immediately in a UI thread.
The DoWork method is an asynchronous I/O method. It means that you don't need multiple threads to execute several of them, as most of the time the method will asynchronously wait for the I/O to complete. One thread is enough to do that.
public async Task RunTasks()
{
var tasks = new List<Task>
{
DoWork(),
//and so on with the other 9 similar tasks
};
await Task.WhenAll(tasks);
//Run the other tasks
}
You should almost never use the Task constructor to create a new task. To create an asynchronous I/O task, simply call the async method. To create a task that will be executed on a thread pool thread, use Task.Run. You can read this article for a detailed explanation of Task.Run and other options of creating tasks.
Just also add a try-catch block around the Task.WhenAll
NB: An instance of System.AggregateException is thrown that acts as a wrapper around one or more exceptions that have occurred. This is important for methods that coordinate multiple tasks like Task.WaitAll() and Task.WaitAny() so the AggregateException is able to wrap all the exceptions within the running tasks that have occurred.
try
{
Task.WaitAll(tasks.ToArray());
}
catch(AggregateException ex)
{
foreach (Exception inner in ex.InnerExceptions)
{
Console.WriteLine(String.Format("Exception type {0} from {1}", inner.GetType(), inner.Source));
}
}

Executing Tasks in Parallel - Silverlight

I want to start a bunch of tasks and wait for all of them to finish.
This question is more or less identical to this question:
Executing tasks in parallel
But, the answer is not same for Silverlight because there is no equivalent method to Task.WhenAll().
This should work, but I get an error
Start may not be called on a promise-style task.
foreach (var displayThumbnailTask in displayThumbnailTasks)
{
displayThumbnailTask.Start();
}
foreach (var task in displayThumbnailTasks)
{
await task;
}
"Start may not be called on a promise-style task." is a somewhat misleading message for the simple thing: the task has already been started.
Thus, you may just omit the first loop.
Silverlight does not have Task.WhenAll, but if you are using Microsoft.Bcl.Async, it contains TaskEx.WhenAll which is the same.
await TaskEx.WhenAll(displayThumbnailTasks);
Execute parallel tasks with async/await

Executing tasks in parallel

Ok, so basically I have a bunch of tasks (10) and I want to start them all at the same time and wait for them to complete. When completed I want to execute other tasks. I read a bunch of resources about this but I can't get it right for my particular case...
Here is what I currently have (code has been simplified):
public async Task RunTasks()
{
var tasks = new List<Task>
{
new Task(async () => await DoWork()),
//and so on with the other 9 similar tasks
}
Parallel.ForEach(tasks, task =>
{
task.Start();
});
Task.WhenAll(tasks).ContinueWith(done =>
{
//Run the other tasks
});
}
//This function perform some I/O operations
public async Task DoWork()
{
var results = await GetDataFromDatabaseAsync();
foreach (var result in results)
{
await ReadFromNetwork(result.Url);
}
}
So my problem is that when I'm waiting for tasks to complete with the WhenAll call, it tells me that all tasks are over even though none of them are completed. I tried adding Console.WriteLine in my foreach and when I have entered the continuation task, data keeps coming in from my previous Tasks that aren't really finished.
What am I doing wrong here?
You should almost never use the Task constructor directly. In your case that task only fires the actual task that you can't wait for.
You can simply call DoWork and get back a task, store it in a list and wait for all the tasks to complete. Meaning:
tasks.Add(DoWork());
// ...
await Task.WhenAll(tasks);
However, async methods run synchronously until the first await on an uncompleted task is reached. If you worry about that part taking too long then use Task.Run to offload it to another ThreadPool thread and then store that task in the list:
tasks.Add(Task.Run(() => DoWork()));
// ...
await Task.WhenAll(tasks);
If you want to run those task's parallel in different threads using TPL you may need something like this:
public async Task RunTasks()
{
var tasks = new List<Func<Task>>
{
DoWork,
//...
};
await Task.WhenAll(tasks.AsParallel().Select(async task => await task()));
//Run the other tasks
}
These approach parallelizing only small amount of code: the queueing of the method to the thread pool and the return of an uncompleted Task. Also for such small amount of task parallelizing can take more time than just running asynchronously. This could make sense only if your tasks do some longer (synchronous) work before their first await.
For most cases better way will be:
public async Task RunTasks()
{
await Task.WhenAll(new []
{
DoWork(),
//...
});
//Run the other tasks
}
To my opinion in your code:
You should not wrap your code in Task before passing to Parallel.ForEach.
You can just await Task.WhenAll instead of using ContinueWith.
Essentially you're mixing two incompatible async paradigms; i.e. Parallel.ForEach() and async-await.
For what you want, do one or the other. E.g. you can just use Parallel.For[Each]() and drop the async-await altogether. Parallel.For[Each]() will only return when all the parallel tasks are complete, and you can then move onto the other tasks.
The code has some other issues too:
you mark the method async but don't await in it (the await you do have is in the delegate, not the method);
you almost certainly want .ConfigureAwait(false) on your awaits, especially if you aren't trying to use the results immediately in a UI thread.
The DoWork method is an asynchronous I/O method. It means that you don't need multiple threads to execute several of them, as most of the time the method will asynchronously wait for the I/O to complete. One thread is enough to do that.
public async Task RunTasks()
{
var tasks = new List<Task>
{
DoWork(),
//and so on with the other 9 similar tasks
};
await Task.WhenAll(tasks);
//Run the other tasks
}
You should almost never use the Task constructor to create a new task. To create an asynchronous I/O task, simply call the async method. To create a task that will be executed on a thread pool thread, use Task.Run. You can read this article for a detailed explanation of Task.Run and other options of creating tasks.
Just also add a try-catch block around the Task.WhenAll
NB: An instance of System.AggregateException is thrown that acts as a wrapper around one or more exceptions that have occurred. This is important for methods that coordinate multiple tasks like Task.WaitAll() and Task.WaitAny() so the AggregateException is able to wrap all the exceptions within the running tasks that have occurred.
try
{
Task.WaitAll(tasks.ToArray());
}
catch(AggregateException ex)
{
foreach (Exception inner in ex.InnerExceptions)
{
Console.WriteLine(String.Format("Exception type {0} from {1}", inner.GetType(), inner.Source));
}
}

multithreading in regards toTask, async, and await

I have the following code and just want to make sure I have the concept of multithreading down on a high level.
public async Task<List<Category>> GetProjectsByCategoryIDAsync(Int16 categoryid)
{
try
{
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
var category = await DbContext.Categories.Include("Projects").Where(p => p.CategoryID == categoryid).ToListAsync();
return category;
}
}
catch (Exception)
{
throw;
}
}
It is my understanding of the following:
async - declares a method to run asynchounously instead of
synchrounously.
Task - declares a method to run as a task on a single thread
await - the task waits for the operation to complete.
Where I am a little fuzzy about is the await keyword. Obviously, the benefit of asynchrounous programming is that the method supposedly doesn't have to wait for the task to complete before another request comes in right behind it. But with the await keyword, the task waits until the operation is finished.
With synchrounous programming, everything is processed in a sequential pattern.
How does this methodology allow for requests to come in simultaneously and be executed in a much faster fashion than synchronous programming??
I just need a high level explanation to get the concept down.
Thanks so much in advance.
Consider the following code:
public async Task DoSomething()
{
Console.WriteLine("Begin");
int i = await DoSomethingElse();
Console.WriteLine("End " + i);
}
public Task<int> DoSomethingElse()
{
return new Task<int>(() =>
{
// do heavy work
Thread.Sleep(1000);
return 1;
});
}
With synchrounous programming, everything is processed in a sequential
pattern.
The code above is asynchronous, but is still sequential. The difference between that code and its synchronous version (e.g., public int DoSomethingElse) is that when you await DoSomethingElse, the main thread will be freed to do other work, instead of blocking waiting for DoSomethingElse to complete.
What actually happens is: your async DoSomething method will run on thread A and be broken in two.
the first part will print "Begin" and make an async call, and then return.
the second part will print "End"
After the first part of the method executes, Thread A will be free to do other work.
Meanwhile, Thread B will be executing the lambda expression that does some heavy work.
Whenever Thread B completes, the second part of your method will be scheduled to run on Thread A, and "End" will be printed.
Notice that, while Thread B was executing the heavy work, Thread A was free to do other stuff.
How does this methodology allow for requests to come in simultaneously
and be executed in a much faster fashion than synchronous
programming??
In frameworks such as ASP.NET MVC, your application has a finite number of threads available to handle incoming requests (lets call these "request threads"). By delegating heavy work to other threads and awaiting, your request threads will be free to handle more incoming requests while heavy work is being done.
This diagram, although complex, illustrates the execution/suspension flow of threads executing asynchronous work:
Notice how at step 6 the thread was yielded, and then step 7 resumed the execution of the method.
As you can see, the await keyword effectively breaks the method in two.

Categories

Resources