PHP性能优化利器:生成器-php教程

资源魔 32 0

假如您是做Python或其余言语的小同伴,您应该相熟天生器。但是,许多PHP开发职员可能没有晓得天生器的性能,要末是由于天生器是正在PHP 5.5.0中引入的,要末是由于天生器的性能没有显著。然而天生器性能的确十分有用。

优点

间接讲概念预计你听完仍是一头雾水,以是咱们先来讲说优点,兴许能勾起你的兴味。那末天生器有哪些优点,以下:

● 天生器会对PHP使用的功能有十分年夜的影响

● PHP代码运转时节流年夜量的内存

● 比拟适宜较量争论年夜量的数据

那末,这些神秘的性能终究是若何做到的?咱们先来举个例子。

概念引入

起首,放下天生器概念的包袱,来看一个简略的PHP函数:

function createRange($number){
    $data = [];
    for($i=0;$i<$number;$i++){
        $data[] = time();
    }
    return $data;
}

这是一个十分常见的PHP函数,咱们正在解决一些数组的时分常常会应用。这里的代码也十分简略:

1.咱们创立一个函数。

2.函数内蕴含一个for轮回,咱们轮回的把以后工夫放到$data外面

3.for轮回执行终了,把$data前往进来。

上面没完,咱们持续。咱们再写一个函数,把这个函数的前往值轮回打印进去:

$result = createRange(10); // 这里挪用下面咱们创立的函数
foreach($result as $value){
    sleep(1);//这里进展1秒,咱们后续有用
    echo $value.'<br />';
}

咱们正在阅读器外面看一下运转后果:

8eef744d896d89cc9d0609ad3cf3cb3.png

这里十分完满,不任何成绩。(当然sleep(1)成果你们看没有进去)

考虑一个成绩

咱们留意到,正在挪用函数createRange的时分给$number的传值是10,一个很小的数字。假定,如今通报一个值10000000(1000万)。

那末,正在函数createRange外面,for轮回就需求执行1000万次。且有1000万个值被放到$data外面,而$data数组正在是被放正在内存内。以是,正在挪用函数时分会占用年夜量内存。

这里,天生器就能够大显神通了。

创立天生器

咱们间接修正代码,你们留意察看:

function createRange($number){
    for($i=0;$i<$number;$i++){
        yield time();
    }
}

看下这段以及刚刚很像的代码,咱们删除了了数组$data,并且也不前往任何内容,而是正在time()以前应用了一个要害字yield

应用天生器

咱们再运转一下第二段代码:

$result = createRange(10); // 这里挪用下面咱们创立的函数
foreach($result as $value){
    sleep(1);
    echo $value.'<br />';
}

b0c76dc7235fef35133dbca4cd7909b.png

咱们奇观般的发现了,输入的值以及第一次不应用天生器的纷歧样。这里的值(工夫戳)两头距离了1秒。

这里的距离一秒其实就是sleep(1)酿成的结果。然而为何第一次不距离?那是由于:

● 未应用天生器时:createRange函数内的for轮回后果被很快放到$data中,而且立刻前往。以是,foreach轮回的是一个固定的数组。

● 应用天生器时:createRange的值没有是一次性疾速天生,而是依赖于foreach轮回。foreach轮回一次,for执行一次。

到这里,你应该对天生器有点儿眉目。

深化了解天生器

代码分析

上面咱们来关于刚刚的代码进行分析。

function createRange($number){
    for($i=0;$i<$number;$i++){
        yield time();
    }
}
 
$result = createRange(10); // 这里挪用下面咱们创立的函数
foreach($result as $value){
    sleep(1);
    echo $value.'<br />';
}

咱们来复原一下代码执行进程。

1.起首挪用createRange函数,传入参数10,然而for值执行了一次而后中止了,而且通知foreach第一次轮回能够用的值。

2.foreach开端对$result轮回,出去起首sleep(1),而后开端应用for给的一个值执行输入。

3.foreach预备第二次轮回,开端第二次轮回以前,它向for轮回又申请了一次。

4.for轮回于是又执行了一次,将天生的工夫戳通知foreach.

5.foreach拿到第二个值,而且输入。因为foreach中sleep(1),以是,for轮回提早了1秒天生以后工夫

