1

我正在做科学研究,通过数百万个兆字节数组的组合进行处理。

为了能够回答这个问题,您需要具备以下所有知识/经验

  • HHVM 如何在请求之间将数据结构缓存在 RAM 中
  • 如何告诉 HHVM 数据结构将保持不变
  • 如何声明数组索引和值类型

我需要处理整个数组,因此需要加载和处理大量数据。(局域网上数分钟内的数百万个请求)。我越快完成请求,我就能越快完成我的工作。如果 HHVM 必须在每个请求上加载这些数据,它会占用很大一部分时间来完成请求(有时超过一半,这取决于我当时正在进行的分析的复杂性)。

我找到了一种方法,可以让我将这些数据结构缓存在 RAM 中(不从文件加载,解释代码,无缘无故地向数组推送数十万次,没有毫无意义的重复反序列化等),因此我有消除了这种巨大的可测量延迟。

关于如何使这更快,我有 3 个问题:

  1. 我现在这样做的方式是否会造成全局范围的惩罚?
  2. 如何将我的数组声明为常量并告诉 HHVM 期望什么数据类型?如果我将我的数组声明为常量,是否甚至需要声明 HHVM 的类型?
  3. 如果我使用 3 个单独的数据结构 ImmVector、PackedArray 或定义一个类,而不是使用嵌套数组,它会更快吗?

请记住,任何阻止 HHVM 在请求之间将数据结构缓存到 RAM 中的行为都应该被视为不可接受的。

查找表35543.php

<?php
$data = [
    ["uuid (20 chars)", 5336, 7373],
    ["uuid (20 chars)", 5336, 7373],
    #more lines as above
];
?>

其中一些文件有很多 MB 大小,其中有很多 Main.php

<?php
function main() {
  require /path/to/Lookuptable35543.php;
  #(Do stuff with $data)
}
?>

这工作得很好,因为 Main.php 收到了数千个请求,在很短的时间内,HHVM 将 Lookuptable.php 的数据结构保存在内存中。避免无意义的处理和 IO,因为它只是位于 RAM 中,可供使用。(我有足够的内存)

不幸的是,我知道如何让 HHVM 将查找表保存在 RAM 中的唯一方法是,我在我的查找####.php 文件中的全局范围内设置 $data (然后将查找文件要求为数据处理中的函数文件:Main.php)?这样 HHVM 就不会费心加载文件或重新执行代码来创建 $data,因为它可以看到 $data 可以在编译时确定,并且在运行时它永远不会改变。这可行,但我不知道在查找###.php 文件的全局范围中存在 $data 是否会受到惩罚。(或者它可能根本不是全局的,因为它是required 进入 main.php 的函数?)

  1. 如果我从 Lookup.php 中的函数返回 $data 并像 Main.php 这样从 Main.php 调用该函数怎么办

HHVM JIT 会是 RAM 中 getData() 的结果吗?不知何故,我将函数与不可预测性联系起来......但也许 HHVM 足够聪明,知道函数结果可以在编译时确定,并且永远不会改变?

我不能将查找表放在 Main.php 中,因为我require根据请求的类型使用不同的查找表。

  1. 有没有办法告诉 HHVM 我的外部数组将始终具有一个永不改变的整数索引,并且外部数组的值将始终是一个数组?也许我需要使用 ImmVector?那么有没有办法告诉 HHVM 我的内部数组将始终是一个固定长度的字符串,后跟 2 个整数,总是,没有额外的元素,内容永远不会改变?

我宁愿不使用 OO 或创建一个类。如何声明类型、程序风格?如果课程是绝对必要的,您能否提供适合我上述要求的示例代码?

  1. 如果我不嵌套数组会更快吗?我刚刚意识到我可以拥有一个具有整数索引和固定长度字符串值的数组。然后是具有整数索引和整数值的第二个数组,以及具有整数索引和整数值的第三个数组。

如果您不熟悉这种 HHVM 缓存技术,请不要浪费时间建议数据库、redis、APC、反序列化等。HHVM 最快的方法是将我的各种 $data 变量保存在 RAM 中。即使从 ramdisk 文件中反序列化 $data 也很慢,因为必须将整个数据结构解析为字符串,并针对每个请求将其转换为内存中的数据结构。据我所知,APC 也有同样的问题。我什至不想复制 $data。查找表是不可变的,只读的。它们必须在 RAM 中保持完全结构化。我当前的缓存解决方案(在这个问题的顶部)已经给我带来了巨大的收益,但是根据我的 3 个问题,我认为可能会有更多的收益?

