【问题标题】:Why does a Ruby program/process spawn more than one thread?为什么一个 Ruby 程序/进程会产生多个线程?
【发布时间】:2018-12-26 12:32:31
【问题描述】:

正如标题所说,为什么一个 Ruby 程序或进程会产生多个线程?

例如,如果我运行这样一个简单的程序:

ruby -e 'while true; end'

然后尝试通过运行来计算该程序正在使用的线程数:

ps -o nlwp `echo $(ps aux | pgrep ruby)`

我得到了输出:

NLWP

2

这意味着该进程正在使用两个线程。

我在 Linux 上使用 CRuby/YARV 2.5.3。我也用 2.3.8 试过这个,得到了同样的结果。

编辑

对于 Ruby 2.6.0,它似乎只运行一个线程。但是,当我使用 --jit 选项启用 JIT 时,它会产生两个线程。

【问题讨论】:

  • 我假设“CRuby”是指 YARV,因为它是唯一一个发布编号为 2.3.8、2.5.3 或 2.6.0 的版本。 (CRuby 的描述性不是很好,因为例如 MRI、YARV、MRuby 和 tinyrb 是用 C 编写的。)有趣的是,在 macOS 10.13 上使用 YARV 2.6.0,我得到了 2 个不带 JIT 的线程和 3 个带 JIT 的线程。 MacOS 的 ps 没有 nlwp 关键字,所以我假设您使用不同的操作系统,也许这会起作用。

标签: ruby virtual-machine interpreter


【解决方案1】:

你没有说你使用的是哪个 Ruby 实现,所以我们只能猜测:

  • 一些 Ruby 实现为 I/O 使用单独的线程。
  • 一些 Ruby 实现具有并发垃圾收集器,即在单独线程中与 mutator 一起运行的垃圾收集器。
  • 一些 Ruby 实现具有并行垃圾收集器,即使用多个线程的垃圾收集器。
  • 一些 Ruby 实现具有并发并行垃圾收集器,即在多个单独线程中与 mutator 一起运行的垃圾收集器。
  • 一些 Ruby 实现具有并发 JIT 编译器,即在单独线程中与解释器一起运行的 JIT 编译器。
  • 一些 Ruby 实现具有并行 JIT 编译器,即使用多个线程的 JIT 编译器。
  • 一些 Ruby 实现具有并发并行 JIT 编译器,即在多个单独线程中与解释器一起运行的 JIT 编译器。
  • 一些 Ruby 实现使用多个消息传递 VM 实现并发,即它们在单独的线程中为每个 CPU 内核运行一个 VM 实例,并通过在这些 VM 之间传递它们来实现 Ruby 线程、纤程等。
  • 一些 Ruby 实现使用单独的线程实现跟踪和统计。
  • 某些 Ruby 实现本身可能在另一个运行时之上运行,该运行时可能会执行上述任何一项操作。

而且可能还有很多其他原因。

例如,YARV 2.6 将在不使用 JIT 的情况下使用 2 个线程(引擎和 I/O),在使用 JIT 运行时使用三个(加上 JIT)。

【讨论】:

  • Ruby 2.6,是的。
  • 我使用的是 CRuby 2.5.3。还在 CRuby 2.3.8 上尝试过。我编辑了问题。
【解决方案2】:

在您计算的两个进程中,一个进程确实是正在运行的 ruby​​ 进程。另一个是你的grep ruby

【讨论】:

  • 我认为这不准确。如果我试图通过计算/proc/PID/task 下的目录数来明确计算我的程序正在使用的线程数,我也会得到两个目录/线程。据我所知,另一个进程 grep 进程并没有干扰这里。
  • @aonemd:我对/proc/PID/task 的评论知之甚少(原始问题中也没有包含...),但就ps 而言,这答案完全正确。 ps 将返回一个用于实际 ruby​​ 进程的进程,另一个用于grep ruby 命令。
  • ...这就是pgrep 的用途。
猜你喜欢
  • 2018-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-25
  • 2011-08-01
  • 2014-10-19
  • 2013-03-10
  • 2012-11-30
相关资源
最近更新 更多