3

我尝试“ http://thrift-tutorial.readthedocs.org/en/latest/usage-example.html ”中的示例。这个例子只是计算两个数字的乘积。服务器:Java,客户端:Python。

如果我尝试通过 thrift 获得产品 3000 次,则经过的时间约为 4.8 秒。如果我在 python 中创建一个简单的函数(乘法)并直接调用它 3000 次,则经过的时间约为 0.007 秒(快 686 倍)。

那么如何提高性能呢?我想构建一个应用程序并将其分成一些子应用程序。它们可以用多种语言实现,并且它们将通过 thrift 相互通信,但是由于性能如此糟糕,我应该考虑将它们组合到单独的应用程序中吗?

App-A (Java)                   App-B (Python)
     |                                 |
     |------------ App-C (C++) --------|

或者

App-A+C (Java)                   App-B+C (Python)
(implement C in Java)            (implement C in Python)
4

2 回答 2

3

您可以将两个关键优化设置为目标:

  • 在等待之前发送您已经拥有的所有数据。
  • 如果唯一要做的事情是直接将其发送回来,则不要通过通道发送计算结果。

您在问题中描述的是“聊天协议”的极端情况。网络有延迟(delay)。如果在开始下一次计算之前等待每个结果,则大部分时间都花在等待网络传输上,而不是等待实际计算。通过在收到第一个结果之前发送另一个计算,您可以显着提高吞吐量。

所以最简单的事情是允许重叠请求。第二对值的乘积不依赖于第一个结果,所以不要等待第一个结果到达。

当您处理本地 IPC 时,这并没有太大帮助。通信的成本不是延迟,而是消息处理和线程同步,取决于请求的数量,而不是顺序。

更大回报的更大变化是让每个请求都代表一个复杂的算法。例如,不是远程调用两个数字的乘法,而是尝试远程调用整个过滤操作,其中参数是整个数据向量或矩阵,服务器将执行 FFT、倍数、逆 FFT、缩放、然后将结果传回。这同时满足了最初的目标:所有可用数据一起发送,而不是单独发送,从而减少等待时间。由于不必交换中间结果,因此减少了总网络流量。


最后一种选择是将所有三种语言的代码链接到一个进程中,以便直接访问数据和函数调用。许多语言允许构建导出纯“C”函数和数据的对象。

此外,.NET 等虚拟机运行的中间语言可以从不同源语言的编译中生成。使用 .NET,您有 C#(类似 Java)、C++/CLI(支持完整的 C++,以及用于处理 .NET 数据的扩展)和 IronPython,它们涵盖了您的问题图。加上 F#、JavaScript、Ruby 变体等等。Java 虚拟机应该是特定于语言的,但人们已经编写了 Clojure 和其他编译为字节码的语言。

虚拟机技术的优势在于它可以实现一些跨语言优化(.NET JIT 进行跨模块内联)。缺点是您的性能取决于 JIT 优化,这通常是最低的公分母。C++/CLI 实际上非常适合弥合这一差距,因为它支持完全优化的本机代码(包括 SIMD)、.NET 中间语言 (MSIL) 以及用于它们之间通信的最低开销层(C++ “It Just Works”互操作) )。

但是您可以在 Java VM 上完成大致相同的事情,方法是使用 JNI 连接完全优化的 C++ 代码,以使用 SIMD 进行密集的数字运算。

于 2014-04-03T18:39:10.080 回答
1

您的比较是基于不正确的假设。假设是,跨进程调用(至少)与进程内调用一样快,这根本不是真的。

这是著名的8 网络谬误之一,起源于 Peter Deutsch,后来被其他人扩展,不仅适用于网络,还适用于单台机器上的 IPC:与您的想法相反,传输成本不是零

根据您有限的信息,我可以告诉您,每次 IPC 往返 1.5 毫秒对我来说听起来还不错。

于 2014-04-03T18:34:21.267 回答