代码之家  ›  专栏  ›  技术社区  ›  jdt141

创建线程时有多少开销?

  •  33
  • jdt141  · 技术社区  · 14 年前

    我刚刚回顾了一些非常糟糕的代码——在串行端口上发送消息的代码,它创建了一个新的线程来打包,并为发送的每个消息将消息组装到一个新的线程中。是的,对于创建pthread的每条消息,正确设置位,然后线程终止。我不知道为什么有人会做这样的事情,但它提出了一个问题——在实际创建线程时有多少开销?

    9 回复  |  直到 8 年前
        1
  •  7
  •   Tony Delroy    14 年前

    …在串行端口上发送消息…对于创建pthread的每条消息,正确设置位,然后线程终止。…在实际创建线程时有多少开销?

    这是高度系统特定的。例如,我上一次使用vms线程是非常慢的(几年了,但是从内存来看,一个线程可以每秒创建10个线程(如果在线程不退出的情况下保持几秒钟),而在Linux上,您可能可以创建数千个线程。如果你想确切地知道,可以在你的系统上进行基准测试。但是,仅仅知道在不了解更多消息的情况下并没有多大用处:它们是平均5字节还是100K,它们是连续发送的还是中间的空闲行,以及应用程序的延迟要求与代码线程使用的适当性有关,就像对线程创建的任何绝对测量一样。开销。性能可能不需要成为主要的设计考虑因素。

        2
  •  35
  •   Nafnlaus    10 年前

    为了恢复这个旧线程,我只做了一些简单的测试代码:

    #include <thread>
    
    int main(int argc, char** argv)
    {
      for (volatile int i = 0; i < 500000; i++)
        std::thread([](){}).detach();
      return 0;
    }
    

    我用 g++ test.cpp -std=c++11 -lpthread -O3 -o test . 然后,我在一台旧的(内核2.6.18)重负荷(进行数据库重建)低速笔记本电脑(IntelCorei5-2540m)上连续运行了三次。连续三次运行的结果是:5.647秒、5.515秒和5.561秒。所以我们在这台机器上每线程的速度都会超过10微秒,可能更不用说你的了。

    考虑到串行端口的最大输出速度约为每10微秒1位,这一开销根本不算多。现在,当然还有许多额外的线程丢失,包括传递/捕获的参数(尽管函数调用本身可以施加一些)、核心之间的缓存速度减慢(如果不同核心上的多个线程同时在同一内存上进行争用)等。但是,一般来说,我高度怀疑您提出的用例将dVersely完全影响性能(并且可能提供好处,具体取决于),尽管您已经预先将概念标记为“非常糟糕的代码”,而不知道启动线程需要多长时间。

    这是不是一个好主意很大程度上取决于你处境的细节。调用线程还负责什么?在准备和写出数据包的过程中究竟涉及到什么?它们被写出的频率(以什么样的分布方式?均匀、成簇等?它们的结构是什么样的?系统有多少个核心?等等,根据具体情况,最佳解决方案可以是从“根本没有线程”到“共享线程池”再到“每个包的线程”。

    请注意,线程池并不神奇,在某些情况下,与唯一线程相比,线程池的速度可能会减慢,因为线程的最大减速之一是同步多个线程同时使用的缓存内存,而线程池由于其必须查找和处理来自不同线程的更新的性质而必须这样做。因此,如果处理器不确定另一个进程是否改变了内存的一部分,那么您的主线程或子处理线程可能会被卡住,不得不等待。相比之下,在理想情况下,给定任务的唯一处理线程只需与调用任务共享一次内存(启动时),然后它们就再也不会互相干扰了。

        3
  •  11
  •   Michael Goldshteyn    14 年前

    你肯定不想这样做。创建单个线程或线程池,并在消息可用时发出信号。一旦接收到信号,线程就可以执行任何必要的消息处理。

    在开销方面,线程创建/销毁(尤其是在Windows上)相当昂贵。在几十微秒左右,具体来说。在大多数情况下,它应该只在应用程序的开始/结束时完成,可能的例外是动态调整线程池的大小。

        4
  •  11
  •   ubiquibacon    14 年前

    我一直被告知线程创建是便宜的,特别是与创建进程的替代方法相比。如果您所讨论的程序没有很多需要并发运行的操作,那么线程可能就不必要了,根据您编写的内容判断,情况很可能是这样的。一些文献支持我:

    http://www.personal.kent.edu/~rmuhamma/OpSystems/Myos/threads.htm

    从这个意义上说,线程是便宜的

    1. 它们只需要寄存器的堆栈和存储 因此,线程的创建成本很低。

    2. 线程很少使用操作系统的资源 他们正在工作。也就是说, 线程不需要新的地址空间, 全局数据、程序代码或操作 系统资源。

    3. 使用线程时,上下文切换很快。原因是 我们只需要保存和/或 恢复PC、SP和寄存器。

    更多相同的 here .

    Operating System Concepts 8th Edition (第155页)作者写了线程的好处:

    为进程创建分配内存和资源是昂贵的。 因为 线程共享的资源 他们所属的过程 更经济的创造和 上下文切换线程。经验性的 测量高架罐的差异 很难,但总的来说 创建和 管理进程而不是线程。在 例如,创建一个 过程大约慢三十倍 创建线程和上下文 切换速度大约慢了五倍。

        5
  •  8
  •   ruslik    14 年前

    线程创建过程中会有一些开销,但与串行端口的波特率通常较低(19200位/秒是最常见的)相比,这并不重要。

        6
  •  3
  •   Mario The Spoon    14 年前

    线程中的线程创建和计算非常昂贵。 所有的数据结构都需要设置,用内核注册的线程和线程开关必须发生,这样新线程才能实际执行(在未指定和不可预测的时间)。 执行thread.start并不意味着立即调用线程主函数。 正如文章(通过打字提到的)所指出的,创建线程只比创建进程便宜。总的来说,它相当昂贵。

    我永远不会用线

    • 为了简单的计算
    • 在我的代码流中需要结果的计算(即 意思是,我正在启动线程 等待它返回 这是计算

    在您的示例中,创建一个处理所有串行通信并且是永恒的线程是有意义的(正如已经指出的那样)。

    高温高压

    马里奥

        7
  •  3
  •   Lunar Mushrooms    11 年前

    要进行比较,请看一下OSX: Link

    • 内核数据结构:大约1 kb堆栈空间:512 kb (辅助线程):8 MB(OS X主线程),1 MB(IOS主线程) 线程)

    • 创建时间:大约90微秒

    我想POSIX线程的创建也应该围绕这个(不远的数字)进行。

        8
  •  2
  •   R.. GitHub STOP HELPING ICE    14 年前

    在任何健全的实现中,线程创建的成本应该与它所涉及的系统调用的数量成正比,并且与熟悉的系统调用的数量级相同,如 open read . 我的系统上的一些偶然测量显示 pthread_create 花费的时间大约是 open("/dev/null", O_RDWR) 相对于纯计算来说,这是非常昂贵的,但是相对于任何IO或其他涉及用户和内核空间之间切换的操作来说,这是非常便宜的。

        9
  •  2
  •   user2074102    8 年前

    我在自己制作的VoIP应用程序中使用了上述“糟糕”的设计。它工作得很好…对于本地连接的计算机,绝对没有延迟或丢失/丢弃的数据包。每次数据包到达时,都会创建一个线程,并将该数据传递给输出设备进行处理。当然,数据包很大,所以不会造成瓶颈。同时,主线程可以返回等待并接收另一个传入的包。

    我尝试过其他设计,其中我需要的线程是预先创建的,但这会造成它自己的问题。首先,您需要为线程正确地设计代码,以便检索传入的数据包并以确定性的方式处理它们。如果您使用多个(预分配的)线程,则可能会“无序”处理数据包。如果您使用一个(预先分配的)线程来循环和接收传入的数据包,那么线程可能会遇到问题并终止,而不留下任何线程来处理任何数据。

    创建一个线程来处理每个传入的数据包工作非常干净,特别是在多核系统上,并且传入的数据包很大。另外,为了更直接地回答您的问题,创建线程的替代方法是创建一个管理预分配线程的运行时进程。能够同步数据传递和处理以及检测错误可能会增加与创建新线程相同的开销,甚至更多。这完全取决于您的设计和需求。