如果您想知道,我已经测量了各种数据加载或缓存方法的延迟。现在我基本上想保留我所拥有的缓存情况,但要让 HHVM JIT 对如何键入我的数据有最大的信心,这样它就可以节省不运行类型甚至绑定(数组大小)检查的时间。

编辑 好的,所以还没有人能给我任何代码示例,所以我只是在尝试一些东西。

这是我到目前为止所发现的。

  • const 数组在 HHVM 中还不能工作。const foo = ['uuid1',43,43]; 抛出有关 HHVM 仅支持具有标量值的常量的错误。

  • 带有数组值的向量:我还不知道它会如何执行......我希望它会比普通数组更好。这是有效的 HH 代码。

这是进步,因为 HHVM 应该能够以相同的方式缓存它,HHVM 知道整个结构是恒定的,并且 HHVM 知道索引都是整数。

我对这种结构仍然不完全满意的是:考虑这段代码

for ($n=0;$n<count($iv);++$n) if ($x > $iv[$n][1]) dosomething();

$if[$n][2]HHVM 会在每次循环迭代时执行类型检查吗?在我$iv上面的定义中,没有说内部数组的第二个元素是整数。我该如何改进呢?禁用类型检查器有什么用吗?这只是隐藏了外部类型检查器的错误,还是阻止了 HHVM 不断地进行类型检查?(我认为这是第一件事)

也许如果我可以创建自己的用户定义类型来解决问题?

<?hh
#I don't know what mechanisms for UDT's exist, so this code is made-up
CreateUDT foo = <string,int,int>;
$iv = ImmVector<foo> {
    ['uuid1',425,244],
    ['uuid2',658,836]
};
print_r($iv);

我在 Hack Collections Literal Syntax Vector<Foo>找到了对此的参考,不幸的是它可能还不能使用。

4

2 回答 2

1

我是 Facebook 的一名软件工程师,从事 HHVM 方面的工作。

这整个问题对我来说都是过早的优化。您是否完成了分析并确定加载此数组实际上是您的应用程序的瓶颈?(不仅仅是微基准,还有它如何实际影响实际页面加载的性能、延迟、RPS 等。)并且还与其他影响隔离,例如,如果这个数组是缓存或某种预先计算的数据,你需要隔离通过以各种不同的方式缓存数据,从实际时间预计算数据以加载数据。

一般来说,HHVM 非常擅长处理数组,因为它们在几乎每个代码路径中都非常热门——尤其是在像这样的常量数组中。对于您关于如何告知它数组中事物的形状和类型的问题,HHVM 可以自己解决所有问题,并且非常擅长处理完全由常量组成的常量数组。(而且它对数组的看法与您对数组的看法不太一样,所以它可能无论如何都可以做得更好!)基本上,除非分析表明这实际上是一个热点——我对此持怀疑态度—— - 我不会太担心。需要注意的几个一般注意事项:

  • 测量每个性能差异。不要过早地优化——使用分析来指导。过早的优化阻碍了开发人员的生产力,这可能是致命的。
  • 尽可能多地从顶层(“伪域”)中获取内容。返回一个static或常量数组的函数应该很好,并且通常会帮助 HHVM 更好地优化代码。
  • 尽可能避免引用,特别是在你非常关心性能的情况下在这个数组中。
  • 您可能应该研究一下repo 权威模式,它可以帮助 HHVM 进一步优化很多东西——但特别是在这种情况下,repo auth 模式可以做的更积极的内联可能是一个胜利。

编辑,一边

因为那时必须将整个数据结构解析为字符串,并针对每个请求将其转换为内存中的数据结构。据我所知,APC 有同样的问题

这正是我所说的过早优化的意思:你甚至没有尝试就拒绝了 APC,即使它可能是一种更清洁的方式来做你想做的事。事实证明,在大多数情况下,HHVM 实际上可以优化 APC 中存储数组的序列化/反序列化,尤其是当它们是永远不会修改的常量数组时。如上所述,HHVM 非常擅长优化许多常见模式。只需编写干净的代码,对其进行分析,然后修复热点。

于 2015-05-11T04:03:00.010 回答
0

好的,我已经解决了我的第一个问题。

  1. 我没有任何全局范围问题。我的要求是从函数 main() 内部完成的,所以就好像 lookuptable####.php 中的代码被插入到函数 main() 中一样。 HHVM 文档:“如果包含出现在函数内部……” 基本上,如果您要打开 lookuptable####.php,看起来代码在全局范围内,但这不是从 hhvm 请求的文件。main.php 是被请求的,因此在全局范围内没有代码。

  2. 我想我已经回答了我的第二个问题,它目前在我的问题的底部。我不是 100% 相信的,但我很高兴继续前进并对其进行测试。

于 2015-05-11T11:18:08.777 回答