Trying to understanding the difference between the TPL & async
/await
when it comes to thread creation.
I believe the TPL (TaskFactory.StartNew
) works similar to ThreadPool.QueueUserWorkItem
in that it queues up work on a thread in the thread pool. That's of course unless you use TaskCreationOptions.LongRunning
which creates a new thread.
I thought async
/await
would work similarly so essentially:
TPL:
Factory.StartNew( () => DoSomeAsyncWork() ) .ContinueWith( (antecedent) => { DoSomeWorkAfter(); },TaskScheduler.FromCurrentSynchronizationContext());
Async
/Await
:
await DoSomeAsyncWork(); DoSomeWorkAfter();
would be identical. From what I've been reading it seems like async
/await
only "sometimes" creates a new thread. So when does it create a new thread and when doesn't it create a new thread? If you were dealing with IO completion ports i can see it not having to create a new thread but otherwise I would think it would have to. I guess my understanding of FromCurrentSynchronizationContext
always was a bit fuzzy also. I always throught it was, in essence, the UI thread.
Compared to the classic threading model in . NET, Task Parallel Library minimizes the complexity of using threads and provides an abstraction through a set of APIs that help developers focus more on the application program instead of focusing on how the threads will be provisioned.
Threading. Tasks namespaces. The purpose of the TPL is to make developers more productive by simplifying the process of adding parallelism and concurrency to applications. The TPL scales the degree of concurrency dynamically to most efficiently use all the processors that are available.
The TPL features (without async-await and some other . NET 4.5 features) can be all run under .
The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.
I believe the TPL (TaskFactory.Startnew) works similar to ThreadPool.QueueUserWorkItem in that it queues up work on a thread in the thread pool.
Pretty much.
From what i've been reading it seems like async/await only "sometimes" creates a new thread.
Actually, it never does. If you want multithreading, you have to implement it yourself. There's a new Task.Run
method that is just shorthand for Task.Factory.StartNew
, and it's probably the most common way of starting a task on the thread pool.
If you were dealing with IO completion ports i can see it not having to create a new thread but otherwise i would think it would have to.
Bingo. So methods like Stream.ReadAsync
will actually create a Task
wrapper around an IOCP (if the Stream
has an IOCP).
You can also create some non-I/O, non-CPU "tasks". A simple example is Task.Delay
, which returns a task that completes after some time period.
The cool thing about async
/await
is that you can queue some work to the thread pool (e.g., Task.Run
), do some I/O-bound operation (e.g., Stream.ReadAsync
), and do some other operation (e.g., Task.Delay
)... and they're all tasks! They can be awaited or used in combinations like Task.WhenAll
.
Any method that returns Task
can be await
ed - it doesn't have to be an async
method. So Task.Delay
and I/O-bound operations just use TaskCompletionSource
to create and complete a task - the only thing being done on the thread pool is the actual task completion when the event occurs (timeout, I/O completion, etc).
I guess my understanding of FromCurrentSynchronizationContext always was a bit fuzzy also. I always throught it was, in essence, the UI thread.
I wrote an article on SynchronizationContext
. Most of the time, SynchronizationContext.Current
:
Any thread can set its own SynchronizationContext
, so there are exceptions to the rules above.
Note that the default Task
awaiter will schedule the remainder of the async
method on the current SynchronizationContext
if it is not null; otherwise it goes on the current TaskScheduler
. This isn't so important today, but in the near future it will be an important distinction.
I wrote my own async
/await
intro on my blog, and Stephen Toub recently posted an excellent async
/await
FAQ.
Regarding "concurrency" vs "multithreading", see this related SO question. I would say async
enables concurrency, which may or may not be multithreaded. It's easy to use await Task.WhenAll
or await Task.WhenAny
to do concurrent processing, and unless you explicitly use the thread pool (e.g., Task.Run
or ConfigureAwait(false)
), then you can have multiple concurrent operations in progress at the same time (e.g., multiple I/O or other types like Delay
) - and there is no thread needed for them. I use the term "single-threaded concurrency" for this kind of scenario, though in an ASP.NET host, you can actually end up with "zero-threaded concurrency". Which is pretty sweet.
async / await basically simplifies the ContinueWith
methods ( Continuations in Continuation Passing Style )
It does not introduce concurrency - you still have to do that yourself ( or use the Async version of a framework method. )
So, the C# 5 version would be:
await Task.Run( () => DoSomeAsyncWork() ); DoSomeWorkAfter();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With