c# - 为什么线程创建这么快?

标签 c# .net multithreading clr

我在书中读到,线程创建是昂贵的(不像进程创建那么昂贵,但仍然如此),我们应该避免它。我编写了测试代码,我对线程创建的速度感到震惊。

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static int testVal = 0;
        static void Main(string[] args)
        {
            const int ThreadsCount = 10000;
            var watch = Stopwatch.StartNew();
            for (int i = 0; i < ThreadsCount; i++)
            {
                var myThread = new Thread(MainVoid);
                myThread.Start();
            }
            watch.Stop();
            Console.WriteLine("Test value ={0}", testVal);
            Console.WriteLine("Ended in {0} miliseconds", watch.ElapsedMilliseconds);
            Console.WriteLine("{0} miliseconds per thread ", (double)watch.ElapsedMilliseconds / ThreadsCount);
        }

        static void MainVoid()
        {
            Interlocked.Increment(ref testVal);
        }
    }
}

输出:

Test value =10000

Ended in 702 miliseconds

0,0702 miliseconds per thread.

是我的代码错误还是线程创建太快而书中的建议是错误的? (我只看到每个线程有一些额外的内存消耗,但没有创建时间。)

最佳答案

线程创建非常慢。考虑一下这段代码,它对比了内联执行操作和使用多个线程执行操作的速度:

private void DoStuff()
{
    const int ThreadsCount = 10000;
    var sw = Stopwatch.StartNew();
    int testVal = 0;
    for (int i = 0; i < ThreadsCount; ++i)
    {
        Interlocked.Increment(ref testVal);
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedTicks);

    sw = Stopwatch.StartNew();
    testVal = 0;
    for (int i = 0; i < ThreadsCount; ++i)
    {
        var myThread = new Thread(() =>
        {
            Interlocked.Increment(ref testVal);
        });
        myThread.Start();
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedTicks);
}

在我的系统上,内联执行需要 200 个刻度。对于线程来说,几乎有 200 万个时钟周期。因此,在这里使用线程大约需要 10,000 倍的时间。我在这里使用了 ElapsedTicks 而不是 ElapsedMilliseconds,因为使用 ElapsedMilliseconds 内联代码的输出为 0。线程版本大约需要 700 毫秒。上下文切换的成本很高。

此外,您的测试从根本上来说是有缺陷的,因为您在获取结果之前没有明确等待所有线程完成。您很有可能在最后一个线程完成递增之前输出 testVal 的值。

顺便说一句,当对代码进行计时时,您应该确保在不附加调试器的情况下以 Release模式运行它。在 Visual Studio 中,使用 Ctrl+F5(启动而不调试)。

关于c# - 为什么线程创建这么快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20293332/

相关文章:

java - 静态变量的线程安全

java - Selenium C# Java - WebDriver 和 IWebDriver 有什么区别?

c# - 我们可以在 C# 中使用流利的迁移器在 postgresql 中创建数据库吗

c# - 如何使用 C# 和 WinForm 创建 1 像素宽的窗口

c# - 在asp.net core 2.2中使用autofac

c# - 为什么我只能从一个供稿中获得 25 个 YouTube 视频?

multithreading - 双核超线程 : Should I use 4 threads or 3 or 2?

c# - 如何在Windows窗体应用程序C#中使用超链接属性

.net - .Net 的 RestfulRouting 更改默认 'id' 参数

iphone - NSFileManager:继续在后台写入磁盘吗?