问题描述
我认为延续任务有一个非直觉性的问题。我会等待延续任务,但是在任务完成运行之前会产生RanToCompletion
吗?这是简短的源代码。输出如下:
private static void TestChildTasks()
{
Task t = Task.Run(() => RunParentTask());
Task t2 = t.ContinueWith(task => Task.Run(() => runchildTask()));
//Task t2 = Task.Run(() => runchildTask());
Console.WriteLine("Waiting on t1");
t.Wait();
Console.WriteLine("Done waiting on t1");
Console.WriteLine($"Waiting on t2,status of {t2.Status}");
t2.Wait();
Console.WriteLine($"Finished; child task is {t2.Status}");
}
private static void RunParentTask()
{
Console.WriteLine("Parent Task is running");
Thread.Sleep(2000);
Console.WriteLine("Parent Task is done");
}
private static void runchildTask()
{
Console.WriteLine("Child task is running");
Thread.Sleep(3000);
Console.WriteLine("Child Task is done");
}
以下是输出:
Waiting on t1
Parent Task is running
Parent Task is done
Done waiting on t1
Waiting on t2,status of Running
Finished; child task is RanToCompletion
press enter to exit
Child task is running
Child Task is done
为什么子任务返回状态RanToCompletion
后仍继续运行?
解决方法
让我们看一下下面的行:
Task t2 = t.ContinueWith(task => Task.Run(() => RunChildTask()));
尽管您已将t2
声明为Task
,但实际上它是Task<Task>
:
Task<Task> t2 = t.ContinueWith(task => Task.Run(() => RunChildTask()));
为什么?因为Task.Run
创建了一个新的Task
。
您有几种解决方法:
选项#1-展开
要从Task
中创建Task<Task>
,您需要调用Unwrap
方法。
Task t2 = t.ContinueWith(task => Task.Run(() => RunChildTask())).Unwrap();
进行此修改后,输出将如下所示:
Waiting on t1
Parent Task is running
Parent Task is done
Done waiting on t1
Child task is running
Waiting on t2,status of WaitingForActivation
Child Task is done
Finished; child task is RanToCompletion
选项2-避免创建新任务
实际上,您可以不使用RunChildTask
来呼叫Task.Run
:
Task t2 = t.ContinueWith(_ => RunChildTask());
进行此修改后,输出将如下所示:
Waiting on t1
Parent Task is running
Parent Task is done
Done waiting on t1
Child task is running
Waiting on t2,status of Running
Child Task is done
Finished; child task is RanToCompletion
选项#3-AttachToParent
如果愿意,您不仅可以将Task附加到ContinueWith
,还可以附加Task.Factory.StartNew
:
Task t2 = null;
Task t = Task.Factory.StartNew(() =>
{
RunParentTask();
t2 = Task.Factory.StartNew(RunChildTask,TaskCreationOptions.AttachedToParent);
});
进行此修改后,输出将如下所示:
Waiting on t1
Parent Task is running
Parent Task is done
Child task is running
Child Task is done
Done waiting on t1
Waiting on t2,status of RanToCompletion
Finished; child task is RanToCompletion
还有其他几种方法。