为什么即使我没有对 ContinueWith
方法返回的第二个任务使用 Wait()
方法,代码仍然可以工作?
如果我在第一个任务中不使用 Wait()
方法,那么什么都不会起作用,但对于第二个任务则不然。
using System;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
void MyMethod1()
{
Console.WriteLine(1);
}
void MyMethod2(Task MyTask)
{
Console.WriteLine(2);
}
Task MyTask1 = new Task(MyMethod1);
MyTask1.Start();
MyTask1.Wait();
Task MyTask2 = MyTask1.ContinueWith(MyMethod2); //Why it is work?
//MyTask2.Wait();
}
}
}
最佳答案
发生这种情况是因为控制台应用程序在后台任务将输出写入控制台之前退出。
如果添加 Console.ReadLine()
到方法的末尾并尝试在没有任何 .Wait()
的情况下运行它你会看到它输出 1
和2
正如预期的那样。
那么,为什么会发生这种情况呢?
嗯,这是因为第一次写入控制台会产生开销 - 后续写入不会出现这种开销。
所以当你没有Wait()
时第一个Console.WriteLine()
在程序退出之前没有时间完成。
但是,当您添加Wait()
时到第一个任务,然后是第一个 Console.WriteLine()
已经(显然)完成了,第二个 Console.WriteLine()
没有与第一个相关的开销,并且它有时间在程序退出之前完成。
(这是一个竞争条件,实际结果可能会因不同的运行和不同的环境而异。)
我们可以执行一些基本的计时来显示第一次调用Console.WriteLine()
之间所花费的时间差异。和第二个电话。 (注意:通常我使用 Bench.Net 进行计时,但对于这种特殊情况,这效果不太好。)
static void Main()
{
Stopwatch sw = Stopwatch.StartNew();
Console.WriteLine("1");
sw.Stop();
Console.WriteLine("First Console.WriteLine() took " + sw.Elapsed);
sw.Restart();
Console.WriteLine("2");
sw.Stop();
Console.WriteLine("Second Console.WriteLine() took " + sw.Elapsed);
}
对于我的电脑上的发布版本,输出:
1
First Console.WriteLine() took 00:00:00.0060951
2
Second Console.WriteLine() took 00:00:00.0000624
如您所见,第二次调用几乎比第一次调用快 100 倍。如果程序退出时间略小于 0.0060951
秒,将看不到任何输出。
但是如果 Console.WriteLine()
如果之前已执行过,则程序必须在 0.0000624
内退出输出不出现的秒数(大约!)。
您还可以通过添加 Console.WriteLine()
来演示这一点到程序的开头,以便后续调用避免第一次调用的开销:
Console.WriteLine("Priming");
void MyMethod1()
{
Console.WriteLine(1);
}
void MyMethod2(Task MyTask)
{
Console.WriteLine(2);
}
Task MyTask1 = new Task(MyMethod1);
MyTask1.Start();
Task MyTask2 = MyTask1.ContinueWith(MyMethod2); //Why it is work?
如果这样做,输出为 1
和2
- 即使没有调用MyTask1.Wait();
.
再次请注意,这是一个竞争条件,实际结果可能会有所不同。它依赖于对 WriteLine()
的调用在程序实际退出之前完成。
您从中得到的结论应该是多线程很棘手,您必须正确地执行它,否则会发生像这样奇怪的事情!
关于c# - ContinueWith 方法返回的任务不需要 Wait() 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69765799/