What is the difference between Task.Run and Task.Factory.StartNew
Task.Run is actually implemented in terms of the same logic used for
Task.Factory.StartNew, just passing in some default parameters. When
you pass an Action to Task.Run:
Task.Run(someAction);
that’s exactly equivalent to:
Task.Factory.StartNew(someAction,
CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
Read more here.
If you pass CancellationToken.None
, TaskCreationOptions.DenyChildAttach
and TaskScheduler.Default
arguments for Task.Factory.StartNew
parameters you should see the same result.
different behavior between Factory.StartNew and Task.Run?
The return type from the task factory is Task <Task>
, the return type of Task.Run is just Task
.
You need to unwrap the inner task with the factory so that your ConinueWith
in the queue code is running the continuation on the inner task instead of the outer task.
static void Main(string[] args)
{
Console.WriteLine($"Starting test program (ManagedThreadId={Thread.CurrentThread.ManagedThreadId} IsThreadPoolThread={Thread.CurrentThread.IsThreadPoolThread})");
SerialTaskQueue co_pQueue = new SerialTaskQueue();
for (int i = 0; i < 2; i++)
{
var local = i;
co_pQueue.Enqueue(() => Task.Factory.StartNew(() => { return SimulateTaskSequence(local); }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap());
}
}
Task.Run has a overload that accepts a Func<Task>
that does this for you. If you declared the delegate in the Task.Run as a Func<object>
you would see the same behavior from the Task.Run.
What is difference between Task.Factory.StartNew and new Thread().Start()?
Task.Factory.StartNew : Starts a new task that will run in a thread pool thread or may run in the same thread. If it is ran in a thread pool thread, the thread is returned to the pool when done. Thread creation/destruction is an expensive process.
new Thread().Start() : Will always run in a new thread, therefore, it is more expensive.
The exception means that there is an ongoing data set being readed from somewhere else, and you are trying to open another data reader at the same time. When using tasks, maybe you are executing one task after the other, and that is why you don't get the exception.
The exception is not threading related. You can get the same exception by opening a data reader, and try to open a new one without closing the first.
I would suggest to review your code considering that, and ensure you need threading before use it. Multithreading overuse creates performance problems and incredibly ugly bugs.
Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew()
Task.Run
is a shorthand for Task.Factory.StartNew
with specific safe arguments:
Task.Factory.StartNew(
action,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
It was added in .Net 4.5 to help with the increasingly frequent usage of async
and offloading work to the ThreadPool
.
Task.Factory.StartNew
(added with TPL in .Net 4.0) is much more robust. You should only use it if Task.Run
isn't enough, for example when you want to use TaskCreationOptions.LongRunning
(though it's unnecessary when the delegate is async. More on that on my blog: LongRunning Is Useless For Task.Run With async-await). More on Task.Factory.StartNew
in Task.Run vs Task.Factory.StartNew
Don't ever create a Task
and call Start()
unless you find an extremely good reason to do so. It should only be used if you have some part that needs to create tasks but not schedule them and another part that schedules without creating. That's almost never an appropriate solution and could be dangerous. More in "Task.Factory.StartNew" vs "new Task(...).Start"
In conclusion, mostly use Task.Run
, use Task.Factory.StartNew
if you must and never use Start
.
Task.Factory.StartNew() vs. TaskEx.Run()
Anders Hejlsberg talked about that briefly in an interview on Channel9. Apparently, Task.Run
is just a shorthand for Task.Factory.StartNew
. Its still early CTP days so we're unsure that Task.Run
will make it int. I personally hope it won't because it's kind of redundant. :)
Task.Factory.StartNew vs new Task
I found this great article by Stephen Toub, which explains that there is actually a performance penalty when using new Task(...).Start()
, as the start method needs to use synchronization to make sure the task is only scheduled once.
His advice is to prefer using Task.Factory.StartNew
for .net 4.0. For .net 4.5 Task.Run
is the better option.
Task.Run vs Task.Factory.StartNew - Expected Deadlock is not happening
The method Task.Factory.StartNew
when used with an async delegate returns a nested task: Task<Task>
. You are assigning this nested task to a variable of type Task
, which is allowed because the class Task<TResult>
derives from the class Task
. What happens then is that you lose the reference to the inner task, so you have no way of awaiting it. When you await this.backgroundTask
you are awaiting the outer Task<Task>
, but you can't get the result of the await operation, which is a Task
, the inner Task
, and await
it. The inner task has become a fire-and-forget task.
await Task.Factory.StartNew(() = versus Task.Start; await Task;
StartNew
is just a short hand for creating and starting a task. If you want to do something to the Task
instance before you start it, use the constructor. If you just want to create and start the task immediately, use the short hand.
Documentation for StartNew
says:
Calling StartNew is functionally equivalent to creating a task by
using one of its constructors, and then calling the Task.Start method
to schedule the task for execution.
Related Topics
How to Get and Set Environment Variables in C#
Byte Array to Image Conversion
How to Get Windows Display Settings
Using Regex to Balance Match Parenthesis
Load an Exe File and Run It from Memory
How to Use Reflection to Inspect the Code in a Method
How to Turn a Datatable to a CSV
How to Intercept a Method Call in C#
How to Shut Down the Computer from C#
Serialize Class Containing Dictionary Member
How to Deserialize Xml to Object
Get a Screenshot of a Specific Application
Why Does .Net Add an Additional Slash to the Already Existent Slashes in a Path