Difference between Task.Run(()=> DoWorkAsync()) and new Thread(async()=> DoWorkAsync()); - c#

I recently came across some code which confused me heavily, I have always thought that you must use threads or Async tasks, not mix and match between them,
public async Task DoWork()
{
Task.Delay(1000);
}
Now I saw code calling this like so:
public void Main()
{
var thread = new Thread(async () => { await DoWorkAync(); })
{
Priority = ThreadPriority.Highest,
IsBackground = true
};
// Start thread
proccessThread.Start();
}
Now this magically seemed to NOT create a thread each time it was run, it seemed to be using the ThreadPool.
now what I am struggling to understand is the difference between the above and:
public void Main()
{
var task = Task.Run(DoWorkASync);
}
From my testing, it seems that C# Thread has a different functionality when passing in an Async Expression vs the standard method on which to run>

This construct:
var thread = new Thread(async () => { await DoWorkAync(); });
// Start thread
proccessThread.Start();
Calls Thread constructor overload accepting ThreadStart delegate, and ThreadStart delegate is () => void. So you have this:
var thread = new Thread(StuffYourThreadExecutes);
thread.Start();
static async void StuffYourThreadExecutes() {
await DoWorkAsync();
}
So you start new thread and it runs the code until first asynchronous operation begins. Then thread exists. After that first asynchronous operation completes - the rest executes on whatever thread task scheduler providers (usually thread pool thread). Any exceptions which happen during this process cannot be observed.
For example if DoWorkAsync is something like:
static async Task DoWorkAsync(){
await Task.Delay(1000);
}
Then thread starts and almost immediately exits, doing nothing useful.
Task.Run, when passing async delegate there, does what is stated in docs:
Queues the specified work to run on the thread pool and returns a
proxy for the task
So whole operation just runs on thread pool thread without creating threads for nothing. You can observe exceptions by awaiting task returned by Task.Run.

Related

Async-Await deadlock?

I'm routinely getting what I think is a deadlock in my C# code that makes heavy use of async-await. I sometimes get it on this line of code:
await context.SaveChangesAsync();
The thread just blocks indefinitely.
I'm not blocking synchronously anywhere in the code. I use async-await all the way to the top where I initialize a new background thread like so from the entry method which is synchronous:
var threads =
new ThreadStart[]
{
async () => await Run(InitiationDelegate),
}.Select(ts =>
new Thread(ts) { IsBackground = true }
);
foreach(var thread in threads)
{
thread.Start();
}
and Run has the following signature:
async Task Run(Func<Task> action)
I'm not sure where the deadlocks could be coming from?

What's the difference between Foo().Result and Task.Run(() => Foo()).Result in C#?

In C# what is the difference between these two statements? If I use the first one in my constructor in my test classes I get a deadlock, or something similar, and the tests never finish. With the second one the code works.
// Deadlock.
var r = MyMethod().Result;
// Works.
var r = Task.Run(() => MyMethod()).Result;
Update: There is a bit more context in this commit: https://github.com/webCRMdotcom/erp-integrations/pull/92/commits/dd8af89899ce1de837ef6e34f0688a685a5cea3b.
The difference is the starting thread context.
Here a simple sample
using System;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
string r;
OutputThreadInfo("Main");
r = MyMethod().Result;
r = Task.Run( () => MyMethod() ).Result;
}
public static async Task<string> MyMethod()
{
OutputThreadInfo("MyMethod");
await Task.Delay(50);
return "finished";
}
private static void OutputThreadInfo(string context)
{
Console.WriteLine("{0} {1}",context,System.Threading.Thread.CurrentThread.ManagedThreadId);
}
}
.net fiddle
which will output
Main 32
MyMethod 32
MyMethod 63
The first call of MyMethod will start at the same thread as Main and if started from a thread with a synchronization context it will block.
The second call of MyMethod will start from a different thread (worker thread from thread pool) as Main which does not have a synchronization context and therefor will not block.
PS You should keep in mind that Console applications do not have a synchronization context as default but WinForms, WPF, UWP application do have and so will behave somehow different on async/await
Task.Result and Task.Wait block the current thread you should use await for this to work without any problems. (Though they only block if not already completed).
The second line will create a task and will start it's execution on a available thread in the Thread Pool and that's why it doesn't block.
This is because the Task construct when used with async-await will generate a State Machine that keeps track of all the awaits used in the code block and when all finishes then it can return the result. Keep in mind thought that depending on the Synchronization Context you are in, the code after await may run on a different thread then the one the task started.
So what I do when I have to execute synchronous an async method I use a small piece of code like this:
private static readonly TaskFactory _tf = new TaskFactory(
CancellationToken.None, TaskCreationOptions.None,
TaskContinuationOptions.None, TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return _tf.StartNew<Task<TResult>>((Func<Task<TResult>>) (() =>
{
return func();
})).Unwrap<TResult>().GetAwaiter().GetResult();
}
Keep in mind that, if needed, you have to use the same CultureInfo inside the RunSync StarNew task factory call so you won't have this kind of problems.

How to call async methods

