Task.Factory.StartNew<TResult; 和 Task.Run<TResult; 到底有什么区别()

从来好事天生俭,自古瓜儿苦后甜。这篇文章主要讲述Task.Factory.StartNew< TResult; 和 Task.Run< TResult; 到底有什么区别?相关的知识,希望能为你提供帮助。
前言这不是和《??Task.Factory.StartNew 和 Task.Run 到底有什么区别???》一样吗,怎么又写一篇?
起先我也是这么觉得的,但实际发现并非如此。
实现代码【Task.Factory.StartNew< TResult; 和 Task.Run< TResult; 到底有什么区别()】查看这 2 个方法的内部实现,其内部实现逻辑其实是一样的,只是传的默认参数不同:

//Task.Factory.StartNew< TResult>
public Task< TResult> StartNew< TResult> (Func< TResult> function)

Task? currTask = Task.InternalCurrent;
return Task< TResult> .StartNew(currTask, function, m_defaultCancellationToken,
m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));


//Task.Run< TResult>
public static Task< TResult> Run< TResult> (Func< TResult> function)

return Task< TResult> .StartNew(null, function, default,
TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default);

这不还和上次一样吗?
Demo让我们创建代码验证一下:
Stopwatch stopwatch1 = new Stopwatch();
stopwatch1.Start();
var task1 = Task.Factory.StartNew(async () =>

await Task.Delay(1000);

return "Task.Factory.StartNew";
);

Console.WriteLine(await task1);
stopwatch1.Stop();
Console.WriteLine(stopwatch1.ElapsedMilliseconds);

Stopwatch stopwatch2 = new Stopwatch();
stopwatch2.Start();
stopwatch2.Start();
var task2 = Task.Run(async () =>

await Task.Delay(1000);
return "Task.Run";
);

Console.WriteLine(await task2);
stopwatch2.Stop();
Console.WriteLine(stopwatch2.ElapsedMilliseconds);

运行程序,你将会看到类似的如下输出:
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.String,ConsoleApp1.Program+< > c+< < Main> b__0_0> d]
86
Task.Run
1024

是不是很你想的结果完全不一样!
使用 ??Task.Factory.StartNew< TResult> ?? 的返回并不是 ??Task< string> ??,而是??Task< Task< string> > ??:
Task.Factory.StartNew&lt;TResult; 和 Task.Run&lt;TResult; 到底有什么区别()

文章图片

这是为什么呢?
原理其实是因为上述代码传入的参数类型不是 ??Func< TResult> ??? 而是 ??Func< Task< TResult> ?> ???,而 ??Task.Run< Task< TResult> ?> ??  对此做了一层封装:
public static Task< TResult> Run< TResult> (Func< Task< TResult> ?> function, CancellationToken cancellationToken)

...

Task< Task< TResult> ?> task1 = Task< Task< TResult> ?> .Factory.StartNew(function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

UnwrapPromise< TResult> promise = new UnwrapPromise< TResult> (task1, lookForOce: true);

return promise;

内部同样使用 ??Task.Factory.StartNew< Task< TResult> ?> ??? 生成任务,但是返回的是 ??UnwrapPromise< TResult> ??:
// This class encapsulates all "unwrap" logic, and also implements ITaskCompletionAction,
// which minimizes the allocations needed for queuing it to its antecedent.This
// logic is used by both the Unwrap extension methods and the unwrap-style Task.Run methods.
internal sealed class UnwrapPromise< TResult> : Task< TResult> , ITaskCompletionAction

而 ??Task.Factory.StartNew< TResult> ?? 没有这层封装。
不过,要想Task.Factory.StartNew< TResult> 达到Task.Run< TResult> 同样目的,可以使用 ??Unwrap?? 方法:
public static Task< TResult> Unwrap< TResult> (this Task< Task< TResult> > task!!) =>
// If the task hasnt completed or was faulted/canceled, wrap it in an unwrap promise. Otherwise,
// it completed successfully.Return its inner task to avoid unnecessary wrapping, or if the inner
// task is null, return a canceled task to match the same semantics as CreateUnwrapPromise.
!task.IsCompletedSuccessfully ? Task.CreateUnwrapPromise< TResult> (task, lookForOce: false) :
task.Result ??
Task.FromCanceled< TResult> (new CancellationToken(true));

//使用示例
var task1 = Task.Factory.StartNew(async () =>

await Task.Delay(1000);

return "Task.Factory.StartNew";
);

Console.WriteLine(await task1.Unwrap());

结论在使用 ??Task.Factory.StartNew??? 时,如果需要等待内部任务的最终完成,需要使用 ??Unwrap?? 方法进行“解开”。
想了解更多内容,请关注我的个人公众号”My IO“


    推荐阅读