道者编程

php的迭代生成器

PHP5.5及以上版本加了个yield生成器,用于实现对象迭代。

PHP官方介绍:

生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。

生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。

以下是鸟哥举的例子:

<?php
function xrange($start, $end, $step = 1) {
    for ($i = $start; $i <= $end; $i += $step) {
        yield $i; //一次给一个数字
    }
}
 
foreach (xrange(1, 1000000) as $num) { //调用xrange方法
    echo $num, "\n";
}
输出1到100万的数字,这里用到了yield。

我们常规的做法是:

<?php
foreach (range(1, 1000000) as $num) {
    echo $num, "\n";
}

这是常规做法,一次输出1到100万的数字,但这种方法有个缺陷,这种是一次性把数据输出到内存中,如果这里不是数字,而是100万篇文章,那么内存很可能就要爆了。第一个例子因为用了yield,内存中每次只存在一条数据,这样就极大的缓解了内存压力,适合批量处理大数据。

关于原理,鸟哥已经说的很清楚了,具体查看鸟哥的这篇文章:http://www.laruence.com/2015/05/28/3038.html

实际干几个操作。

1:数据库插入100万条数据,如果一次性插入会超时,速度也慢,一次提取到内存插入,会占用很大的内存,可能还要改max_allowed_packet设置,这里就可以用yield;当然你如果直接在mysql里面导入也没问题,这里用程序实现一下:

<?php
header("Content-Type: text/html;charset=utf-8");
set_time_limit(0);
$t=time();
try{ 
    $pdo=new pdo("mysql:host=127.0.0.1;dbname=abc","root","123",array(PDO::ATTR_AUTOCOMMIT=>1)); 
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //开启异常处理
   $pdo->exec('set names utf8');  
}catch(PDOException $e){ 
     dir('数据库连接失败,错误信息:'. $e->getMessage());  
} 

function xrange($start, $end, $step = 1) {

    for ($i = $start; $i <= $end; $i += $step) {
    	 $time = time();
      	 $counts = '李连杰'.$i; 
         $sql .= "('李小龙','".$counts."',$time),"; 

         if($i % 5000 == 0){ // 内存一次写5000个sql
    		yield $sql;
    		$sql = ''; //因为上面用了.= 链接符,如果不清空会一直加
    	}
    	
    }
}

foreach (xrange(1, 1000000) as $numSql) { //调用xrange方法
	$numSql = substr($numSql,0,strlen($numSql)-1); //去掉最后一个逗号
	$pdo->exec("insert into new (title, counts,times) values".$numSql);
}

echo"写入成功,耗时:",time()-$t;

写入成功,耗时:10s

反过来试试,再把这100万数据导出Excel,同样的方法。yield的出现,实现了PHP操作大文件;


最新评论:
我要评论:

看不清楚