以是,整个代码执行中,始终只有一个记载值参加轮回,内存中也只有一条信息。

无论开端传入的$number有多年夜,因为其实不会立刻天生一切后果集,以是内存始终是一条轮回的值。

概念了解

到这里,你应该曾经大略了解甚么是天生器了。上面咱们来讲下天生器原理。

起首明白一个概念:天生器yield要害字没有是前往值,他的业余术语叫产出值,只是天生一个值

那末代码中foreach轮回的是甚么?实际上是PHP正在应用天生器的时分,会前往一个Generator类的工具。foreach能够对该工具进行迭代,每一一次迭代,PHP会经过Generator实例较量争论出下一次需求迭代的值。这样foreach就晓得下一次需求迭代的值了。

并且,正在运转中for轮回执行后,会立刻中止。期待foreach下次轮回时分再次以及for索要下次的值的时分,for轮回才会再执行一次,而后立刻再次中止。直到没有餍足前提没有执行完结。

实际开发使用

不少PHP开发者没有理解天生器,其实次要是没有理解使用畛域。那末,天生器正在实际开发中有哪些使用?

读取超年夜文件

PHP开发不少时分都要读取年夜文件,比方csv文件、text文件,或许一些日记文件。这些文件假如很年夜,比方5个G。这时候,间接一次性把一切的内容读取到内存入彀算没有太事实。

这里天生器就能够派上用场啦。简略看个例子:读取text文件

d297d22030b090d9de1af9800bb1463.png

咱们创立一个text文本文档,并正在此中输出几行文字,树模读取。

<?php
header("content-type:text/html;charset=utf-8");
function readTxt()
{
    # code...
    $handle = fopen("./test.txt", 'rb');
    while (feof($handle)===false) {
        # code...
        yield fgets($handle);
    }
    fclose($handle);
}
 
foreach (readTxt() as $key => $value) {
    # code...
    echo $value.'<br />';
}

cc85c34bd95961a2e6aa4bad04421b5.png

经过上图的输入后果咱们能够看出代码齐全失常。

然而,面前的代码执行规定却一点儿也纷歧样。应用天生器读取文件,第一次读取了第一行,第二次读取了第二行,以此类推,每一次被加载到内存中的文字只有一行,年夜年夜的减小了内存的应用。

这样,即便读取上G的文本也不必担忧,齐全能够像读取很小文件同样编写代码。

批量更新数据库表字段

/**
 * @desc: 办法形容
 * @param int $count 数组个数(需求轮回几何次)
 * @param int $limit 数组巨细
 * @return \Generator
 */
public function getAddressContent($count = 1, $limit = 20000)
{
    for ($i = 0; $i < ceil($count / $limit); $i++) {
        $result = StudentModel::where('id','<','67265')
            ->limit($i * $limit, $limit)
            ->order('id desc')
            ->select()->toArray();
        yield $result;
    }
}
 
/**
 * @desc: 修正数据库 省分、都会
 * @throws Exception
 */
public function idCard()
{
    $count = 200000000; // 需求更新的数据
    foreach ($this->getAddressContent($count) as $key=>$lists) {
        foreach ($lists as $k => $v) {
            $peopleIdentity = new Identity($v['idcard']);
            $peopleRegion = $peopleIdentity->region();
            if($peopleRegion->code() != 0 ){
                $res = StudentModel::where('id', $v['id'])->update([
                    'birthday' => $peopleIdentity->birthday()??'',
                    'province' => $peopleRegion->province()??'',
                    'city' => $peopleRegion->city()??'',
                    'county' => $peopleRegion->county()??'',
                ]);
                Log::debug('更新后果 [' . $v['id'] . ']: ' . json_encode($res));
            }
        }
    }
    echo "success";
}

应用饬令行执行

php id_card.php

打印日记

96a4e359b4555187723e1cbad2df140.png

CPU以及内存耗费

ae6da1d1b8e3937c00521ce3f7e6610.png

更多php常识,请拜访php教程!

以上就是PHP功能优化利器:天生器的具体内容,更多请存眷资源魔其它相干文章!

标签: php php开发教程 php开发资料 php开发自学

抱歉,评论功能暂时关闭!