生成器Generator测试

生成器相关测试

前些日子爬个小说站,满足自己尝试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 — 序列化回调

阿杰博客
请先登录后发表评论
  • latest comments
  • 总共0条评论