【问题标题】:Thread pools and context switching (tasks)?线程池和上下文切换(任务)?
【发布时间】:2014-12-05 23:12:12
【问题描述】:

这是一个相当普遍的计算机科学问题,并不特定于任何操作系统或框架。

所以我对在线程池上切换任务相关的开销感到有些困惑。在许多情况下,为每个作业分配自己的特定线程是没有意义的(我们不想创建太多硬件线程),因此我们将这些作业放入可以安排在线程上运行的任务中。我们设置了一个线程池,然后动态分配任务以在从线程池中取出的线程上运行。

对于与在特定线程(线程池中)上切换任务相关的开销,我有点困惑(无法找到深入的答案)。 DrDobbs 的一篇文章(来源如下)指出确实如此,但我需要更深入地回答实际发生的事情(可引用的来源会很棒:))。

根据定义,SomeWork 必须在池中排队,然后运行 与原始线程不同的线程。这意味着我们必然 产生排队开销加上上下文切换只是为了将工作移动到 游泳池。如果我们需要回复原始答案 线程,例如通过消息或未来或类似的,我们将招致 另一个上下文切换。

来源:http://www.drdobbs.com/parallel/use-thread-pools-correctly-keep-tasks-sh/216500409?pgno=1

线程的哪些组件实际上在切换?线程本身实际上并没有切换,只是特定于线程的数据。与此相关的开销是多少(更多、更少或相同)?

【问题讨论】:

    标签: task threadpool context-switch


    【解决方案1】:

    让我们在这里澄清前 5 个关键概念,然后讨论它们在线程池上下文中的相关性:

    • 线程: 在简短的简历中,它可以被描述为程序执行上下文,由正在运行的代码、cpu 注册表中的数据和堆栈给出。创建线程时,会为其分配应在该线程上下文中执行的代码。在每个 cpu 周期中,线程都有一条指令要执行,并且 cpu 注册表和堆栈中的数据处于给定状态。

    • 任务: 代表一个工作单元。它是分配给要执行的线程的代码。

    • 上下文切换(来自维基百科): 是存储和恢复线程状态(上下文)的过程,以便以后可以从同一点恢复执行。这使多个进程能够共享一个 CPU,并且是多任务操作系统的基本特征。如上所述,构成上下文的是正在执行的代码、cpu 注册表和堆栈。

    上下文切换是线程。任务仅代表可以分配给要执行的线程的工作和平。在给定的时刻,一个线程可以执行一个任务。

    • 线程池(来自维基百科): 在计算机编程中,线程池是创建多个线程以执行多个任务的地方,这些任务通常组织在一个队列中。

    • 线程池队列: 放置任务以由池中的线程执行的位置。这种数据结构是内存的共享和平,其中线程可能会竞争队列/出队,可能会导致高负载情况下的争用。

    说明一个线程池使用场景:

    • 在您的程序中(最终在主线程中运行),您创建一个任务并安排它在线程池中执行。
    • 任务在线程池队列中排队。
    • 当池中的一个线程执行时,它会从池中取出一个任务并开始执行它。
    • 如果没有可用的 CPU 来执行池中的线程,操作系统会在某个时间点(取决于线程调度程序策略和线程优先级)停止执行线程,并将上下文切换到其他线程。

    操作系统可以随时停止一个线程的执行,上下文切换到另一个线程,返回后者继续它停止的地方。

    当竞争 cpu 的活动线程数量增加时,上下文切换的开销会增加。因此,理想情况下,线程池会尝试使用最少的必要线程来占用机器中所有可用的 CPU。

    如果您的任务没有在某处阻塞的代码,则会最小化上下文切换,因为它使用的线程数不超过机器上可用的 cpu。

    当然如果你只有一个核心,你的主线程和线程池会竞争同一个cpu。

    【讨论】:

      【解决方案2】:

      文章大概讲了工作被发布到池中并等待结果的情况。在线程池上运行任务通常不会产生任何上下文切换开销。

      想象一下排队 1000 个工作项。线程池线程将一个接一个地执行它们。所有这一切都无需在两者之间进行一次上下文切换。

      切换发生在等待/阻塞。

      【讨论】:

      • 这开始变得更有意义(有点)。所以“线程池”线程实际上并没有上下文切换。文章指出有一个上下文切换来排队任务(即将任务移动到线程池)。你在说同样的话吗?线程池不进行上下文切换,但任务呢?即将任务从创建任务的线程移动到将运行任务的线程
      • 任务只是一个数据结构(一个函数指针)。队列也只是数据。内核不参与排队任务或执行它们。没有开关。
      • 那么,如果没有与在线程池上排队和运行任务相关的开销,为什么我们需要确保任务足够大呢?来自文章(第 1 页):“另一方面,任务不应该太短,因为将工作作为线程池任务执行是有实际成本的。”
      • 存在与处理工作相关的开销。联锁操作和其他基础设施代码。只是不是很多。想象一下只用一条指令运行任务。显然,开销将占主导地位。
      猜你喜欢
      • 2012-01-12
      • 2018-04-18
      • 1970-01-01
      • 2017-09-09
      • 2011-07-23
      • 2021-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多