【问题标题】:"Work stealing" vs. "Work shrugging"?“偷工作”与“工作耸肩”?
【发布时间】:2011-02-02 21:55:39
【问题描述】:

为什么我可以找到很多关于“工作窃取”的信息,而没有找到关于“工作耸肩”作为动态负载平衡策略的信息?

“工作耸耸肩”我的意思是 将多余的工作从繁忙的处理器推到负载较轻的邻居,而不是让空闲的处理器繁忙的邻居的工作(“工作——偷窃”)。

我认为这两种策略的总体可扩展性应该相同。但是,我认为,就延迟和功耗而言,在肯定有工作要做时唤醒空闲处理器会更有效,而不是让所有空闲处理器定期轮询所有邻居以寻找可能的工作。

无论如何,快速谷歌并没有在“工作耸耸肩”或类似标题下显示任何内容,因此欢迎任何指向现有技术和该策略的行话的指针。

澄清

我实际上设想工作提交处理器(可能是也可能不是目标处理器)负责查看首选目标处理器的直接位置(基于数据/代码位置)以决定是否应该将新工作交给近邻,因为他们没有那么多工作要做。

我认为决策逻辑只需要原子读取此处的直接(通常为 2 到 4 个)邻居的估计 q 长度。我不认为这比盗贼从他们的邻居那里轮询和偷窃所暗示的耦合更多。 (我在这两种策略中都假设“无锁、无等待”队列)。

分辨率

似乎我的意思(但只是部分描述!)“工作耸耸肩”策略属于“正常”的前期调度策略领域,这些策略恰好对处理器、缓存和内存忠诚度以及可扩展性很聪明。

我发现很多参考文献都在搜索这些术语,其中一些看起来很可靠。当我确定一个最符合(或破坏!)我对“工作耸肩”定义的逻辑时,我会发布一个参考。

【问题讨论】:

  • 你加“tm”有什么用?? SO 不是营销培训场
  • 这不是社区 wiki 问题;这里有一个正确的答案。
  • @Andres:社区 Wiki 并不意味着“没有正确答案”——它的意思是“社区可以编辑”。
  • 触摸!我现在更快乐了。 :-)

标签: terminology scheduling load-balancing scheduled-tasks multiprocessor


【解决方案1】:

负载均衡不是免费的;它的代价是上下文切换(到内核)、查找空闲处理器以及选择重新分配的工作。尤其是在一台任务一直切换的机器上,每秒几十次,这个成本加起来。

那么有什么区别呢?工作耸肩意味着您通过负载平衡的开销进一步负担过度配置的资源(繁忙的处理器)。当隔壁有一个处理器无事可做时,为什么要中断一个繁忙的处理器呢?另一方面,工作窃取让空闲处理器运行负载平衡器,而忙碌的处理器继续工作。偷工减料可以节省时间。

示例

考虑:处理器 A 有两个任务分配给它。它们分别需要时间 a1a2。附近的处理器 B(可能是缓存反弹的距离)处于空闲状态。处理器在所有方面都是相同的。我们假设每个任务的代码和内核都在两个处理器的 i-cache 中(在负载平衡上没有添加页面错误)。

任何类型的上下文切换(包括负载平衡)都需要时间c.

无负载平衡

完成任务的时间将是 a1 + a2 + c。 处理器 A 将完成所有工作,并在两个任务之间进行一次上下文切换。

工作窃取

假设 B 窃取 a2, 会导致上下文切换时间本身。这项工作将在 max(a1, a2 + c) 时间内完成。假设处理器 A 开始在 a1; 上工作,同时处理器 B 将窃取 a2 并避免 a1 处理中的任何中断。 B 上的所有开销都是空闲周期。

如果 a2 是更短的任务,那么在这种情况下,您有效地隐藏了上下文切换的成本;总时间为a1.

工作耸耸肩

假设 B 完成 a2, 如上所述,但 A 产生移动它的成本(“耸耸肩”工作)。本例中的工作将在 max(a1, a2) + c 时间内完成;上下文切换现在总是添加到总时间,而不是被隐藏。处理器 B 的空闲周期在这里被浪费了;相反,繁忙的处理器 A 已经把工作交给 B 浪费了时间。

【讨论】:

  • 感谢 Andres - 这个社区很棒!但是我意识到要简洁地表达一个问题并包含足够的上下文是多么困难!我实际上并不关心处理器虚拟化/上下文切换问题!在我的应用程序中,我有 N 个线程绑定到 N 个物理处理器。他们得到的工作保证是非阻塞的。我不希望处理器在有工作时(没有轮询/睡眠延迟)很快就达到标准,而在没有工作的时候(最好甚至不接触内存)。跨度>
  • 我所描述的直接适用于物理线程。 “任务”=“线程”。至于在任务创建时立即分配工作,您描述的机制听起来不错。如果现代调度程序还没有这样做,我会感到震惊,也许考虑到缓存效果。
  • 哦,是的,我现在明白了。您的方程式也适用于物理情况(我被提到内核/上下文切换蒙蔽了双眼)。我现在正在研究“现代调度程序”等 - thnx - 问题已更新。
