生成器相关测试
前些日子爬个小说站,满足自己尝试Python的心,当时使用
scrapy
框架,里面使用到了关键字yield
后来想到
PHP
中也有这个关键字,一直没有使用过,现在记录下我的一些测试对比。生成器实现了迭代器的接口,和以前关于理解迭代器接口的方法差不多。
创建一个PHP脚本,用于测试相关数据。
/**
* 测试生成器
*
* @date 2019年11月2日 09:53:08
*/
// 记录初始使用的内存量
$_mem[] = memory_get_usage();
/**
* 创建一个指定长度的数组
*
* @param int $num 数组的长度
* @param string $val 填充的值
*
* @return array
*/
function createArray(int $num = 10000, string $val = '0')
{
$a = [];
for ($i = 0; $i < $num; ++$i) {
$a[] = is_string($val) ? $val : '' . $i;
}
return $a;
}
/**
* 创建一个生成器
*
* @param int $num
* @param string $val
*
* @return Generator
*/
function createArrayByGenerator(int $num = 10000, string $val = '0')
{
for ($i = 0; $i < $num; ++$i) {
yield $val;
}
}
$arr = createArray(100000);
//$arr = createArrayByGenerator(100000);
// 记录创建 数组或者生成器后使用的内存
$_mem[] = memory_get_usage();
$n = 0;
foreach ($arr as $k) {
++$n;
}
// 记录遍历后的内存使用量
$_mem[] = memory_get_usage();
// 输出相关数据
echo $n, "\n";
print_r($_mem);
我测试使用两个函数使用的脚本输出的结果如下:
// 生成器函数
10000
Array
(
[0] => 397296
[1] => 398184
[2] => 397992
)
// 数组函数
10000
Array
(
[0] => 397296
[1] => 926112
[2] => 926112
)
// 增加一个数量级
// 生成器函数
100000
Array
(
[0] => 397552
[1] => 398440
[2] => 398248
)
// 数组函数
100000
Array
(
[0] => 397552
[1] => 6689464
[2] => 6689464
)
第一眼就看出使用的内存明显差距,使用数组是生成器的两倍多,而这数据量仅仅是10000。增加一个数量级后内存占用急剧增加。
从另一个角度分析,就是对比初始内存占用生成器不管什么数量级,内存占用仅仅比初始使用量多 888b 不到1k 对比之下,高下立判。
官网的简介如下:
一个简单的例子就是使用生成器来重新实现 range() 函数。
标准的 range() 函数需要在内存中生成一个数组包含每一个在它范围内的值,然后返回该数组, 结果就是会产生多个很大的数组。
比如,调用 range(0, 1000000) 将导致内存占用超过 100 MB。
做为一种替代方法, 我们可以实现一个 xrange() 生成器,
只需要足够的内存来创建 Iterator 对象并在内部跟踪生成器的当前状态,
这样只需要不到1K字节的内存。
function xrange($start, $limit, $step = 1){
for ($i=$start; $i <= $limit; $i+= $step) {
yield $i;
}
}
// Generator 对象是从 generators返回的.
// Caution Generator 对象不能通过 new 实例化.
/**
* 生成器类
*/
Generator implements Iterator {
/* Methods */
public current ( void ) : mixed
public getReturn ( void ) : mixed
public key ( void ) : mixed
public next ( void ) : void
public rewind ( void ) : void
public send ( mixed $value ) : mixed
public throw ( Throwable $exception ) : mixed
public valid ( void ) : bool
public __wakeup ( void ) : void
}
Generator::current — 返回当前产生的值
Generator::key — 返回当前产生的键
Generator::next — 生成器继续执行
Generator::rewind — 重置迭代器
Generator::send — 向生成器中传入一个值
Generator::throw — 向生成器中抛入一个异常
Generator::valid — 检查迭代器是否被关闭
Generator::__wakeup — 序列化回调
评论已关闭