9

我很感兴趣在 Java、C# 和 C++ 中创建线程的实际成本是多少?我知道当线程在创建时必须完成一堆操作:分配线程堆栈,初始化描述符等。

但我对实际成本很感兴趣。C# 和 Java 使用不同的 VM 和不同的 JIT,而 C++ 执行本机代码。因此,所有这些语言的线程创建时间都不同。我还听说在 Java 中创建线程比在 C# 中慢得多。有人可以就这个问题给出权威的答案和解释吗?

4

3 回答 3

8

在 C#、Java 和 Visual C++ 中创建 10,000 个线程的基准测试:

C#

class Program
{
    static void Main(string[] args)
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        for (int i = 0; i < 10000; i++)
        {
            Thread thread = new Thread(DoNothing);
            thread.Start();
        }
        watch.Stop();
        Console.WriteLine(watch.Elapsed);
    }

    static void DoNothing()
    {
        //Do Nothing
    }
}

结果:1.7638042 秒

爪哇

public class ThreadBencher {

    public static void main(String[] args) {
        Runnable r = new Runnable() {
             public void run() {
                 //Do nothing
             }
         };

         long startTime = System.nanoTime();
         for (int i = 0; i < 10000; i++) {
             Thread thread = new Thread(r);
             thread.start();
         }
         long stopTime = System.nanoTime();
         long totalTime = stopTime - startTime;
         System.out.print(totalTime);

    }

}

结果:1.514557805 秒(或 1514557805 纳秒)

视觉 C++

DWORD WINAPI DoNothing( LPVOID lpParam ) 
{
    return 0;
}

void main()
{
    HANDLE ourThreadHandle = 0;
    SYSTEMTIME st1;
    SYSTEMTIME st2;
    int i;
    GetLocalTime(&st1);
    for (i = 0; i < 10000; i++) {
        ourThreadHandle = CreateThread( NULL, 0, DoNothing, 0, 0, NULL);
    }
    GetLocalTime(&st2);
    double dblSt1 = st1.wSecond + (st1.wMilliseconds / 1000);
    double dblSt2 = st2.wSecond + (st2.wMilliseconds / 1000);
    double result = dblSt2 - dblSt1;
    cout << st1.wSecond << "." << st1.wMilliseconds << endl;
    cout << st2.wSecond << "." << st2.wMilliseconds << endl;
}

结果(根据输出手动计算后):0.925 秒

(免责声明:我不太了解 C++,所以 C++ 代码非常拼凑在一起)

注意:这是在 64 位 Windows 8 环境中完成的。

于 2013-10-12T20:22:57.037 回答
5

这就是创建线程时发生的情况。

创建新线程时,它会与其他线程共享其代码段、数据段和操作系统资源(如打开的文件)。但它被分配了自己的堆栈、寄存器集和程序计数器。

线程成本

线程在内存使用和性能方面对您的程序(和系统)有实际的影响。每个线程都需要在内核内存空间和程序的内存空间中分配内存。

管理线程和协调其调度所需的核心结构使用有线内存存储在内核中。线程的堆栈空间和每个线程的数据存储在程序的内存空间中。

大多数这些结构都是在您第一次创建线程时创建和初始化的——由于需要与内核交互,这个过程可能相对昂贵。

其中一些成本是可配置的,例如为辅助线程分配的堆栈空间量。创建线程的时间成本是一个粗略的近似值,仅用于相互比较。线程创建时间可能会因处理器负载、计算机速度以及可用系统和程序内存的数量而有很大差异。

在此处输入图像描述

线程不消耗内存(除了它们的堆栈,它是恒定大小的);进程消耗内存。线程的全部意义在于它们共享进程状态。

默认情况下,公共语言运行时(CLR) 线程的堆栈空间设置为(由 CLR 提供)1MB(64 位代码线程为 4MB)。

在 C++ 中,它为堆栈保留 1MB(它映射其地址空间),但它不一定分配在物理内存中,只是其中的一小部分。如果堆栈增长超过该值,则会生成页面错误并分配更多物理内存。

Java 线程的创建很昂贵,因为涉及到相当多的工作:

  • 必须为线程堆栈分配和初始化一大块内存。

  • 需要进行系统调用以使用主机操作系统创建/注册本机线程。

  • 需要创建、初始化描述符并将其添加到 JVM 内部数据结构中。

从某种意义上说,只要线程还活着,它就会占用资源,这也是昂贵的。例如线程堆栈、从堆栈可访问的任何对象、JVM 线程描述符、OS 本机线程描述符。

于 2013-10-15T12:50:01.973 回答
0

C++ 通常是一种运行速度更快的语言,尽管它可能是一种更难学习的语言;因此需要更长的时间来理解更多的基本功能,这可能会减慢编写应用程序时的编码过程

于 2013-10-14T06:34:59.260 回答