Imagine there is a method
async static System.Threading.Tasks.Task Do()
{
//do sth
await Task.Delay(10000);
}
now , when I call the method with
Do();
Does it make a new thread ? or I have to create a thread as below
Task.Factory.StartNew(() => Do());
Do doesn't create a thread.
The part before the await runs on the calling thread and there's no thread at all during the delay. Task.Delay uses a timer internally which doesn't hold up a thread throughout the operation.
When the delay completes a thread from the ThreadPool is used to continue executing the method.
About Task.Factory.StartNew, why would you want to create a thread? If you need to offload a CPU intensive method to the thread pool then it's fine (although Task.Run is preferable) but if you don't then simply call Do and await the result:
await Do();
If you insist on creating a new thread for Do you need to use TaskCreationOptions.LongRunning:
Task.Factory.StartNew(() => Do(), TaskCreationOptions.LongRunning);
But since Do is an async method that releases the thread when it reaches the first await this doesn't make any sense as I've explained on my blog: LongRunning Is Useless For Task.Run With async-await
All my case is this :
public void Start(Action action)
{
Token = CancellationToken.None;
IsRunning = true;
Task.Factory.StartNew(() => Do(action), TaskCreationOptions.LongRunning);
}
async Task Do(Action action)
{
while (IsRunning)
{
action();
await Task.Delay(Interval, Token);
}
}
then I call Start() with five different actions with different intervals.
Is this Correct to use ?

Why async code is run on worker thread in C#

I am playing with the async/await in the C# and while I think that I understand most of the concepts, I can not explain why the code line "var rxres = await ..." first time runs on my UDP thread, and after further receptions of the packets runs on the worker thread. As far as I understand, I am not "yielding" back to the thread function and it is still alive and so all invocations of ReceiveAsync should run on the thread I created.
static void Main(string[] args)
{
var ewh = new EventWaitHandle(false, EventResetMode.ManualReset);
var udpThread = new Thread(async () =>
{
ListenUdpAsync().Wait();
});
udpThread.Name = "UDP THREAD";
udpThread.Start();
ewh.WaitOne();
}
static public async Task ListenUdpAsync()
{
var localPort = 5555;
var localBind = new IPEndPoint(IPAddress.Any, localPort);
using (var udpc = new UdpClient(localBind))
{
while(true)
{
var rxres = await udpc.ReceiveAsync();
Console.WriteLine("Rx From: " + rxres.RemoteEndPoint);
Console.WriteLine("Rx Data: " + Encoding.ASCII.GetString(rxres.Buffer));
}
}
}
I am not "yielding" back to the thread function
The method yields once hitting await udpc.ReceiveAsync(), that is how async-await works. ListenAsync itself synchronously blocks, but since there is no sync context that comes into play, the continuation is able to marshal itself onto an arbitrary thread pool thread.
so all invocations of ReceiveAsync should run on the thread I created.
Not really. Generally, when you're running inside a console application, it uses the default TaskScheduler, which internally uses the thread pool to execute continuations on an arbitrary threadpool thread. Ones ReceiveAsync() completes, its continuation needs to be scheduled somewhere, and that place is on the thread pool.
On a side note - there is no reason to use the async modifier on the delegate, as you're not awaiting anything inside, but synchronously blocking.

Prevent async method from returning until all tasks are completed

So I'm still trying to understand the async/await pattern, but I'm also trying to achieve the following behavior:
A method A calls method B which runs a number of processes. Some of those processes can be run on separate threads while other things are being processed so that their return values will be available closer to when they are needed. Method B needs to not return control to the caller until all of these processes are completed.
Here is the test code that I am working with:
static void Main(string[] args)
{
CallProc();
Console.WriteLine("Program finished");
Console.ReadKey();
}
public static async Task CallProc()
{
var two = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(5000, "two"));
var one = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(500, "one"));
var three = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(1500, "three"));
// some process happens here
var oneMessage = await one; // waits until one finishes and then snags it's value
Console.WriteLine("Got message {0}", oneMessage);
// some more stuff happens here
var twoMessage = await two; // waits until two is finished and then snags it's value
Console.WriteLine(twoMessage);
// TODO: need to make sure that everything is completed before returning control to caller
}
public static string SomeSynchronousProcessIDontOwn(int delayTime, string message, bool delay = true)
{
Console.WriteLine("Starting \"{0}\"", message);
if(delay) Thread.Sleep(delayTime);
return string.Format("Finished \"{0}\"", message);
}
Right now, what is happening is that everything words as I expected except that the method is returning before everything is finished, so the output shows "Program finished" while "two" is still running.
How do I write this so that CallProc() can execute those tasks asynchronously but delay returning until everything has been completed. In other words, CallProc() needs to run some tasks asynchronously, but CallProc() itself needs to be called synchronously.
The idea of an asynchronous method, which is what you've written is that it will return control (approximately) immediately and the task that it returns will be marked as completed when the operation that it conceptually represents finishes.
This means that your program should either be looking at the resulting task to see when it finishes, or that you don't want an asynchronous method in the first place, and you should re-write CallProc synchronously rather than asynchronously.
To make CallProc synchronous simply remove async (and adjust the return type accordingly), and wait on each task instead of using await.
If CallProc really should be asynchronous then the caller should be adding a continuation (or using await) to perform an action when the task is completed, rather than when the method returns.
Instead of awaiting each task individually why not just await all of them using WhenAll
public static async Task CallProc()
{
var two = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(5000, "two"));
var one = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(500, "one"));
var three = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(1500, "three"));
// run synchronous tasks
await Task.WhenAll(one, two, three);
}
If you would prefer to have CallProc block (i.e. not return until all tasks have finished) then remove the async declaration and use Task.WaitAll instead.
public static void CallProc()
{
// start tasks
Task.WaitAll(one, two, three);
}
One way to do this is to simply call Wait() on the result of CallProc. This will essentially wait for the task returned by CallProc to finish before it continues. Calling Wait in a GUI app can cause a deadlock but for a console app it is fine.
static void Main(string[] args)
{
CallProc().Wait();
Console.WriteLine("Program finished");
Console.ReadKey();
}
That will ensure that "Program finished" is printed after task two is finished.

Categories