no worker thread create when Task has not started executing yet? - c#

I'm reading a book on threads, below is the quote from the book:
When a thread calls the Wait method, the system checks if the Task that the
thread is waiting for has started executing. If it has, then the thread calling Wait will block
until the Task has completed running. But if the Task has not started executing yet, then
the system may (depending on the TaskScheduler) execute the Task by using the thread
that called Wait. If this happens, then the thread calling Wait does not block; it executes
the Task and returns immediately
Let's say we have the following code:
static void Main(string[] args) {
// Create a Task (it does not start running now)
Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 10);
t.Start();
t.Wait();
Console.WriteLine("The Sum is: " + t.Result);
}
static Int32 Sum(Int32 n) {
Int32 sum = 0;
for (; n > 0; n--)
{ sum += n; }
return sum;
}
My understanding is, t.Start(); means CLR will schedule it for execution so later a worker thread from threadpool can execute it. So let's say the main thread has reached to t.Wait(); while the task is still not executed by any worker thread (task has been scheduled but hasn't been picked up by the thread pool's worker thread).
Then main thread will actually execute the Sum method, is my understanding correct? So if I run the program a thousand of times, 99.99% Sum method will be executed by other worker thread, but 0.01% it will be executed by main thread. Currently no matter how many time I run the program it is always a woker thread to execute Sum method, this is just because the task always start to execute quicke before the main thread executes t.Wait();, if sth usunal happen, there is still a chance (0.01%) that the main thread can execute Sum method, is my understanding correct?

if [the unusual happens], there is still a chance (0.01%) that the main thread can execute Sum method, is my understanding correct?
The answer is possibly!
This involves some serious deep-diving into the specific implementation details of how the TaskScheduler handles tasks that are queued and how the compiler and subsequent smoke and mirrors that run in the back-end of the MSDN language have implemented the state-machines that handle Tasks and async operations.
But in the basic sense you're conclusion, in my opinion, is correct! Per MSDN, if you are using the default TaskScheduler, the TaskScheduler implements certain optimizations on your behalf such as Task Inlining, like you described, and other optimizations like Work Stealing.
If work stealing and task inlining are not desirable, consider specifying a synchronization context of the tasks that you are creating, to prevent them from performing work on threads other than the ones you specify.

Related

When are ThreadPool threads are released back to the ThreadPool?

