PHP Iterator,yield,range创建大数字迭代器对比.
PHP Iterator,yield,range创建大数字迭代器对比.
range是一个生成数组函数,可以生成一个可遍历的数字数组.如range(1,5)返回[1,2,3,4,5]
对比结果
生成100万数据,耗时和内存消耗对比,使用php8.1.23版本
创建:
只创建.$arr=range(1,1000000);
,$arr=new IRange(1,1000000)
,xrange(1,1000000)
方法 | 内存 | 耗时 |
---|---|---|
内置range函数 | 32.3964MB | 0.01714s |
Iterator类 | 401.9609kB | 0.00005s |
Yield 生成器 | 402.5078kB | 0.00006s |
结论: 看出来Iterator和Yield 内存和效率都差不多.range函数会占大量内存.
遍历:
使用foreach 来遍历
方法 | 内存 | 耗时 |
---|---|---|
内置range函数 | 32.3972MB | 0.01968s |
Iterator类 | 402.7734kB | 0.24452s |
Yield 生成器 | 403.0156kB | 0.05788s |
结论:Iterator遍历最慢,Yield和range速度差不多.
综合,当有大量数据需要遍历时,使用生器创建.
Range函数
$arr= range(1,1000000,1);
foreach ($arr as $key=>$value){}
Iterator类
class IRange implements Iterator {
private int $point=0;
private int $value=0;
private int $start=0;
private int $end=0;
private int $step=1;
public function __construct(int $start,int $end,int $step=1)
{
$this->start=$start;
$this->value=$start;
$this->end=$end;
$this->step=$step;
}
public function current(): int
{
return $this->value;
}
public function next():void{
$this->point++;
$this->value += $this->step;
}
public function key():int{
return $this->point;
}
public function valid():bool{
return ($this->value >= $this->start && $this->value <= $this->end);
}
public function rewind():void{
$this->point=0;
$this->value=$this->start;
}
}
// 创建
$arr=new IRange(1,1000000);
foreach ($arr as $key=>$value){}
Yield 生成器
function xRange($start,$end,$step=1): Generator
{
for($key=0,$value=$start;$value<=$end;$key++,$value=$value+$step){
yield $key=>$value;
}
}
$arr= xrange(1,1000000);
内存和耗时函数
php查看运行内存和耗时代码.
内存函数:
// 代码
memory_get_usage();// 当前使用内存
memory_get_peak_usage(true);// 最大真实内存
耗时:
当前时间-开时时间
$startTime=microtime(true);
// 代码
$endTime=microtime(true);
echo number_format($endTime-$startTime,5,'.','');
Trace类代码参考:
<?php declare(strict_types=1);
class Trace{
private static float $startTime=0;
private static float $endTime=0;
private static int $tag=0;
public static function Start(){
self::$startTime=microtime(true);
self::$endTime=microtime(true);
echo "\033[2;37m";
printf("php_ver:%s,max_mem:%s",PHP_VERSION,ini_get("memory_limit"));
echo "\e[0m ".PHP_EOL;
}
private static function out(float $size,float $time,string $msg=''){
self::$tag++;
$unit=array('b','kB','MB','GB','TB','PB');
$mem=@number_format($size/pow(1024,($i=floor(log($size,1024)))),4,'.','').''.$unit[$i];
$time=@number_format($time,5,'.','');
echo "\033[2;37m";
printf("[%s] mem:%s,time:%ss", self::$tag,$mem,$time);
echo "\e[0m ".$msg.PHP_EOL;
}
public static function Log(string $msg=''){
$endTime=microtime(true);
$time=$endTime-self::$endTime;
self::$endTime=$endTime;
self::out(memory_get_usage(),$time,"[$msg]");
}
public static function End(){
$endTime=microtime(true);
$time=$endTime-self::$startTime;
self::$endTime=$endTime;
self::out(memory_get_peak_usage(true),$time,'[end]');
}
public static function run(callable $callback,int $num=1,$out=false){
self::Start();
if(!$out) {
ob_start(function(){return null;},2);
}
while($num-->0) {
$callback();
}
if(ob_get_status()) {
ob_end_clean();
}
self::End();
}
}
使用:
Trace::Start();
// 代码1
Trace::Log("测试1");
// 代码2
Treace::Log("测试2");
Trace::End();
// 循环测试print_r函数100次,不输出内容.
Trace::run(function(){
print_r("hello");
},100,false);
测试
<?php declare(strict_types=1);
require "./trace.php";
// 自定义迭代器
class IRange implements Iterator {
private int $point=0;
private int $value=0;
private int $start=0;
private int $end=0;
private int $step=1;
public function __construct(int $start,int $end,int $step=1)
{
$this->start=$start;
$this->value=$start;
$this->end=$end;
$this->step=$step;
}
public function current(): int
{
return $this->value;
}
public function next():void{
$this->point++;
$this->value += $this->step;
}
public function key():int{
return $this->point;
}
public function valid():bool{
return ($this->value >= $this->start && $this->value <= $this->end);
}
public function rewind():void{
$this->point=0;
$this->value=$this->start;
}
}
function xRange($start,$end,$step=1): Generator
{
for($key=0,$value=$start;$value<=$end;$key++,$value=$value+$step){
yield $key=>$value;
}
}
Trace::Start();
// 通过迭代器
//$arr=new IRange(1,1000000,1);
//Trace::Log("iterator");
// 通过数组
//$arr= range(1,1000000,1);
//Trace::Log("range");
// 通过yield
$arr= xrange(1,1000000,1);
Trace::Log("yield");
foreach ($arr as $key=>$value){}
Trace::Log("foreach");
Trace::End();
结果:
➜ php iterator.php
php_ver:8.1.23,max_mem:128M
[1] mem:402.4063kB,time:0.00005s [iterator]
[2] mem:402.7734kB,time:0.24452s [foreach]
[3] mem:2.0000MB,time:0.24463s [end]
➜ php iterator.php
php_ver:8.1.23,max_mem:128M
[1] mem:32.3968MB,time:0.01456s [range]
[2] mem:32.3972MB,time:0.01968s [foreach]
[3] mem:34.0039MB,time:0.03428s [end]
➜ php iterator.php
php_ver:8.1.23,max_mem:128M
[1] mem:402.9609kB,time:0.00010s [yield]
[2] mem:403.0156kB,time:0.05788s [foreach]
[3] mem:2.0000MB,time:0.05802s [end]
cpu用时也可以用linux的time命令查看.
\time php iterator.php
后续 : Yield 和 Fiber 的使用
原作者:阿金
本文地址:https://hi-arkin.com/archives/iterator-yield-range.html