2014-10-10 77 views
3

这是一个相当普遍的计算机科学问题,并不针对任何操作系统或框架。线程池和上下文切换(任务)?

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

对于在特定线程(在线程池中)切换任务相关的开销,我只是有点困惑(无法找到深入的答案)。 DrDobbs的一篇文章(来源于下文)说明了它的作用,但我需要更深入地回答实际发生的事情(可以引用的来源会非常棒:))。

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

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

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

回答

0

本文可能会讨论将工作发布到池中并等待其结果的情况。通常在线程池上运行任务不会导致任何上下文切换开销。

想象一下排队1000个工作项目。线程池线程将一个接一个地执行它们。所有这些之间没有一个单独的上下文切换。

切换发生等待/阻塞。

+0

这开始变得更有意义(有点)。所以“线程池”线程并没有实际的上下文切换。文章指出有一个上下文切换来排队任务(即将任务移动到线程池)。你是说同样的事情吗?线程池不上下文切换,但任务呢?即将任务从创建任务的线程移动到将运行任务的线程 – smjpl 2014-10-10 18:34:50

+0

任务只是一个数据结构(一个函数指针)。队列也只是数据。内核不参与排队任务或执行它们。没有开关。 – usr 2014-10-10 18:49:26

+0

那么为什么我们需要确保任务足够大,如果在线程池中排队和运行任务没有任何相关开销?从文章(第1页):“另一方面,任务不应该太短,因为执行工作作为线程池任务存在实际成本。” – smjpl 2014-10-10 19:05:53

2

let's这里澄清前5个关键概念,然后再讨论他们在一个线程池的背景下如何关联:

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

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

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

上下文切换是什么线程。一项任务仅代表一项可以分配给待执行线程的工作安宁。在给定的时刻,一个线程可以执行任务。

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

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

表示线程池的使用场景:

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

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

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

如果你的任务没有在某个地方编写代码块,那么上下文切换会被最小化,因为它不会使用比机器上可用的cpus更多的线程。

当然,如果你只有一个内核,你的主线程和线程池将竞争相同的CPU。