【问题标题】:Code take too long to process and has a big memory footprint代码处理时间过长并且内存占用很大
【发布时间】:2011-04-30 15:55:11
【问题描述】:

这段代码执行时间为 0.8 秒,占用了我机器上 22Mb 的内存。

   $x=500;
   $y=500;

   $im = imagecreatetruecolor($x,$y);
   $ia=array();
   for ($i = 0; $i < $x; $i++) {
    for ($j = 0; $j < $y; $j++) {
        $r=rand(0,96);
        $g=rand(0,128);
        $b=rand(0,255);
        $ia[$i][$j]=ImageColorAllocate($im,$r,$g,$b);
    }
   }

可以做些什么来加快它,但更重要的是降低它在任何给定时间消耗的内存占用。

【问题讨论】:

  • 您可以预先填充随机颜色列表,然后从这些颜色中进行选择,而不是每次都创建一个新实例。虽然,我不确定 php 的内存分配和收集是如何工作的。
  • 随机颜色不是这里的问题,这只是为了解决问题而填充数组的一些代码。问题在于迭代和数组占用的内存。答案不需要涵盖调色板。
  • 如果更改$x$y,内存使用情况如何变化?
  • @david: 100x100=0.04591s/1.31Mb/131bytes/像素
  • 300x300=0.37025s/8.91Mb/99bytes/像素

标签: php algorithm memory-management gd spl


【解决方案1】:

您的函数总共进行了一百万次迭代,这总是需要相当多的 PHP 脚本来完成。

但是,您可以做一些事情。

首先,mt_rand() 比 rand() 快,请改用它。

其次,如果您在内循环上使用循环展开,您可能会获得一些速度提升。我不确定这在 PHP 中的实际效果如何,但您可以对其进行基准测试以查看它的效果。

for ($j=0;$j<$y;$j+=10) {
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j]=ImageColorAllocate($im,$r,$g,$b);
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j + 1]=ImageColorAllocate($im,$r,$g,$b);
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j + 2]=ImageColorAllocate($im,$r,$g,$b);
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j + 3]=ImageColorAllocate($im,$r,$g,$b);
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j + 4]=ImageColorAllocate($im,$r,$g,$b);
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j + 5]=ImageColorAllocate($im,$r,$g,$b);
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j + 6]=ImageColorAllocate($im,$r,$g,$b);
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j + 7]=ImageColorAllocate($im,$r,$g,$b);
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j + 8]=ImageColorAllocate($im,$r,$g,$b);
    $r=mt_rand(0,96);
    $g=mt_rand(0,128);
    $b=mt_rand(0,255);
    $ia[$i][$j + 9]=ImageColorAllocate($im,$r,$g,$b);
}

但是,这些都不会减少内存占用,因为您正在构建的数据结构基本上是一个大数据结构。

也许您从错误的方向看待这个问题?您在这里真正应该问自己的第一件事是,您真的需要如此庞大的数据结构来完成您想做的事情吗?循环展开和使用更快的随机数生成器会给你带来一些性能提升,但最终你可以拥有的最快的代码是你不编写的代码。任何给定算法的性能的最大因素始终是算法的选择。如果您重新考虑您想要做什么,您可能会想出一些不浪费计算机内存和处理资源的方法。

【讨论】:

  • 首先,我认为您的意思是循环增量为$j += 10。其次,与其用一个丑陋的硬代码展开(它本身会降低性能),不如只使用一个带有一些模数运算的变量并将循环体保持在原始的 4 行,它可能具有相同的运行时间。我怀疑这两种技术一起会改变任何明显的运行时间......
  • 每个 PHP 变量最少占用 68 个字节。由于您使用的是二维数组,因此您会导致 x*y*68 字节(在您的情况下为 500*500*68 = 17 MB)内存消耗只是为了存储数组。直接对位图进行操作会更节省内存。
  • 似乎这增加了时间并且内存使用是相同的,顺便说一句:代码已经从 v1.0 开始优化。目的是创建更大的图像,这会消耗大量的内存,所以......寻求其他选择
  • @davin:是的,发现并修复了它。您可能对建议的更改没有太大影响是对的,但我也确实指出算法的选择是最重要的因素。 @jmz 每个变量真的是 68 个字节吗?哇。 @alix:这是一种称为循环展开的技术,通常在其他语言中用于从循环中获得更多性能,尽管我不知道在 PHP 中这样做会有多有效。可以这么说,这几乎是从臀部射击。
【解决方案2】:

试试下面的代码(来自http://php.net/manual/en/function.imagecolorallocate.php),而不是直接分配颜色:

function createcolor($pic,$c1,$c2,$c3) {
   $color = imagecolorexact($pic, $c1, $c2, $c3);
   if($color==-1) {
      if(imagecolorstotal($pic)>=1000) {
         $color = imagecolorclosest($pic, $c1, $c2, $c3);
      } else {
         $color = imagecolorallocate($pic, $c1, $c2, $c3);
      }
   }
   return $color;
 }

另外,尝试在 1 行中调用函数:

$ia[$i][$j] = createcolor($im, mt_rand(0,96), mt_rand(0,128), mt_rand(0,255));

摆弄硬编码值 1000,看看它如何改变内存使用情况。

【讨论】:

  • 这会更慢(而且不等价),但会消耗更少的内存。
  • @Alix,我认为值得一试,因为它可能只会对速度产生轻微影响,但会更大程度地减少内存消耗,尽管 OP 没有发表评论,所以这一切都只是猜测......它不是等效的,但如果节省的内存很大,则可能值得失去调色板大小。
  • 确实,我误解了您的代码。这几乎是我的答案,除了它不需要(另一个)巨大的数组,+1!
【解决方案3】:

据我所知,imagecreatetruecolor 可能是最有可能成为内存猪的罪魁祸首。

您可以使用其他方法(例如 imagecreate)来创建图像吗?

【讨论】:

  • 在一个数组中分配 250.000 种颜色可能也会消耗一点内存...
【解决方案4】:

我可以在您的代码中看到的唯一改进是不会多次分配相同的颜色(在您的情况下,3.203.328 颜色为 500.000 像素),这应该减少您的内存占用:

$x = 500;
$y = 500;

$image = ImageCreateTrueColor($x, $y);
$matrix = array();
$colors = array();

for ($i = 0; $i < $x; $i++)
{
    for ($j = 0; $j < $y; $j++)
    {
        $rand = array(rand(0, 96), rand(0, 128), rand(0, 255));

        if (isset($colors[implode('|', $rand)]) !== true)
        {
            $colors[implode('|', $rand)] = ImageColorAllocate($im, $rand[0], $rand[1], $rand[2]);
        }

        $ia[$i][$j] = $colors[implode('|', $rand)];
    }
}

另外,如果您不需要真彩色图像,ImageCreate() 应该不会占用太多内存。


我不确定您要归档什么,但可能是 you would be better with mt_rand()

【讨论】:

    猜你喜欢
    • 2023-03-06
    • 2018-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 2014-10-21
    • 2022-01-06
    • 2013-07-12
    相关资源
    最近更新 更多