首先,我用Thread实现了测试逻辑:
public void ThreadProc()
{
Console.Write("s");
Thread.Sleep(1000);
Console.Write("e");
}
public void TestByThread()
{
for (var i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(ThreadProc));
t.Start();
}
}
运行TestByThread()时,结果如下:
sssssssssseeeeeeeeee
但是当涉及到任务......
public void TestByTask()
{
for (var i = 0; i < 10; i++)
{
Task.Run(() =>
{
Console.Write("s");
Thread.Sleep(1000);
Console.Write("e");
});
}
}
执行TestByTask()时,结果很奇怪:
ssssssseesesseeeeeee
不仅char命令,而且输出速度也不同。
任务和线程之间有什么区别?
答案 0 :(得分:4)
当您致电Thread.Start
时,会创建一个新线程,并且所有线程都会打印s
,然后等待所有线程打印e
。
如果是Task.Run
,则任务在线程池中只有很少的线程。看起来有点奇怪,因为池中只有7个线程可用,可能是某些线程忙着做某事。因此7次任务打印s
,并且所有任务都进入休眠状态,但是,队列中还有更多任务根本没有启动。
当池中的某些任务完成(打印e
)时,这些任务可用于运行新任务,因此它会在待处理中启动其余任务。
答案 1 :(得分:3)
Thread.Start()
启动一个新线程,其中Task.Run()
计划任务。然后,该任务由下一个可用的工作线程执行。可能会发生新线程的创建,但不要依赖它。
答案 2 :(得分:3)
在第一个示例中,您手动创建10个线程并并行运行它们。并且由于每个线程在写"e"
之前等待1秒,因为并行性,所有10 "s"
都已写入。
使用Task.Run
时,只要池中有一个可用的工作人员,就会指示CLR启动新任务。通常,您将在池中拥有与CPU核心一样多的工作者(但这不是保证),所以基本上即使您调用Task.Run
10次,这也不意味着10个线程将立即开始工作。恰恰相反,它只会启动池中当前可用的任务,然后其他任务将等待第一个任务完成,然后重新开始。