multithreading - 这个 Ruby 代码会在 Puma 下使用非阻塞 I/O 吗?

标签 multithreading ruby-on-rails-4 blocking puma

我正在调查旧版 Rails 应用程序中的一些瓶颈。除其他外,它使用以下类的对象作为 Controller 响应主体向(防火墙)后端服务器发出一些 HTTP 请求并将响应流式传输到客户端:

class Streamer
  def initialize(url)
    @url = url
  end

  def each 
    client = HTTPClient.new
    client.receive_timeout = 7200
    client.send_timeout = 3600
    client.connect_timeout = 7200
    client.keep_alive_timeout = 3600

    client.get_content(@url) { |chunk|
      yield chunk
    }

  end
end

我是 Ruby I/O 和线程方面的新手,而且我也不是 Rails 方面的专家。设计假设似乎是这个(在 MRI 上运行)只会在每个 block 中锁定解释器一次,并且当数据来自 HTTPClient 时其他线程可以执行。 ,或者去浏览器——这个假设有效吗?还是这段代码会让 Puma 的其他线程饿死?

最佳答案

答案是肯定的和否定的,主要是因为问题中的术语有些不清楚。

阻塞 IO 表示 IO 正在等待数据。 HTTPClient使用阻塞 IO。它等待数据可用,只有在收到数据后才返回。

非阻塞 IO 意味着 IO 层立即返回,即使没有数据存在(通常带有错误 EAGAIN 或 EWOULDBLOCK)。
HTTPClient模块阻塞控制流,等待 HTTP 服务器的响应。

但是,这不会阻止其他线程“并行”运行(或者,对于 Ruby MRI,交叉运行)。

The design assumption seems to be that this (running on MRI) is only going to lock the interpreter once per chunk, and that other threads can execute while data is either coming in from the HTTPClient, or going out to the browser -- is that assumption valid?



一般来说,假设是正确的(或足够接近以至于无关紧要)。

Ruby MRI 中的 GIL(全局解释器锁)强制 Ruby 代码执行单线程。它阻止了真正的并行性,让人想起单核 CPU 机器使用的多线程模型。

但是,由于 IO 代码在 GIL 之外执行,其他线程将在 IO 等待传入数据时运行(阻塞 writereadselect )。

通常,Ruby 将管理线程调度以交错 Ruby 线程执行,允许并发执行(尽管不是并行执行)。

Or is this code going to starve Puma's other threads?



不知道你说的饿死是什么意思...

该代码将饿死 Puma 的线程 游泳池 ,但线程本身将继续不受阻碍地运行。

澄清:

Puma 有一个用于 HTTP 请求和任务处理的线程池。线程数是有限的。

HTTPClient 线程将被“卡住”,等待 IO 完成并且不会返回线程池,从而减少池(作为一个整体)并可能导致资源匮乏。

例如,如果所有线程都在等待 HTTPClient 响应,则在线程再次可用之前不会处理任何请求(HTTPClient 和其余工作完成)。

另一方面,线程本身将允许其他线程同时运行,使用交错调度。所以,其他线程不会饿死,但 Puma 整体可能会饿死。

关于multithreading - 这个 Ruby 代码会在 Puma 下使用非阻塞 I/O 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51029903/

相关文章:

objective-c - 当 Cocoa 应用程序中的主线程被阻塞时,UI 不会更新

java - 如何创建 session 范围的线程安全对象实例?

c# - System.Threading.ThreadPool 与信号量?

ruby-on-rails - Rails 4 : Add mail attachment as remote . pdf 文件

c - c - 如何退出或停止正在运行的线程?

mysql - 将参数发送到 ROR 中的存储过程的安全方法

ruby-on-rails-4 - 使用 capistrano 3 部署到 Unicorn 服务器时出错

kotlin - 如何使用Kotlin协同程序正确进行阻止服务调用?

node.js - NodeJS WebSockets (ws) 模块是否实现了背压?

几分钟后,Go 爬虫在从输出 channel 中选择时停止