C# 任务的行为不像我期望的那样

本文关键字:期望 任务 | 更新日期: 2023-09-27 18:34:28

首先,我用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(( 时,结果是这样的:

ssssssseeeeeeee

但是当涉及到任务时...

    public void TestByTask()
    {
        for (var i = 0; i < 10; i++)
        {
            Task.Run(() =>
            {
                Console.Write("s");
                Thread.Sleep(1000);
                Console.Write("e");
            });
        }
    }

当执行TestByTask((时,结果很奇怪:

ssssssseesesseeeeee

不仅字符顺序不同,而且输出速度也不同。

任务和线程有什么区别?

C# 任务的行为不像我期望的那样

当您调用Thread.Start时,将创建一个新线程,并且所有线程都打印s然后等待,所有线程都打印e

Task.Run的情况下,任务在线程池中只有很少的线程。这似乎有点奇怪,因为池中只有 7 个线程可用,可能是一些线程正忙于做某事。所以 7 次任务打印 s ,并且它们都进入睡眠状态,但是,队列中还有更多任务根本没有启动。

当池中的某些任务完成(打印e(时,这些任务可用于运行新任务,因此它会启动挂起的其余任务。

Thread.Start()启动一个新线程,Task.Run()在其中计划任务。然后,该任务由下一个可用的工作线程执行。可能会创建一个新线程,但不要依赖它。

在第一个示例中,您将手动创建 10 个线程并并行运行它们。由于每个线程在写入"e"之前等待 1 秒,由于并行性,所有 10 个"s"都已经写入。

使用 Task.Run 时,您指示 CLR 在池中有一个可用辅助角色时立即启动新任务。通常池中的工作线程数量与 CPU 内核一样多(但这不是保证(,所以基本上即使您调用Task.Run 10 次,这并不意味着 10 个线程会立即开始工作。恰恰相反,它只会启动池中当前可用的任务,然后其他任务将等待第一个任务完成,然后再重新开始。