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操作大文件;