在foreach循环参数中展开一个数组 [英] Exploding an array within a foreach loop parameter

查看:125
本文介绍了在foreach循环参数中展开一个数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  foreach(explode(','$ foo)as $ bar){...} 



  $ test = explode(','$ foo); 
foreach($ test as $ bar){...}

在第一个例子,是否为每次迭代爆炸 $ $ foo 字符串还是PHP保存在内存中爆炸在它自己的临时变量?从效率的角度来看,创建额外变量 $ test 还是几乎相等?

解决方案

我可以做一个有根据的猜测,但是我们试试看吧!



有三种主要方法可以解决这个问题。
$ b $ ol <

  • 在进入循环之前进行爆炸和分配

  • 爆炸在循环中,没有赋值

  • 字符串标记大小

  • 我的假设:


    1. 由于赋值而可能消耗更多的内存
    2. 可能与#1或#3相同,不知道哪个

    3. 可能会更快,更小的内存占用



    方法



    $ p



    $ b $ ini_set('memory_limit ','1024M');

    $ listStr ='text';
    $ listStr。= str_repeat(',text',9999999);

    $ timeStart = microtime(true);

    / *****
    * {INSERT LOOP HERE}
    * /

    $ timeEnd = microtime(true);
    $ timeElapsed = $ timeEnd - $ timeStart;
    $ b printf(Memory used:%s kB\\\
    ,memory_get_peak_usage()/ 1024);
    printf(Total time:%s s \\\
    ,$ timeElapsed);

    以下是三个版本:

    1)

      //分别爆炸
    $ arr = explode(',',$ listStr);
    foreach($ arr as $ val){}



    <2>

      //展开内联
    foreach(explode(',',$ listStr)as $ val){}



    $ b $ > // tokenize
    $ tok = strtok($ listStr,',');
    while($ tok = strtok(',')){}



    h2>



    结论



    看起来有些假设是错误的。你不喜欢科学吗? : - )


    • 总的来说,任何这些方法对于合理大小如果你正在遍历巨大的,时间差异相对较小,但是内存使用可能会有一个数量级的差异!
    • >
    • 当您的 explode()没有预先赋值时,它会慢一些。

    • <令人惊讶的是,标记化比显式迭代声明的数组慢了一点。在这么小的范围内工作,我认为这是由于每次迭代调用函数 strtok()的调用堆栈开销。


    根据函数调用的数量, explode() O(1) vs O(n)



    )在循环中调用一个函数。我用 strlen($ val),认为这会是一个相对相似的执行时间。这是有争议的,但我只是想说明一个问题。 (我只运行了 strlen($ val)并忽略了输出,我没有把它分配给任何东西,因为赋值是一个额外的时间)

    $ $ p $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $
    foreach($ arr as $ val){strlen($ val);}

    你可以从结果表中看到,然后成为三者中最慢的方法。

    最后的想法



    这是很有趣的知道,但我的建议是做任何你觉得最可读/可维护。只有当你真的处理一个非常大的数据集时,你应该担心这些微观优化问题。


    foreach(explode(',' $foo) as $bar) { ... }
    

    vs

    $test = explode(',' $foo);
    foreach($test as $bar) { ... }
    

    In the first example, does it explode the $foo string for each iteration or does PHP keep it in memory exploded in its own temporary variable? From an efficiency point of view, does it make sense to create the extra variable $test or are both pretty much equal?

    解决方案

    I could make an educated guess, but let's try it out!

    I figured there were three main ways to approach this.

    1. explode and assign before entering the loop
    2. explode within the loop, no assignment
    3. string tokenize

    My hypotheses:

    1. probably consume more memory due to assignment
    2. probably identical to #1 or #3, not sure which
    3. probably both quicker and much smaller memory footprint

    Approach

    Here's my test script:

    <?php
    
    ini_set('memory_limit', '1024M');
    
    $listStr = 'text';
    $listStr .= str_repeat(',text', 9999999);
    
    $timeStart = microtime(true);
    
    /*****
     * {INSERT LOOP HERE}
     */
    
    $timeEnd = microtime(true);
    $timeElapsed = $timeEnd - $timeStart;
    
    printf("Memory used: %s kB\n", memory_get_peak_usage()/1024);
    printf("Total time: %s s\n", $timeElapsed);
    

    And here are the three versions:

    1)

    // explode separately 
    $arr = explode(',', $listStr);
    foreach ($arr as $val) {}
    

    2)

    // explode inline-ly 
    foreach (explode(',', $listStr) as $val) {}
    

    3)

    // tokenize
    $tok = strtok($listStr, ',');
    while ($tok = strtok(',')) {}
    

    Results

    Conclusions

    Looks like some assumptions were disproven. Don't you love science? :-)

    • In the big picture, any of these methods is sufficiently fast for a list of "reasonable size" (few hundred or few thousand).
    • If you're iterating over something huge, time difference is relatively minor but memory usage could be different by an order of magnitude!
    • When you explode() inline without pre-assignment, it's a fair bit slower for some reason.
    • Surprisingly, tokenizing is a bit slower than explicitly iterating a declared array. Working on such a small scale, I believe that's due to the call stack overhead of making a function call to strtok() every iteration. More on this below.

    In terms of number of function calls, explode()ing really tops tokenizing. O(1) vs O(n)

    I added a bonus to the chart where I run method 1) with a function call in the loop. I used strlen($val), thinking it would be a relatively similar execution time. That's subject to debate, but I was only trying to make a general point. (I only ran strlen($val) and ignored its output. I did not assign it to anything, for an assignment would be an additional time-cost.)

    // explode separately 
    $arr = explode(',', $listStr);
    foreach ($arr as $val) {strlen($val);}
    

    As you can see from the results table, it then becomes the slowest method of the three.

    Final thought

    This is interesting to know, but my suggestion is to do whatever you feel is most readable/maintainable. Only if you're really dealing with a significantly large dataset should you be worried about these micro-optimizations.

    这篇关于在foreach循环参数中展开一个数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