如何让ruby pry停止所有其他线程

pgu*_*rio 16 ruby multithreading pry

我正在尝试调试多线程ruby脚本,问题出在我做的时候

binding.pry
Run Code Online (Sandbox Code Playgroud)

其他线程继续将输出发送到控制台.如何让它们在binding.pry停止然后在我退出时再次启动?我想在.pryrc中有一种方法可以做到这一点

ano*_*rmh 6

听起来您似乎建议使用 的调用binding.pry来询问所有子线程并挂起它们,直到您结束 pry 会话。由于技术和实际原因,这是不可能的。和类不是这样工作的,Ruby 中的多线程也不是这样工作的BindingThread

Ruby 中的线程只能通过调用Kernel#sleep或 来挂起Thread.stop(并且这些方法在功能上是等效的)至关重要的是,这些方法只能在当前线程上调用。一个线程不能挂起另一个线程。(Thread.stop是类方法,不是实例方法)

让我们看看实际做了什么: Bindingbinding.pry类的对象将执行上下文封装在代码中的某个特定位置,并保留此上下文以供将来使用。因此,当您放入代码时,您就是在告诉 Ruby 封装当前线程的执行上下文。binding.pry

这意味着当您binding.pry在主线程中调用 Binding 对象时,它具有当前线程的上下文,并且可以告诉自己休眠,但核心 Ruby Thread 类不允许它告诉任何其他线程休眠。

即使它确实支持它,也会很奇怪并且容易出错,并且会引起很多麻烦。想象一下您有这样的代码:

# we are in the main thread
Thread.new do
  # we are in the child thread
  foo = Foo.new(bar.fetch(:baz, {}))
  foo.save
end

# we are in the main thread
binding.pry
Run Code Online (Sandbox Code Playgroud)

由于 Ruby 处理上下文切换的方式,如果告诉所有子线程停止,那么子线程可能会停止调用堆栈中的任何位置,包括或binding.pry代码中的任何位置。让这些线程在执行您未编写的代码的过程中暂停和恢复会给您带来麻烦。例如,如果从池中检出 ActiveRecord 连接并将其用于查询,但线程在将连接返回到池中且获得响应之前进入睡眠状态,会发生什么情况?不好的东西。很多不好的东西。Foo.new.saveSELECT

听起来对您来说真正的解决方案是更改子线程的详细程度。如果您正在对繁琐的代码进行故障排除,并且当您尝试在单个线程中工作时其他线程很吵闹,那么请设置其他线程使用,例如暂时设置较低的日志记录级别。


lax*_*089 4

如果 binding.pry 产生不一致的结果,请尝试以下操作:

  1. 如果存在,请pry-stack_explorer从您的 gemfile 中删除,然后重新打包您的应用程序。该宝石似乎有问题 pry-byebug

  2. 此外,不确定您是否已经尝试过此操作,但重新启动一些服务器不会有什么坏处;这为我解决了类似奇怪的问题,这种情况比我愿意承认的还要频繁。

然而,您可能正在尝试做一些用 binding.pry 根本无法完成的事情:

必须理解的一个基本原理binding.pry是,它的范围仅包括当前线程,而不是您所描述的多线程应用程序中的每个线程。

假设,如果binding.pry确实影响每个线程(同样,它不会),这将导致不可预测的行为,特别是如果某些线程正在执行数据访问/检索/更新操作。

为了实现您想要的目标,您可能需要采取不同的方法:

尽管这可能很乏味,具体取决于应用程序中有多少线程,但您可能需要单独控制/停止每个线程。显然,这可以通过 来完成Thread.stop