Can anyone explain (or have a resource that explains) exactly when ThreadPool threads are released back to the ThreadPool? Here is a small example program (Dotnet fiddle: https://dotnetfiddle.net/XRso3q)
public static async Task Main()
{
Console.WriteLine("Start");
var t1 = ShortWork("SW1");
var t2 = ShortWork("SW2");
await Task.Delay(50);
var t3 = LongWork("LW1");
Console.WriteLine($"After starting LongWork Thread={Thread.CurrentThread.ManagedThreadId}");
await Task.WhenAll(t1, t2);
await t3;
Console.WriteLine("Done");
}
public static async Task ShortWork(string name)
{
Console.WriteLine($"SHORT Start {name} Thread={Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(500);
Console.WriteLine($"SHORT End {name} Thread={Thread.CurrentThread.ManagedThreadId}");
}
public static async Task LongWork(string name)
{
Console.WriteLine($"LONG Start {name} Thread={Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(2500);
Console.WriteLine($"LONG End {name} Thread={Thread.CurrentThread.ManagedThreadId}");
}
Outputs:
Start
SHORT Start SW1 Thread=1
SHORT Start SW2 Thread=1
LONG Start LW1 Thread=5
After starting LongWork Thread=5
SHORT End SW1 Thread=7
SHORT End SW2 Thread=5
LONG End LW1 Thread=5
Done
Long work starts on thread 5, but at some point thread 5 is released back to the threadpool as thread 5 is able to pick up Short SW1 ending. When exactly does 5 get released back to the threadpool after await Task.Delay(2500) in LongWork? Does the await call release it back to the threadpool? I dont think this is the case as if I log the thread id right after the call to LongWork, that is still running on thread 5. await Task.WhenAll is called on thread 5 - which then releases control back up to whatever called 'main' - is this where it gets released as there is no 'caller' to go back to?
My understanding of what happens:
Starts on thread 1, thread 1 executes ShortWork SW1 and SW2.
Task.Delay(50) is awaited and thread 1 gets released (as there is no more work to do?)
Thread 5 is chosen to pick up the continuation after the 50ms delay
Thread 5 kicks off LongWork, and it it gets to the awaited 2500ms delay. Control gets released back up to main, still on thread 5. t1 and t2 are awaited - control gets released back up to whatever called main (and so thread 5's work is done - it gets released to the threadpool)
At this point no threads are 'doing' anything
When the ShortWork delay is done, thread 5 and 7 are selected from the pool for the continuation of each call. Once done with the continuation, these are released to the pool (?)
Another thread picks up the continuation between Task.WhenAll and await t3, which then immediately gets released because it is just awaiting t3
A ThreadPool thread is selected to do the continuation of the LongWork call
Finally, a ThreadPool thread picks up the last work to write done after t3 is done.
Also as a bonus, why does 5 pick up end of SW1, and 7 pick up end of LW1? These are the threads that were just used. Are they somehow kept as 'hot threads and prioritised for continuations that come up?
The way await works is that it first checks its awaitable argument; if it has already completed, then the async method continues synchronously. If it is not complete, then the method returns to its caller.
A second key to understanding is that all async methods begin executing synchronously, on a normal call stack just like any other method.
The third useful piece of information here is that a Console app needs a foreground thread to keep running or it will exit. So when you have an async Main, behind the scenes the runtime blocks the main thread on the returned task. So, in your example, when the first await is hit in Main, it returns a task, and the main thread 1 spends the rest of the time blocked on that task.
In this code, all continuations are run by thread pool threads. It's not specified or guaranteed which thread(s) will run which continuations.
The current implementation uses synchronous continuations, so in your example the thread id for LONG Start LW1 and After starting LongWork will always be the same. You can even place a breakpoint on After starting LongWork and see how a LongWork continuation is actually in the call stack of your Main continuation.
What actually happens is that when a pool thread starts, it takes a task from the pool's work queue, waiting if necessary. It then executes the task, and then takes a new one, again waiting if necessary. This is repeated until the thread determines that it has to die and exits.
While the thread is taking a new task, or waiting for one, you could say that it has been "released to the thread pool", but that's not really useful or helpful. Nothing from the pool actually does things to the threads, after starting them up. The threads control themselves.
When you write an async function, the compiler transforms it in a way that divides it into many tasks, each of which will be executed by a function call. Where you write Task.Delay(), what actually happens is that your function schedules the task that represents the remainder of its execution, and then returns all the way out to the thread's main procedure, allowing it to get a new task from the thread pool's work queue.

Does async method get its own thread [duplicate]

I am new to TPL and I am wondering: How does the asynchronous programming support that is new to C# 5.0 (via the new async and await keywords) relate to the creation of threads?
Specifically, does the use of async/await create a new thread each time that they are used? And if there many nested methods that use async/await, is a new thread created for each of those methods?
In short NO
From Asynchronous Programming with Async and Await : Threads
The async and await keywords don't cause additional threads to be
created. Async methods don't require multithreading because an async
method doesn't run on its own thread. The method runs on the current
synchronization context and uses time on the thread only when the
method is active. You can use Task.Run to move CPU-bound work to a
background thread, but a background thread doesn't help with a process
that's just waiting for results to become available.
According to MSDN : async keyword
An async method runs synchronously until it reaches its first await expression, at which point the method is suspended until the awaited task is complete. In the meantime, control returns to the caller of the method, as the example in the next section shows.
Here is a sample code to check it :
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
private void Print(string txt)
{
string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
}
private void Run()
{
Print("Program Start");
Experiment().Wait();
Print("Program End. Press any key to quit");
Console.Read();
}
private async Task Experiment()
{
Print("Experiment code is synchronous before await");
await Task.Delay(500);
Print("Experiment code is asynchronous after first await");
}
}
And the result :
We see the code of Experiment() method after await executes on another Thread.
But if I replace the Task.Delay by my own code (method SomethingElse) :
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
private void Print(string txt)
{
string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
}
private void Run()
{
Print("Program Start");
Experiment().Wait();
Print("Program End. Press any key to quit");
Console.Read();
}
private async Task Experiment()
{
Print("Experiment code is synchronous before await");
await SomethingElse();
Print("Experiment code is asynchronous after first await");
}
private Task SomethingElse()
{
Print("Experiment code is asynchronous after first await");
Thread.Sleep(500);
return (Task.CompletedTask);
}
}
I notice the thread remains the same !
In conclusion, I'll say async/await code could use another thread, but only if the thread is created by another code, not by async/await.
In this case, I think Task.Delay created the thread, so I can conclude async/await does not create a new Thread like said by #Adriaan Stander.
Sorry for being late to the party.
I am new to TPL and I am wondering: How does the asynchronous
programming support that is new to C# 5.0 (via the new async and await
keywords) relate to the creation of threads?
async/await is not introduced for thread creation, but to utilize the current thread optimally.
Your app might read files, wait for response from another server or even do a computation with high memory access (Simply any IO task). These tasks are not CPU intensive (Any task that will not use 100% of your thread).
Think about the case when you are processing 1000 non CPU intensive tasks. In this case, process of creating 1000s of OS level thread might eat up more CPU and Memory than doing actual work on a single thread (4mb per thread in Windows, 4MB * 1000 = 4GB). At the same time if you run all the tasks sequentially, you might have to wait until the IO tasks gets finished. Which end up in long time to complete the task, while keeping the CPU idle.
Since we require parallelism to complete multiple tasks quickly, at the same time all parallel tasks are not CPU hungry, but creating threads is inefficient.
The compiler will break the execution at any method call to an async method (which gets called with an await) and immediately execute the code outside of the current code branch, once an await is reached, the execution will go inside the previous async. This will be repeated again and again until all the async calls are completed and their awaiters are satisfied.
If any of the async method have heavy CPU load without a call to an async method, then yes, your system will become unresponsive and all the remaining async methods will not get called until the current task is finished.
So I've been reading up on the threading model, and Async / Await can certainly lead to new threads being used (not necessarily created - the pool creates them at application start). It's up to the scheduler to determine if a new thread is needed. And as I see it, a call to an awaitable function may have internal details that increase the chances of the scheduler utilizing another thread; simply because more work means more opportunities / reasons for the scheduler to divvy out work.
WinRT async operations automatically happen on the thread pool. And typically you will be calling FROM the thread pool, except for UI thread work .. Xaml/Input/Events.
Async operations started on Xaml/UI threads have their results delivered back to the [calling] UI thread. But asynchronous operation results started from a thread pool thread are delivered wherever the completion happens, which may not be the same thread you were on before. The reason behind this is that code written for the thread pool is likely to be written to be thread safe and it is also for efficiency, Windows doesn't have to negotiate that thread switch.
So again, in answer to the OP, new threads are not necessarily created but your application can and will use multiple threads to complete asynchronous work.
I know this seems to contradict some of the literature regarding async / await, but that's because although the async / await construct is not by itself multithreaded. Awaitables are the, or one of the mechanisms by which the scheduler can divide work and construct calls across threads.
This is at the limit of my knowledge right now regarding async and threading, so I might not have it exactly right, but I do think it's important to see the relationship between awaitables and threading.
Using Async/Await doesn't necessarily cause a new thread to be created. But the use of Async/Await can lead to a new thread to be created because the awaitable function may internally spawn a new thread. And it often does, making the statement 'No, it doesn't spawn threads' almost useless in practice. For example, the following code spawns new threads.
VisualProcessor.Ctor()
{
...
BuildAsync();
}
async void BuildAsync()
{
...
TextureArray dudeTextures = await TextureArray.FromFilesAsync(…);
}
public static async Task<TextureArray> FromFilesAsync(...)
{
Debug.WriteLine("TextureArray.FromFilesAsync() T1 : Thread Id = " + GetCurrentThreadId());
List<StorageFile> files = new List<StorageFile>();
foreach (string path in paths)
{
if (path != null)
files.Add(await Package.Current.InstalledLocation.GetFileAsync(path)); // << new threads
else
files.Add(null);
}
Debug.WriteLine("TextureArray.FromFilesAsync() T2 : Thread Id = " + GetCurrentThreadId());
...
}
In case of Java Spring Framework, a method annotated with #Async runs in a separate thread. Quoting from official guide (https://spring.io/guides/gs/async-method) -
The findUser method is flagged with Spring’s #Async annotation,
indicating that it should run on a separate thread. The method’s
return type is CompletableFuture instead of User, a requirement
for any asynchronous service.
Of course in the backend it uses a Thread Pool and a Queue (where async tasks wait for a thread to be back in the pool).

Exact threading of async WhenAll [duplicate]

In the context of a console application making use of async/await constructs, I would like to know if it's possible for "continuations" to run in parallel on multiple threads on different CPUs.
I think this is the case, as continuations are posted on the default task scheduler (no SynchronizationContext in console app), which is the thread pool.
I know that async/await construct do not construct any additional thread. Still there should be at least one thread constructed per CPU by the thread pool, and therefore if continuations are posted on the thread pool, it could schedule task continuations in parrallel on different CPUs ... that's what I thought, but for some reason I got really confused yesterday regarding this and I am not so sure anymore.
Here is some simple code :
public class AsyncTest
{
int i;
public async Task DoOpAsync()
{
await SomeOperationAsync();
// Does the following code continuation can run
// in parrallel ?
i++;
// some other continuation code ....
}
public void Start()
{
for (int i=0; i<1000; i++)
{ var _ = DoOpAsync(); } // dummy variable to bypass warning
}
}
SomeOperationAsync does not create any thread in itself, and let's say for the sake of the example that it just sends some request asynchronously relying on I/O completion port so not blocking any thread at all.
Now, if I call Start method which will issue 1000 async operations, is it possible for the continuation code of the async method (after the await) to be run in parallel on different CPU threads ? i.e do I need to take care of thread synchronization in this case and synchronize access to field "i" ?
Yes, you should put thread synchronization logic around i++ because it is possible that multiple threads would be executing code after await at the same time.
As a result of your for loop, number of Tasks will be created. These Tasks will be executed on different Thread Pool threads. Once these Tasks are completed the continuation i.e. the code after the await, will be executed again on different Thread Pool threads. This makes it possible that multiple threads would be doing i++ at the same time
Your understanding is correct: in Console applications, by default continuations will be scheduled to the thread pool due to the default SynchronizationContext.
Each async method does start synchronously, so your for loop will execute the beginning of DoOpAsync on the same thread. Assuming that SomeOperationAsync returns an incomplete Task, the continuations will be scheduled on the thread pool.
So each of the invocations of DoOpAsync may continue in parallel.

If an async method is single threaded how can it be run in the background?

I'm trying to understand async/await and have read a number of articles but am still confused about the synchronous/asynchronous nature.
I have the following test console app:
static void Main(string[] args)
{
var test = FooAsync();
Console.WriteLine("After FooAsync");
for (int i = 0; i < 100; i++)
Console.WriteLine("After that");
Console.ReadKey();
}
private static async Task FooAsync()
{
Console.WriteLine("Before delay");
await Task.Delay(1);
Console.WriteLine("After delay");
}
The code gives output along the lines of:
Before delay
After FooAsync
After that
After that
After that
After that
After delay
After that
.
.
I understand that async/await will not create a separate thread for processing and that at the point FooAsync reaches the await Task.Delay(1) line it will return back to Main as the task will not yet have completed, however, as we are only running on a single thread can someone explain what triggers the FooAsync method to resume at some arbitrary point within Main before Main can then continue?
Update
I take it back and i3arnon and dariogriffo are correct. The code does use multiple threads (as I'd have seen before had looked in the debugger or done the obvious as kha suggested). I'd been confused by the Threads section on the following page https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_Threads not realising that a "continuation" actually refers to a continuation task schedule to run as soon as the task being "awaited" finishes.
This isn't single threaded.
When the delay task completes the rest of the method is posted to the ThreadPool and runs concurrently with your main thread. The "trigger" here is the callback of the internal System.Threading.Timer being used inside Task.Delay.
This behaviour depends on the SynchronizationContext. In a UI environment this would have been posted to the same UI thread and would have to wait until that thread is free.
If you would have been waiting for the task returned from FooAsync then you would only have a single thread running each time.
Async/await may create new threads OR NOT, it depends of the nature of the operation.
If the operation is an IO (for example disks/network operations) probably is coded in a way it will not spin a new thread. You can read from here:
The async and await keywords don't cause additional threads to be created?
If you create your own Async operation and you create a thread, that's a different story, that's why you shouldn't do async over sync
http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx
You can check this also but using Thread.CurrentThread to get the Id of the process. (Add that to a Console.WriteLine)
It's a pretty common misconception that the async or await keywords create new threads. They don't.
The threads are created by running a Task. In this case, the thread is created by the Task.Delay call.

Backgroundworker and TPL's Task have the same ManagedThreadID?

I have a Backgroundworker whose purpose is to run jobs sequentially in the background. Now one job is implemented in multithreading way. That mean, the Backgroundworker will create several threads. I use Task Parallel Library so I use the Task.Factory.StartNew to create multiple Tasks.
After the tasks are run, the Backgroundworker waits all of them to finish.
Now I print the Backgroundworker's ManagedThreadID and all the tasks' ManagedThreadIDs. I found that the BackgroundWorker's ManagedThreadID is always the same as the first task's ManagedThreadID. I think this shouldn't happen so I cannot explain. I think the Backgroundworker's thread must be different to all the tasks it creates so the ManagedThreadIDs must be all different from each other.
Can anyone explain why this scenario happens? Thank you very much.
Edit:
The code is similar to this:
Backgroundworker.Run(){
// Print Thread.CurrentThread.ManagedThreadID.
var task = Task.Factory.StartNew(action1); // action1, action2 also print ManagedThredID.
taskList.Add(task);
task = Task.Factory.StartNew(action2);
taskList.Add(task);
... // Several other tasks.
foreach(var task in taskList) task.Wait();
}
You will find that one task has the same ManagedThreadID as the Backgroundworker.
I would go on a limb here and guess that the TPL is smart enough to reuse the BackgroundWorker thread. Since the worker waits for all tasks to complete running one task in the same thread is probably an optimization.
From further investigation, what you are seeing is a result of the expected behaviour of the Task.Wait method. You can read more at Task.Wait and "Inlining" on the Parallel Programming Team blog.
If the Task being Wait’d on has
already started execution, Wait has to
block. However, if it hasn’t started
executing, Wait may be able to pull
the target task out of the scheduler
to which it was queued and execute it
inline on the current thread.
The Background worker draws threads from the thread pool as well as TPL. What might happen is that the background worker is started, it draws a thread from the pool and fires TPL threads and returns immediately the thread to the pool. By the time TPL's first task is executed TPL draws a thread from the pool and it happens that it picks the same thread as the one once used by the background worker.
Of course that's just a supposition which cannot be verified because you haven't shown your code.
What you have stumbled upon is of course not a problem but a feature (optimization): The TPL is re-using threads as much as it can.
When you create a Task it is not immediately/permanently associated with a Thread. A Task is a Job that is put in a Queue and the Queue(s) are serviced by worker threads. So it could be that the Bgw Task is suspended and its thread returned to the pool, or more directly it could be done by the Wait():
// thread A
var t1 = Task.Startnew(...);
var t2 = Task.Startnew(...);
t1.Wait(); // Thread A is idle/available so Wait can execute t1
t2.Wait();
Use TaskCreationOptions.LongRunning to avoid re-cycling the background worker.

Categories

Resources