Reputation: 603
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;
}
Upvotes: 2
Views: 1697
Reputation: 456527
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. await
ing 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.
Upvotes: 2
Reputation: 2230
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.
Upvotes: 0
Reputation: 131
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.
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
Upvotes: 0