2

我正在使用 savon gem 与肥皂 api 进行交互。我正在尝试使用并行 gem 向 api 发送三个并行请求。通常每个请求大约需要 13 秒才能完成,因此三个请求大约需要 39 秒。在使用并行 gem 并使用 3 个线程发送三个并行请求后,完成所有三个请求大约需要 23 秒,这非常好,但我无法弄清楚为什么它没有在 14-15 秒内完成它。我真的需要降低总时间,因为它直接影响我网站的响应时间。关于为什么会发生的任何想法?网络请求本质上是阻塞的吗?

我发送请求如下

Parallel.map(["GDSSpecialReturn", "Normal", "LCCSpecialReturn"], :in_threads => 3){ |promo_plan| self.search_request(promo_plan) }

我也尝试使用多个进程,但没有用。

4

2 回答 2

3

我有两个理论:

  • 部分工作负载无法并行运行,因此您看不到 3 倍加速,但比这要少一些。很少看到多线程任务与使用的 CPU 数量成比例地加速 100%,因为总是有几个位必须一次运行一个。请参阅Amdahl 定律,它提供了描述这一点的方程式,并指出:

在并行计算中使用多个处理器的程序的加速受到程序顺序部分所需时间的限制

  • 涉及磁盘 I/O,由于磁盘寻道时间,并行运行速度较慢,限制了每秒的 IO。请记住,除非您在 SSD 上,否则每次您在磁盘上寻找不同的东西时,磁盘都必须进行物理旋转。一次有 3 个请求,磁盘会重复跳过磁盘以尝试满足 3 个不同位置的 I/O 请求。这就是为什么硬盘驱动器上的随机 I/O比顺序 I/O 慢得多的原因。即使在 SSD 上,随机 I/O 也可能会慢一些,尤其是在涉及小块读写的情况下。

如果您在同一系统上运行数据库,我认为选项 2 是罪魁祸首。 问题是当 SOAP 调用访问数据库时,它会同时受到这两个因素的影响。即使是速度极快的 15000 RPM 服务器硬盘,每秒也只能管理约 200 次 IO 操作。SSD 将执行 10,000-100,000+ IO/s。请参阅 Wikipedia 上的有关球场的数据。不过,大多数数据库都会做一些巧妙的内存缓存来缓解这些问题。

测试它是否为因素 2 的一种聪明方法是运行H2 数据库内存数据库并使用它测试 SOAP 调用。它们可能会更快地完成,并且您应该一次看到类似的 1,3 或 $CPU-COUNT 请求的执行时间。

于 2013-08-02T12:19:50.833 回答
1

这实际上是一个大问题,它取决于许多因素。

1.Ruby语言实现

MRI、Rubinus、JRuby 之间可能有所不同。我不确定并行 gem 是否支持 Rubinus 和 JRuby。

2. 你的机器

您的机器中有多少个 CPU 内核,您可以使用并行进程来利用它吗?如果您有多个内核,您是否尝试过使用 process 执行此操作?

Parallel.map(["GDSSpecialReturn", "Normal", "LCCSpecialReturn"]){ |promo_plan| self.search_request(promo_plan) } # by default it will use [number] of processes if you have [number] of CPUs

3. 下划线发生了什么self.search_request

如果你在 MRI 环境中运行它,导致GIL,它实际上不是同时运行你的代码。或者准确地说,IO调用不会阻塞(MRI实现),所以只有网络调用部分会同时运行而不是所有其他部分。这就是为什么我对你在self.search_request中所做的其他工作感兴趣的原因,因为这会对整体性能产生影响。


所以我建议你可以在不同的环境和不同的机器上测试你的代码(你的本地机器和真实的生产机器可能会有所不同,所以请尝试调整和基准测试)以获得最佳结果。

顺便说一句,如果您想了解更多关于 ruby​​ 中的线程/进程的信息,强烈推荐Jesse StorimerWorking with ruby​​ threads,他很好地解释了所有这些事情。

希望有帮助,谢谢。

于 2013-07-26T20:42:46.120 回答