Consider such code:
private static async Task ProcessSomethingAsync()
{
while (true)
{
var message = await GetMessageAsync();
await WriteAsync(message);
}
}
Consider that GetMessageAsync and WriteAsync methods leverage asynchronous IO.
Imagine that I have several(from 2 to N) tasks like this, which live as long as application lives.
To my opinion, since the code inside the loop is fully async, it is better not to use LongRunning option when I start such tasks, so that we will be able to leverage ThreadPool instead of creating thread per Task.
Is this correct or am I missing something?
it is better not to use LongRunning option when I start such tasks, so that we will be able to leverage ThreadPool instead of creating thread per Task.
When you're running async code, you should not specify LongRunning. If you do, then (as of today's implementation), the thread pool will start a new thread just to run the first part of your async code. As soon as your code yields at an await, that new thread will be disposed and the rest of the code will run on regular thread pool threads. So, LongRunning is usually counterproductive for async code.
I have a blog post on why StartNew is dangerous, and I (briefly) cover all of the TaskCreationOptions in that post:
AttachedToParent shouldn't be used in async tasks, so that's out. DenyChildAttach should always be used with async tasks (hint: if you didn't already know that, then StartNew isn't the tool you need). DenyChildAttach is passed by Task.Run. HideScheduler might be useful in some really obscure scheduling scenarios but in general should be avoided for async tasks. That only leaves LongRunning and PreferFairness, which are both optimization hints that should only be specified after application profiling. I often see LongRunning misused in particular. In the vast majority of situations, the threadpool will adjust to any long-running task in 0.5 seconds - without the LongRunning flag. Most likely, you don't really need it.
Yes, specifying LongRunning will potentially allow more threads to be created, because you are telling the scheduler that your task is going to hog a thread for a long time.
Async methods are exactly the opposite, they free up the thread to do other things without blocking.
Related
I need to make sure some of my code runs in the background and doesn't stop block the UI thread, and I thought I knew how to use Task.Factory.New, but as I read more and more, it seems that it doesn't always create a new thread but sometimes runs it on the UI thread if the thread pool thinks that's the way to go so now I am pretty confused over what to use to be safe that the method is not blocking the UI thread. I should also add that I don't need a return value from the method , I just need it to run asynchronously ( in the background ).
So what's the difference between these methods below and what is best to use to make sure it doesn't block the UI thread ?
And is it really true that Task.Factory.StartNew doesn't always create a thread that runs in the background and doesn't block the UI?
public Form1()
{
Task.Factory.StartNew(() => Thread.Sleep(1000));
Task.Run(() => Thread.Sleep(1000));
Task<int> longRunningTask = LongRunningOperationAsync();
}
public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation
{
await Task.Delay(1000);
return 1;
}
I should also add that I don't need a return value from the method
Beware of a common problem: just because you don't need a return value doesn't mean you shouldn't await the returned task. awaiting the task provides you with exception information as well. The only time it's appropriate to ignore the returned task is when you don't care about the return value and you don't care about any exceptions the background work may raise (that is, you're OK with silently swallowing them).
In easily >99% of cases, the appropriate behavior is to await the task.
So what's the difference between these methods below
StartNew is an outdated way to run code on a thread pool thread. You should use Run instead of StartNew. I describe why in painful detail on my blog, but the short answer is that StartNew does not understand async delegates and has inappropriate default options.
async is completely different. Run executes code on a thread pool thread, but async rewrites the code so that it doesn't need a thread while there's an asynchronous operation in progress. So, the Run example will block a thread pool thread for 1000ms in the Thread.Sleep call. The async example will run on the UI thread and then not use the UI thread for 1000ms in the await Task.Delay call.
and what is best to use to make sure it doesn't block the UI thread?
Both Task.Run and async are appropriate in UI apps, depending on the nature of the background code.
If your code is asynchronous (usually all I/O-bound code), then you should use async/await. Note that imposing asynchrony "top-down" is hard. Don't think about "forcing code off the UI thread"; instead, identify the naturally-asynchronous parts of your system (DB, file, WebAPI calls, etc), change them to be async at the lowest level, and work up from there.
If your code is synchronous (CPU-bound), then you can use Task.Run if it takes too long to run on your UI thread.
And is it really true that Task.Factory.StartNew doesn't always create a thread that runs in the background and doesn't block the UI?
Run always executes code on threads from the thread pool. The rules for StartNew are much more complex, but in your example example code, if TaskScheduler.Current == TaskScheduler.Default, then StartNew will also use a thread from the thread pool.
The two examples you give are pretty much the same and depend of the context you are using them on.
Tasks are a way to describe a packet of work with meta information to know about its state, synchronize multiple tasks, cancel them etc. The main idea about tasks and asynchronicity is that you don't have to care about "where" (on which thread) this unit of work is executed, it is performed asynchronously, that's all you need to know. So no worries for your UI-Thread, as long as you are working asynchronously, it won't be locked (that's one of the main improvements since Win8 and the async/await keywords, every UI Manipulation has to be async not to bloat the UI).
As for async&await, those are in fact syntactic sugar. In many simple cases, you don't need to care about the task itself, you just want the asynchronous computation "do this and give me the answer when you have it".
int x = await ComputeXAsync(); //Returns a Task<int> which will be automatically unwrapped as an int
If you need to synchronize tasks, for example start multiple tasks in parallel and wait that all of them are done before continuing, you can't rely on the simple await Task<int> format, you then need to work with the task itself, its Status property and in this case the Task.WaitAll(task[]) API.
Edit: I really recommend the chapter of JonSkeets Book C# in Depth (last edition). The Async/Await part is really well explained and will take you way further than any reading online will do.
The first two are actually the same. see here
Well you can think of it as a task is something you want to be done.
A thread is something like a worker which does the task for you. So basically a threads helps you doing a task, but it doesn't return a value.
a task does not create its own OS thread. Instead, tasks are executed by a TaskScheduler; the default scheduler simply runs on the ThreadPool.
See Here
An example is. A remote request you can do as task, you want the job done but dont know when it will be. But a TCPListener for the server I would run as a thread, because it always needs to listen to the socket.
Like Andreas Niedermair pointed out, you can also use longliving tasks with the TaskCreationOptions
In his answer to this question, Stephen Cleary refers to "fake" asynchrony and "true" asynchrony.
there's a much easier way to schedule work to the thread pool: Task.Run.
True asynchrony isn't possible, because you have a blocking method
that you must use. So, all you can do is a workaround - fake
asynchrony, a.k.a. blocking a thread pool thread.
How then is it possible to achieve true asynchrony, like the various methods in System.Threading.Tasks.Task? Aren't all "truly asynchronous" methods just blocking operations on some other thread if you dig deep enough?
Aren't all "truly asynchronous" methods just blocking operations on some other thread if you dig deep enough?
No. Truly asynchronous operations don't need a thread throughout the entire operation and using one limits scalability and hurts performance.
While most truly asynchronous operations are I/O ones, that can get too overly complicated to understand. (For a deep dive read There Is No Thread by Stephen Cleary).
Let's say for example that you want to await a user's button click. Since there's a Button.Click event we can utilize TaskCompletionSource to asynchronously wait for the event to be raised:
var tcs = new TaskCompletionSource<bool>();
_button.Click += (sender, EventArgs e) => tcs.SetResult(false);
await tcs.Task;
There's no non-generic TaskCompletionSource so I use a bool one with a dummy value. This creates a Task which isn't connected to a thread, it's just a synchronization construct and will only complete when the user clicks that button (through SetResult). You can await that Task for ages without blocking any threads whatsoever.
Task.Delay for that matter is implemented very similarly with a System.Threading.Timer that completes the awaited task in its callback.
Aren't all "truly asynchronous" methods just blocking operations on some other thread if you dig deep enough?
On the contrary. Truely asynchronous methods are async all the way down to the OS level. These types of methods by default dont block even at the device driver level, using IRP (IO request packet) and DPC.
See How does running several tasks asynchronously on UI thread using async/await work? where i went into detail as of how overlapped IO works all the way down.
How then is it possible to achieve true asynchrony, like the various methods in System.Threading.Tasks.Task?
A Task represents a unit of work which will complete in the future. This has nothing to do with async IO. The reason you might assume that is because async-await works together nicely with awaitables. Most of the BCL libraries expose async IO operations via the TaskAwaiter, and that's why you assume it is the one achieving the asynchrony.
Okay , let me try to put it in sentences ...
Lets consider an example,
where I create an async method and call it with await keyword,
As far as my knowledge tells me,
The main thread will be released
In a separate thread, async method will start executing
Once it is executed, The pointer will resume from last position It left in main thread.
Question 1 : Will it come back to main thread or it will be a new thread ?
Question 2: Does it make any difference if the async method is CPU bound or network bound ? If yes, what ?
The important question
Question 3 : Assuming that is was a CPU bound method, What did I achieve? I mean - main thread was released, but at the same time, another thread was used from thread pool. what's the point ?
async does not start a new thread. Neither does await. I recommend you read my async intro post and follow up with the resources at the bottom.
async is not about parallel programming; it's about asynchronous programming. If you need parallel programming, then use the Task Parallel Library (e.g., PLINQ, Parallel, or - in very complex cases - raw Tasks).
For example, you could have an async method that does I/O-bound operations. There's no need for another thread in this scenario, and none will be created.
If you do have a CPU-bound method, then you can use Task.Run to create an awaitable Task that executes that method on a thread pool thread. For example, you could do something like await Task.Run(() => Parallel...); to treat some parallel processing as an asynchronous operation.
Execution of the caller and async method will be entirely on the current thread. async methods don't create a new thread and using async/await does not actually create additional threads. Instead, thread completions/callbacks are used with a synchronization context and suspending/giving control (think Node.js style programming). However, when control is issued to or returns to the await statement, it may end up being on a different completion thread (this depends on your application and some other factors).
Yes, it will run slower if it is CPU or Network bound. Thus the await will take longer.
The benefit is not in terms of threads believe it or not... Asynchronous programming does not necessarily mean multiple threads. The benefit is that you can continue doing other work that doesn't require the async result, before waiting for the async result... An example is a web server HTTP listener thread pool. If you have a pool of size 20 then your limit is 20 concurrent requests... If all of these requests spend 90% of their time waiting on database work, you could async/await the database work and the time during which you await the database result callback will be freed... The thread will return to the HTTP listener thread pool and another user can access your site while the original one waits for the DB work to be done, upping your total limit.
It's really about freeing up threads that wait on externally-bound and slow operations to do other things while those operations execute... Taking advantage of built-in thread pools.
Don't forget that the async part could be some long-running job, e.g. running a giant database query over the network, downloading a file from the internet, etc.
I am not sure how C# works when assigning tasks to thread.
I want to verify something. Is it guaranteed that at any time, each task is being handled by one and only one thread, regardless of what that task is doing, even if its just stopped or did Thread.currentThread().sleep(), that thread will not go and serve any other task ? So its 1:1 between the thread and the tasks ? Regardless of what the task is doing, even if its just sleeping, or whether the task was called via Task.Run or await Task.Run etc ?
There are a couple of cases I'm aware of where tasks can be re-entrant. One is where one task is waiting for another task to complete, and that first task hasn't yet started. It makes sense for the new task to be started on the current thread in that case... sort of. It does raise some nasty worries about locking and any other thread-local context.
It's also possible (apparently) for Task.Factory.StartNew to execute a new task "inline", if the scheduler deems it appropriate - but the schedulers built into .NET don't do this.
See this other Stack Overflow question which includes more detailed response from Stephen Toub (on the PFX team).
For my .NET 4.0 project, I am using a custom TaskScheduler with a limited degree of concurrency (similar to the LimitedConcurrencyLevelTaskScheduler example on MSDN). A bunch of the tasks it executes block while waiting for some other operation to return a result and then continue with their work. Because it is a shame that the threads of this scheduler don't have anything to do during this period of time, I would like to schedule another task while one blocks.
I thought that maybe the TPL could see when a task blocked and then schedule something else, but my experiments with Monitor.Wait() or waiting on a ManualResetEvent have shown that this is not the case. Since I am already using my own task scheduler I thought there might be way to tell it explicitly to schedule another task, but I haven't found any method on Task, TaskScheduler etc. to do so.
Note that continuations won't work here, as I am in the middle of one task executing. Also, I would really like to avoid splitting the tasks into two, a pre-wait and a post-wait task, because there are potentially several points where waiting is required and splitting them all would lead to a level of fragmentation of my original algorithm that would make it hard to maintain. I suppose things like await from the Async CTP would be helpful, but I have to stick with .NET 4 for this one.
Is there something I am missing to tell a task scheduler to dequeue the next task and then come back to the current one when that one done?
If you have your own TaskScheduler, TPL doesn't schedule anything, that's the work of the TaskScheduler.
If you want some way to tell your custom TaskScheduler to schedule another Task, you will have to add it to your TaskScheduler by yourself. And you can't execute new Task and then “come back” to the old one, because there is no way to pause an executing Task.
But the simplest solution might be using the default TaskScheduler, since it takes blocked Tasks into account when deciding how many Tasks to schedule.
Task.ContinueWith does gives you the option to schedule a task once your initial task is complete or faulted.but this helps only when the initial task has ran to completion.
There is no such thing built-in. To avoid problems like this one, use non-blocking tasks.
You could also slightly oversubscribe the CPU by makign your own custom TaskScheduler run more threads in parallel than there are CPUs. This will lead to light inefficiencies but in case a task blocks, you have other "backfill" task already running and taking over the CPU.