如何修复循环中的php内存问题

时间:2017-11-23 12:53:07

标签: php

我有一个循环,通过给出所需的位数来生成所有可能的位组合,问题是当位数超过20时,我的内存已经耗尽,是否有任何可以进行的优化,解决这个问题。

这里是我的代码:

function bitsGenerator($N)
{
    $listN = $N;
    $bits = ['0', '1'];

    //check if input is valid or not
    if (!is_int($listN)) {
        echo 'Input must be numeric!';
    }

    if ($listN >= 1 && $listN <= 65) {
        if ($listN == 1) {
            echo '1';
            exit;
        }

        for ($i = 1; $i <= ($listN - 1); $i++) {
            $reverseBits = array_reverse($bits);

            $prefixBit = preg_filter('/^/', '0', $bits);

            $prefixReverseBits = preg_filter('/^/', '1', $reverseBits);

            $bits = array_merge($prefixBit, $prefixReverseBits);

            unset($prefixBit, $prefixReverseBits, $reverseBits);
        }

        $finalBits = array_slice($bits, -$listN);

        foreach ($finalBits as $k => $v) {
            echo $v . "\n";
        }
    } else {
        echo 'Invalid input!';
    }
}

此函数的目的是获取最后$N组合并显示它们所有其他组合被丢弃,我正在寻找我的代码的某种优化,以便$ bits数组将不存储超过 65 项目,因为最大数量到位因此显示的最大组合数为65.

感谢每一个人帮助我。

1 个答案:

答案 0 :(得分:0)

主要问题是保存所有结果的$bits数组的大小。该数组将包含2 ^ $ N个元素,每个元素的N个长度乘以8位(因为您使用字符串具有前导零),因此您最终将获得大约(2 ^ N)的内存消耗* $ N * 8,即167772160字节。使用RAM时,它不会变小。

$bitspreg_filterarray_merge的工作副本也会占用大量内存。使用$N = 20运行您的函数会消耗180375552(172MiB)。

BTW:unset变量不会减少消耗的RAM,因为无论如何它们都会在下一次迭代中被覆盖(或者在函数结束时被破坏)

以下函数是我的第一个基于您的函数的草图,使用的RAM少一点:171970560字节或164MiB(对172MiB)。

function myBitsGenerator($length)
{
    if (!is_int($length)) {
        die('Input must be numeric!');
    }

    if ($length < 1 || $length > 65) {
        die('Input must be between 1 and 65');
    }

    $bitsArray = ['0', '1'];
    $count = 2;

    if ($length > 1) {
        for ($i = 0; $i < $length; $i++) {
            for ($j = 0; $j < $count; $j++) {
                $bitsArray[] = $bitsArray[$j] . '1';
                $bitsArray[$j] = $bitsArray[$j] . '0';
            }
            $count += $j;
        }
    }

    $printArray = array_slice($bitsArray, $count - $length);

    array_walk(
        $printArray,
        function ($value) {
            echo $value . PHP_EOL;
        }
    );
}

但是,这些数字的生成过于复杂,应该简化:

理论:二进制数可以用十进制数写,反之亦然。固定长度为$ N的二进制数的可能组合数为x = 2 ^ $N。从0到x的每个十进制数表示结果中的二进制数。

实际例子 :(二进制)(0b101 === 5)(int)

您只需要用零填充计算的二进制数。

简化的生成器看起来像:

    $n = pow(2, $length);
    for ($i = 0; $i < $iterations; $i++) {
        $binary = str_pad(decbin($i), $length, '0', STR_PAD_LEFT);
    }

您可以使用此生成器生成

如果你真的需要使用更少的RAM,你应该考虑将它存储在一个文件中,这会让整个想法变得更慢,但它会减少使用RAM。

function fileBitsGenerator($length)
{
    $handle = fopen('bits.txt', 'w+');

    $iterations = pow(2, $length);

    for ($i = 0; $i < $iterations; $i++) {
        fwrite($handle, str_pad(decbin($i), $length, '0', STR_PAD_LEFT) . PHP_EOL);
    }
}

这只消耗2097152个字节并进行扩展! 但请注意,性能将取决于您的HDD / SSD速度,并执行大量写入操作(这可能会缩短您的SSD寿命)。例如:如果length = 22

,则生成的文件bits.txt为92MB