Task.Run与Task.Factory.StartNew有什么区别?

6

我知道这个问题以前已经被问过了,但是在谷歌搜索结果中没有找到正确的答案。

我有以下代码:

Task.Run(() => DoSomething())
    .ContinueWith(t=>Log.Error(t,"Error"), TaskContinuationOptions.OnlyOnFaulted);

Task.Factory.StartNew(() => DoSomething())
    .ContinueWith(t=>Log.Error(t,"Error"),TaskContinuationOptions.OnlyOnFaulted);

在成功运行DoSomething之后,Task.Run会抛出TaskCanceledException,而Task.Factory.StartNew可以正常工作。为什么?
更多阅读: Stephen Clearly关于不使用Task.Factory.StartNew的原因
MSDN链接 更新2: 示例代码:
private async void button27_Click(object sender, EventArgs e)
{
    var r = new Random(System.DateTime.Now.Millisecond);

    await Task.Factory.StartNew(
        () => {
            Divide(r.Next(100), r.Next(-1, 10));
            Log.Information("Divide Done!");
        },
        CancellationToken.None,
        TaskCreationOptions.DenyChildAttach,
        TaskScheduler.Default)
    .ContinueWith(
        t => {
            Log.Error(t.Exception,"There is an exception on Divide");
        },
        TaskContinuationOptions.OnlyOnFaulted);
}

private static void Divide(int a, int b)
{
    var c = a/b;
}

不是的。它没有回答我的问题,即为什么会出现抛出异常的情况。它描述了我已经知道的内容。谢谢。 - Milad
2
我已经撤销了你的问题,因为你完全改变了它,使现有的答案无效。如果你有一个新问题,请发布一个新问题。 - svick
@Sepinood - 好的,我取消了关闭投票。尽管我认为题目“Task.Run和Task.Factory.StartNew之间有什么区别?”在建议的重复问题中已经回答了。而且所有当前的回答大致都陈述了与建议的重复问题相同的内容,并引用了相同的来源。 - smoksnes
@smoksnes 感谢您的时间。我很感激。 - Milad
1个回答

6

Task.Run实际上是使用与Task.Factory.StartNew相同的逻辑实现的,只是传入了一些默认参数。当你将一个Action传递给Task.Run时:

Task.Run(someAction);

这相当于以下内容:
Task.Factory.StartNew(someAction, 
    CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

点击此处阅读更多。

如果你将CancellationToken.NoneTaskCreationOptions.DenyChildAttachTaskScheduler.Default参数传递给Task.Factory.StartNew方法,你应该会看到相同的结果。


2
@Sepinood:也许是这个问题:https://dev59.com/moTba4cB1Zd3GeqP8Z3b 或者 https://dev59.com/o4Xca4cB1Zd3GeqPKpqm - CharithJ
谢谢,这很有帮助。我完全更新了问题。我认为这与TPL的设计有关。 - Milad
3
你不会看到完全相同的行为,这里有一个重要的区别。Task.Run() 有重载,可以接受 Func<Task>Func<Task<T>> 作为参数。这使得你可以将异步函数传递给 Task.Run(),如果你试图使用 StartNew() 运行异步函数,则必须在返回的任务上调用 .Unwrap() 才能获得相同的行为。 - Scott Chamberlain
@ScottChamberlain,感谢您提供的详细信息,使得清晰度更高。 - Mrinal Kamboj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接