Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task.Run does not work like Thread.start

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

like image 549
Azzurro94 Avatar asked Jul 16 '18 06:07

Azzurro94


People also ask

Does task run block thread?

Run is misused to run IO blocking tasks. Although the code will work just fine (e.g UI not not freeze) but it is still a wrong approach. This is because Task. Run will still block a thread from thread pool the entire time until it finishes the method.

Does task run Use thread pool?

The main purpose of Task. Run() is to execute CPU-bound code in an asynchronous way. It does this by pulling a thread from the thread pool to run the method and returning a Task to represent the completion of the method.

Is task better than thread?

It is always advised to use tasks instead of thread as it is created on the thread pool which has already system created threads to improve the performance. The task can return a result. There is no direct mechanism to return the result from a thread. Task supports cancellation through the use of cancellation tokens.

Is task delay the same as thread sleep?

sleep will block a thread and task. delay will not and has a cancellation token, unless your app is pretty complex, it really doesn't matter as on the surface: task. delay and thread. sleep do pretty much the same thing.


2 Answers

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.

like image 129
Fabjan Avatar answered Oct 28 '22 08:10

Fabjan


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/

like image 25
TheGeneral Avatar answered Oct 28 '22 08:10

TheGeneral