【问题标题】:Does increasing number of cores speed up execution time of a program where threads currently have 50% IO contention?增加内核数量是否会加快线程当前具有 50% IO 争用的程序的执行时间?
【发布时间】:2017-05-18 02:58:09
【问题描述】:

向一个在 IO 上花费 50% 等待时间的程序添加更多内核会有所收获吗?我得到了完全 IO 绑定和 CPU 绑定的琐碎案例,但我不完全确定每个线程花费部分时间等待 IO 的情况。

我的直觉是,通过添加内核,每个线程现在都有更多的 IO 争用。所以现在每个线程可能会花费大约 60% 的时间来等待 IO。所以结果是净中性甚至净负。

编辑
Threads: Fast IO - Slow CPU
Threads: Balanced IO and CPU

这些是一些简单情况的示例图,我试图了解添加线程/内核如何影响 IO 等待时间。

我看到的一件有趣的事情是任务 IO 时间和任务 CPU 之间的比率决定了额外线程的有用性。例如,如果 IO = 10ms 和 CPU = 40ms,那么总任务时间 = 50ms。 50ms/10ms = 5,因此这种情况可能会受益于 5 个线程,但可能不会再提高性能。

这是正确的吗?

【问题讨论】:

  • 嗯,当然。如果程序有一个线程在 I/O 上花费 50%,那么添加另一个线程可以使其速度提高一倍。一个的 IO 等待时间将与另一个的计算时间重叠。添加第三个线程并不会使其更快。
  • @HansPassant 我有点困惑。如果我有 10 个线程/内核在运行并且它们都花费 50% 的时间在等待 IO 上会怎样?将线程/内核加倍到 20 是否意味着执行时间会减少一半,但更多的内核将无济于事?
  • 那么得出的正确结论是基准测试中存在错误或有人试图完成他的家庭作业。你必须自己思考,做功课的意义。
  • @HansPassant - 该评论是不必要的。我没有做作业,我试图理解一些事情。我是并发新手,所以求助于 stackoverflow 之类的地方。我已经进行了基准测试来测试这一点,但我仍在尝试了解底层机制以使我的理解更加完整。
  • 我很明确,如果这不是家庭作业,那么基准就被打破了。因此,如果您需要帮助,请向我们展示基准代码。其他任何事情都只是在浪费大家的时间。

标签: multithreading concurrency io


【解决方案1】:

这取决于。您如何定义“I/O 争用”?如果您的意思是当前线程都在尝试使用共享 I/O 设备/介质,并且它们必须“排队等待”才能使用它,那么:是的,您应该期望添加 更多的线程进入同一个队列,它会增加等待时间的百分比。

这样看。如果共享 I/O 非常可预测会怎样。每次在共享介质上发出 I/O 请求时,大约需要 10 毫秒。然后,您将在所有线程中每秒最多发出 100 个 I/O 请求。如果你有 10 个线程,那么每个线程平均每秒发出 10 个请求。将 CPU 缩放到这个值,我们还假设它的 CPU 使用率是面向请求的。也就是说,假设为每个 I/O 请求存储的计算需要 50 毫秒。您现在将 50% 的时间花在“I/O 争用”上。每一秒你都会得到 10 个周期 [准备请求 (50ms) + 执行 I/O (50ms)]。

现在,如果您将 10 个线程增加到 20 个,那么您现在有两倍的线程尝试使用同样有限的每秒 100 个请求的资源。现在每个线程平均每秒只能发出 5 个请求。这意味着它每秒花费 250 毫秒 (5 x 50 毫秒) 的 CPU 时间来准备请求,并在 I/O 队列中等待 750 毫秒。因此,通过将线程数加倍,您现在将 75% 的每线程时间用于争用共享资源。

添加线程将继续增加您的 I/O 争用 - 总是有一些线程在取得进展,因此它永远不会达到 100%(平均而言),但您可以接近。如果您有 100 个线程,那么每个线程每秒只能完成一个请求(因此,50 毫秒 CPU + 950 毫秒等待 = 95% 的争用)。如果您有一千个线程/内核,现在只有十分之一的人每秒完成一个请求(99.5% 的争用,每个线程工作 50 毫秒,然后在 I/O 轮到等待 9.95 秒)。

【讨论】:

  • 这很有道理,谢谢。我实际上编辑了我的问题并添加了您所描述内容的图表(数字略有不同)。我认为我认为更多的线程争用 = 更差的性能让自己感到困惑。如果我理解正确,那么添加线程是有帮助的,即使单个线程有更多的争用,只要共同进行更多的处理。最终,如果我理解正确,添加更多线程将无济于事。
  • 是的。我会说这完全取决于你的线程在做什么。如果正在执行的 I/O 您试图实现的最终结果(如在我的思想实验中)那么,一旦 I/O 资源保持“饱和”,就没有什么意义了在添加新线程。
  • I/O 的行为也存在差异。例如,如果您在现代操作系统上进行 I/O 写入 [例如,写入硬盘],那么这些通常是近乎瞬时的(至少 直到某些队列填满) - 即操作系统即使 I/O 实际上只是排队,也会说“是的,已经完成了”。另一方面,I/O 读取往往是串行/同步的:通常在完成之前无法继续。
猜你喜欢
  • 1970-01-01
  • 2021-06-09
  • 2020-03-07
  • 1970-01-01
  • 2016-07-04
  • 2022-09-27
  • 2018-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多