【解决方案2】:

一些问题...如果一个繁忙的线程很忙,您是否不希望它花时间处理实际工作,而不是推测性地寻找空闲线程来卸载?

您的线程如何决定什么时候它有这么多工作应该停止工作以寻找可以提供帮助的朋友?

你怎么知道其他线程没有那么多工作并且你找不到合适的线程来卸载?

工作窃取似乎更优雅,因为解决相同问题(争用)的方式可以保证执行负载平衡的线程只执行负载平衡,否则它们本来会处于空闲状态。

我的直觉是,从长远来看,您所描述的不仅效率会低得多,而且需要对每个系统进行大量调整才能获得可接受的结果。

尽管在您的编辑中建议您希望提交处理器来处理此问题,而不是您之前建议的工作线程以及此处的某些 cmets。如果提交处理器正在搜索最短的队列长度,那么您可能会增加提交延迟,这并不是一个真正可取的事情。

但更重要的是,它是对工作窃取的补充技术,而不是相互排斥的技术。你已经潜在地缓解了一些关于工作窃取是为了控制而发明的争论,但是在你得到好的结果之前你还有很多事情需要调整,这些调整不会对每个系统都是一样的,而且你仍然有可能遇到偷工减料对你有帮助的情况。

我认为您编辑的建议,提交线程执行“智能”工作分配可能是针对工作窃取的过早优化。您的空闲线程是否如此猛烈地撞击总线,以至于您的非空闲线程无法完成任何工作?然后是优化工作窃取的时候了。

【讨论】:

    【解决方案3】:

    因此,与“Work Stealing”相比,这里“Work Shrugging”的真正含义是一种正常的前期工作调度策略,它对处理器、缓存和内存忠诚度以及可扩展。

    搜索上述术语/行话的组合会产生许多重要的后续参考。一些解决了机器虚拟化的附加复杂性,这实际上并不是提问者关心的问题,但一般策略仍然是相关的。

    【讨论】:

      【解决方案4】:

      “工作窃取”算法的基本优势在于,当每个人都很忙时,移动工作的开销会降至 0。因此,只有在某些处理器本来空闲时才会产生开销,并且开销成本主要由空闲处理器支付,而繁忙的处理器只需要很少的总线同步相关成本。

      【讨论】:

      • 是的,这是“偷工减料”的明显好处。我考虑替代窃取的一个激励问题是空闲处理器获取到达其附近的多余工作的延迟?我发现的偷文件和例子都归结为投票周期有多快。我想,总而言之,我的应用程序需要在一个处理器上发出突发负载,以迅速分散到不太忙的,包括空闲的邻居。我准备支付一些适度的前期开销,以尽量减少所涉及的延迟。
      • 好吧,我说的是前期(缓存状态和内存节点感知)“动态负载分配” - 我在这方面得到了很多可靠的结果。
      【解决方案5】:

      我认为这个想法的问题在于它使有实际工作的线程浪费时间不断地寻找空闲的处理器。当然,有一些方法可以提高速度,比如拥有一个空闲处理器队列,但随后该队列成为并发瓶颈。所以最好让那些无事可做的线程坐下来寻找工作。

      【讨论】:

      • 谢谢 - 我实际上并没有设想任何处理器不断寻找空闲处理器或全局队列 - 只是在有新工作可用时偷看邻居 - 我不认为这种耦合比小偷偷看更重要在邻居那里工作 - 我在我的问题中包含了更多细节。
      【解决方案6】:

      据我所知,工作窃取是为高度并行的系统设计的,以避免让单个位置(单个线程或单个内存区域)负责共享工作。为了避免这个瓶颈,我认为它确实在简单的情况下引入了低效率。

      如果您的应用程序不是那么并行,以至于单点工作分布会导致可伸缩性问题,那么我希望您可以按照您的建议通过显式管理它来获得更好的性能。

      恐怕不知道你会用谷歌搜索什么。

      【讨论】:

      • 我对 Work-Shrugging 的看法是可扩展的(我认为!) - 每个处理器将负责将多余的工作推给负载较轻的邻居(NUMA、LAN 或 WAN),而不是拉动工作对自己。我对这个问题做了一些澄清。 - thnx
      猜你喜欢
      • 2015-11-20
      • 1970-01-01
      • 2021-05-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-21
      • 2015-05-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多