我正在进行科学研究,通过<强大>数百万的多兆字节阵列组合进行处理。
为了能够回答这个问题,您需要具备以下所有知识/经验
我需要处理整个数组,因此需要加载和处理大量数据。 (在局域网上几分钟内就有数百万的请求)。我可以更快地完成请求,我可以更快地完成工作。如果HHVM必须在每个请求上加载这些数据,它会占用完请求的很大一部分时间(有时超过一半,这取决于我当时正在进行的分析的复杂性)
我找到了一种方法,它允许我将这些数据结构保存在RAM中(无需从文件加载,解释代码,无理由地推送到数组数十万次,没有无意义的重复反序列化等),以及因此,我已经消除了这种巨大的可衡量的延迟。
关于如何使更快
,我有3个问题请记住,任何阻止HHVM在请求之间缓存RAM中的数据结构的行为都应被视为不可接受。
Lookuptable35543.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中,随时可以使用。 (我有足够的RAM)
不幸的是,我知道如何让HHVM在RAM中保存查找表的唯一方法是,我在查找####。php文件中的全局范围内设置$ data(然后将查找文件放入函数中)数据处理文件:Main.php)?这样HHVM就不会费心加载文件或重新执行代码来创建$ data,因为它可以看到$ data可以在编译时确定,并且在运行时它不会改变。这有效,但我不知道在查找###。php文件的全局范围内是否存在$ data存在惩罚。 (或者它可能不是全局的,因为它是require
到main.php的功能?)
如果我从Lookup.php中的函数返回$ data并从Main.php调用该函数怎么样? Main.php
HHVM JIT会在RAM中产生getData()的结果吗? 不知怎的,我把函数与不可预测性联系起来......但是HHVM可能很聪明,知道函数结果可以在编译时确定,而且永远不会改变?
我无法将查找表放在Main.php中,因为根据请求的类型我require
个不同的查找表。
我不想使用OO或创建课程。我怎样才能声明类型,程序风格? 如果一个课程是绝对必要的,您能否提供适合我上述要求的示例代码?
如果您不熟悉这种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();
HHVM会在每次循环迭代时对$if[$n][2]
执行类型检查吗?
在我上面对$iv
的定义中,没有任何内容表明内部数组的第二个元素是一个整数。
我该如何改进呢?
disabling the type checker可以用吗?这是否只隐藏外部类型检查器的错误,还是阻止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>中找到了对此的引用,遗憾的是它可能尚未可用。
答案 0 :(得分:1)
我是Facebook的一名软件工程师,负责HHVM。
这整个问题让我过早优化。您是否完成了分析并确定加载此阵列实际上是您的应用程序的瓶颈? (不仅仅是微基准,而是它如何影响现实页面加载的性能,延迟,RPS等。)并且还与其他效果隔离,例如,如果此数组是缓存或某种预先计算的数据,您需要通过以各种不同的方式缓存数据与实际时间来预先计算数据,以加载数据。
通常,HHVM非常擅长处理数组,因为它们几乎在每个代码路径中都很热 - 特别是在像这样的常量数组中。关于如何告知数组中事物的形状和类型的问题,HHVM可以自己解决这个问题,并且非常在完全由常量组成的常量数组上做得很好。 (它对数组的思考方式并不是你对数组的思考方式,所以无论如何它都可以做得更好!)基本上,除非分析说这实际上是一个热点 - - 我对此持怀疑态度 - 我不会过分担心它。一些注意事项需要注意:
static
或常量数组的函数应该没问题,并且通常可以帮助HHVM更好地优化代码。编辑,旁边:
因为那时必须将整个数据结构解析为字符串,并在每个请求的内存中转换为数据结构。就我所知,APC遇到同样的问题
这正是我过早优化的意思:你甚至在没有尝试的情况下拒绝接受APC,即使它可能是一种更干净的方式来做你想做的事情。事实证明,在大多数情况下,HHVM实际上可以优化APC中存储数组的序列化/反序列化,特别是如果它们是永不修改的常量数组。如上所述,HHVM非常擅长优化大量常见模式。只需编写干净的代码,对其进行分析并修复热点即可。
答案 1 :(得分:0)
好的,我已经解决了我的第一个问题。
我没有任何全球范围问题。我的需求是从函数main()内部完成的,所以它好像是可查询的####。php中的代码被插入到函数main()中。 HHVM docs: "If the include occurs inside a function..." 基本上,如果您打开可查找的####。php,它看起来像代码在全局范围内,但那不是从hhvm请求的文件。 main.php是被请求的,因此全局范围内没有代码。
我想我已回答了我的第二个问题,它目前在我的问题的最底层。我并非100%相信,但我很乐意继续前进并进行测试。