为了账号安全,请及时绑定邮箱和手机立即绑定

我如何优化这个 for 循环以在 PHP 上快速运行。在 javascript 上运行得非常快

我如何优化这个 for 循环以在 PHP 上快速运行。在 javascript 上运行得非常快

PHP
慕田峪7331174 2021-11-26 19:27:55
所以我一直在将一些代码从 Javascript 移植到现在可以运行的 PHP 中,但是,执行时间很短。在 PHP 中大约需要 26 秒,而在 javascript 中它非常快。我已经能够将其分解为导致问题的 for 循环。这是循环for ($R0d = 0; $R0d < $F0d; $R0d = $R0d + 16) {                $f0d = [bitwise_and(JS_charCodeAt($C0d,($R0d + 4)), 0xff) | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($R0d + 5)), 0xff)), 8) | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($R0d + 6)), 255)), 16) | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($R0d + 7)), 255)), 24), bitwise_and(JS_charCodeAt($C0d, ($R0d)), 255) | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($R0d + 1)), 255)), 8) | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($R0d + 2)), 255)), 16) | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($R0d + 3)), 0xff)), 24)];                $f0d = x64Multiply($f0d, $M0d);                $f0d = x64Rotl($f0d, 31);                $f0d = x64Multiply($f0d, $I0d);                $P0d = x64Xor($P0d, $f0d);                $P0d = x64Rotl($P0d, 27);                $P0d = x64Add($P0d, $o0d);                $P0d = x64Add(x64Multiply($P0d, [0, 5]), [0, 1390208809]);                $H0d = x64Multiply($H0d, $I0d);                $H0d = x64Rotl($H0d, 33);                $H0d = x64Multiply($H0d, $M0d);                $o0d = x64Xor($o0d, $H0d);                $o0d = x64Rotl($o0d, 31);                $o0d = x64Add($o0d, $P0d);                $o0d = x64Add(x64Multiply($o0d, [0, 5]), [0, 944331445]);                   }`每个单独的函数调用都很好,我已经看到每次迭代大约需要 0.01 秒,而对于我在这段代码中使用的测试字符串,大约需要 24-27 秒。这次的循环运行了 2444 次。想象$F0d = 39104无论如何,我是否可以像在使用 JavaScript 的浏览器中那样将执行时间缩短到不到一秒?
查看完整描述

2 回答

?
慕的地6264312

TA贡献1817条经验 获得超6个赞

如果这是 MurmurHash,那么去看看https://github.com/lastguest/murmurhash-php。

否则,您可以摆脱大量不必要的函数调用,如下所示:


for ($i = 0; $i < $F0d; $i += 16) {

    // Let's start with this block. What does it do? It clearly takes a block of 8 bytes

    // four at a time, and builds a pair of 32-bit words.

    // Each byte is AND-ed bitwise with 0xFF to ensure it is a 8-bit value.

    $f0d = [

        bitwise_and(JS_charCodeAt($C0d, ($i + 4)), 0xff)

        | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($i + 5)), 0xff)), 8)

        | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($i + 6)), 255)), 16)

        | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($i + 7)), 255)), 24),

        bitwise_and(JS_charCodeAt($C0d, ($i)), 255)

        | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($i + 1)), 255)), 8)

        | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($i + 2)), 255)), 16)

        | shift_left_32((bitwise_and(JS_charCodeAt($C0d, ($i + 3)), 0xff)), 24),

    ];

    // We can do the same thing in PHP using the unpack() function and type V on an appropriate substr() of $C0d.

    // But due to the vagaries of unpack() and the fact that the elements are reversed,

    // we cannot use unpack alone (well, we COULD, if we changed the algorithm below, but it would be too awkward).

    $x0d = array_reverse(array_values(unpack('V2', substr($C0d, $i, 8))));


    // If you now dump $f0d and $x0d, they should be identical.

    // You can do the same with $H0d. 


    // Actually you can do both together, avoiding the array manipulation, BUT I HAVEN'T CHECKED (just do a simple test run and verify $x0d's contents comparing it to $f0d and $H0d's):


    $x0d = unpack('V4', substr($C0d, $i, 16));

    $f0d = [ $x0d[2], $x0d[1] ];

    $H0d = [ $x0d[4], $x0d[3] ];


    // and get all 16 bytes neatly converted in two two-32-bit word arrays.


查看完整回答
反对 回复 2021-11-26
?
慕沐林林

TA贡献2016条经验 获得超9个赞

您的主要问题在于错误编写的 JS_charCodeAt 函数。通过增加输入大小,性能呈指数级下降,因为每次调用单个字符时,此函数都会从 UTF8 - UTF16 转换整个输入。


添加这个简单的缓存将工作时间减少了 100 倍。只需替换此功能:


function JS_charCodeAt($str, $index) {

    static $utf16s = [];

    if (isset($utf16s[$str]))

        $utf16 = $utf16s[$str];

    else

        $utf16s[$str] = $utf16 = mb_convert_encoding($str, 'UTF-16LE', 'UTF-8');

    return ord($utf16[$index*2]) + (ord($utf16[$index*2+1]) << 8);

}

当然,有很多事情是错误的,但这是非常容易和快速修复的,并且会产生最大的不同。到目前为止,如果您需要更高的性能,我可以进一步研究它。但该代码真的应该完全重写,这是一团糟。但现在它至少有效。




查看完整回答
反对 回复 2021-11-26
  • 2 回答
  • 0 关注
  • 180 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信