• php网站大数据高并发处理方法简单总结层层剥开来讲,有以下部位需要注意。1.资源。能静态实现的就静态实现,静态资源也要尽量使用分布式存储,例如云存储。2.效率。PHP代码里,尽量注意内存的使用,单个脚本的运行...

    php网站大数据高并发处理方法简单总结

    一层层剥开来讲,有以下部位需要注意。

    1.资源。能静态实现的就静态实现,静态资源也要尽量使用分布式存储,例如云存储。

    2.效率。PHP代码里,尽量注意内存的使用,单个脚本的运行效率要Ok.

    3.缓存。使用memcache来实现非持久存储,使用no-sql来实现持久存储。

    4.server。使用nginx+fpm或者nginx+apache,来实现动静态分离访问。

    5.mysql。作为最终的存储库以及一些不可避免的实时调用库,做主从处理,Master+多Slave,多个只读副本来实现实时的调用库。

    6.负载。建议架设一层负载均衡,来实现web server的轮询。例如云平台中的LBS。

    展开全文
  • 但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.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 />';
    }

    我们在浏览器里面看一下运行结果:

    图片描述

    这里非常完美,没有任何问题。(当然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 />';
    }

    图片描述

    我们奇迹般的发现了,输出的值和第一次没有使用生成器的不一样。这里的值(时间戳)中间间隔了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拿到第二个值,并且输出。由于foreachsleep(1),所以,for循环延迟了1秒生成当前时间

    所以,整个代码执行中,始终只有一个记录值参与循环,内存中也只有一条信息。

    无论开始传入的$number有多大,由于并不会立即生成所有结果集,所以内存始终是一条循环的值。

    概念理解

    到这里,你应该已经大概理解什么是生成器了。下面我们来说下生成器原理。

    首先明确一个概念:生成器yield关键字不是返回值,他的专业术语叫产出值,只是生成一个值

    那么代码中foreach循环的是什么?其实是PHP在使用生成器的时候,会返回一个Generator类的对象。foreach可以对该对象进行迭代,每一次迭代,PHP会通过Generator实例计算出下一次需要迭代的值。这样foreach就知道下一次需要迭代的值了。

    而且,在运行中for循环执行后,会立即停止。等待foreach下次循环时候再次和for索要下次的值的时候,for循环才会再执行一次,然后立即再次停止。直到不满足条件不执行结束。

    实际开发应用

    很多PHP开发者不了解生成器,其实主要是不了解应用领域。那么,生成器在实际开发中有哪些应用?

    读取超大文件

    PHP开发很多时候都要读取大文件,比如csv文件、text文件,或者一些日志文件。这些文件如果很大,比如5个G。这时,直接一次性把所有的内容读取到内存中计算不太现实。

    这里生成器就可以派上用场啦。简单看个例子:读取text文件

    图片描述

    我们创建一个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 />';
    }

    图片描述

    通过上图的输出结果我们可以看出代码完全正常。

    但是,背后的代码执行规则却一点儿也不一样。使用生成器读取文件,第一次读取了第一行,第二次读取了第二行,以此类推,每次被加载到内存中的文字只有一行,大大的减小了内存的使用。

    这样,即使读取上G的文本也不用担心,完全可以像读取很小文件一样编写代码。

    展开全文
  • PHP5.5引入了迭代生成器的概念,迭代的概念早就在PHP有了,但是迭代生成器是PHP个新特性,这跟python3中的迭代生成器类似,看看PHP5.5的迭代生成器如何定义。 ? 1 2 3 4 5 6 7 ...

    PHP5.5引入了迭代生成器的概念,迭代的概念早就在PHP有了,但是迭代生成器是PHP的一个新特性,这跟python3中的迭代生成器类似,看看PHP5.5的迭代生成器如何定义。

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    <?php

    function xrange($start, $end, $step = 1) {

        for ($i = $start; $i <= $end; $i += $step) {

          yield $i;

        }

    }

    foreach (xrange(1, 1000000) as $num) {

        echo $num, "\n";

    }

    注意关键字:yield,正是这个yeild关键字构建了一个迭代器,这个函数xrange跟以往的函数的不同之处就在这里。一般情况都是return一个值,而yield一个值就表示这是个迭代器,每循环一次这个迭代器就生成这个值,故名为迭代生成器,迭代生成器这个函数可以进行foreach循环,每次都产生一个值。

    PHP5.5之前是通过定义类实现Iterator接口的方式来构造迭代器,通过yield构造迭代器将更加提升性能节省系统开销。

    这种方法的优点是显而易见的.它可以让你在处理大数据集合的时候不用一次性的加载到内存中,甚至你可以处理无限大的数据流。

    如上面例子所示,这个迭代器的功能是生成从1到1000000的数字,循环输出,那么使用以往的方式是生成好这1到1000000的数字到数组中,将会十分占用内存,因为是事先就要生成好所有结果,而不是用的时候按需生成,也就是说调用xrange这个迭代器的时候,里面的函数还没有真正的运行,直到你每一次的迭代。

    再看看PHP官网的例子:

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    <?php

    function xrange($start, $limit, $step = 1) {

      for ($i = $start; $i <= $limit; $i += $step) {

        yield $i;

      }

    }

    echo 'Single digit odd numbers: ';

    /*

     * Note that an array is never created or returned,

     * which saves memory.

     */

    foreach (xrange(1, 9, 2) as $number) {

      echo "$number ";

    }

    echo "\n";

    ?>

    这里的xrange是一个迭代,功能和range是一样的,如果使用range函数的话,那么函数内部实现会储存每个迭代的中间过程,即每个中间变量都有 个内存空间,那么首先程序使用的内存空间就大了,而且分配内存,回收内存都会导致程序的运行时间加长。但是如果使用上yield实现的xrange函数的 话,里面所有的中间变量都只使用一个内存$i,这样节省的时间和空间都会变小。

    那么为什么yield会有这样的效果呢?联想到lua中的yield,这里就算是协程的概念了。在lua语言中,当程序运行到yield的时候,使用协程 将上下文环境记录住,然后将程序操作权归还到主函数,当主函数调用resume的时候,会重新唤起协程,读取yield记录的上下文。这样形成了程序语言 级别的多协程操作。php 5.5这里的yield也是同样的道理,当程序运行到yield的时候,当前程序就唤起协程记录上下文,然后主函数继续操作,只是php中没有使用如 resume一样的关键字,而是“在使用的时候唤起”协程。比如上例中的foreach迭代器就能唤起yield。所以上面的这个例子就能理解了。

    展开全文
  • 几个重点, 1,文本记录数据落地点,2...5,日志跟踪 6,递归处理数据(业务需求),7,正则匹配数据(业务需求)增强程序的可执行 &lt;?php /** * Created by PhpStorm. * User: Administrator * Date: 2...

    几个重点,

    1,文本记录数据落地点,2,死循环断开点  3,防止sql断开连接(MySQL server has gone away)4,防止php超时 

    5,日志跟踪   6,递归处理数据(业务需求),7,正则匹配数据(业务需求)增强程序的可执行性

    <?php
    /**
     * Created by PhpStorm.
     * User: Administrator
     * Date: 2017/9/8 0008
     * Time: 上午 10:52
     */
    
    global $_G;
    echo $_GET['exec'] !== 1;
    
    
    if ($_GET['exec'] !== '1') {
        exit('Pemission denied');
    }
    
    if ($_GET['val'] !== null) {
        $fidArr['val'] = $_GET['val'];
    }
    
    $pid =isset($_GET['pid']) ? $_GET['pid'] : 0;
    
    //获取所有数据表
    $sql = 'SELECT fid FROM ' . DB::table('forum_forum');
    $resource = DB::query($sql);
    $re = DB::fetch_all($resource);
    $fidArr = array_unique(array_column($re, 'fid'));
    
    //切换数据库连接
    $object = DB::object();
    $object->set_config($_G['config']['db']);
    $object->connect(2);
    
    $fun = function ($val,$pid) {
    
        set_time_limit(0);// 防止时间超时
        DB::query('SET SESSION wait_timeout=7200'); // 防止出现 MySQL server has gone away
        $csql = "SELECT count(*) FROM  `pre_forum_post_" . $val . "`;";
        $ct = DB::result_first($csql);//获取表里面所有的message数据
    //死循环开始
        while (1) {
            $result = DB::fetch_all(DB::query('SELECT pid,authorid,parentpid,message FROM ' . DB::table('forum_post_' . $val) . " WHERE pid > {$pid} ORDER BY pid LIMIT 100"));
            if (!$result) {
                runlog('pre_forum_post___finish__', $val);
                echo 'pre_forum_post_' . $val . ' __finish__' . $result;
                echo '<br />';
                break;
            } else {
                runlog('get-message-fail', $result);
                echo 'pre_forum_post_success_' . $val . ' __get-message-fail__' . $result;
                echo '<br />';
                $start=array_shift($result);$end=end($result);
                foreach ($result as $r) {
                    $presult = pidUpdate($val,$r);
                    if (!$presult) {
                        $presult['authorid'] = 0;
                        $presult['pid'] = 0;
                    }
                    $res = DB::update('forum_post_' . $val,
                        array('parentpid' => $presult['pid']), 'pid =' . $r['pid']);
                    if ($res) {
                        runlog('UPDATE-parentpid-success_', $r['pid']);
                        echo 'UPDATE-parentpid-success_pre_forum_post_' . $val . ' __pid__' . $r['pid'];
    
                    } else {
                        runlog('UPDATE-parentpid-fail', $r['pid']);
                        echo 'UPDATE-parentpid-fail_pre_forum_post_' . $val . ' __pid__' . $r['pid'];
                    }
                }
                setLastStatus($end['pid'],$start['pid'],$end['pid'],$val,$end['pid']);
                sleep(2);// 执行1000后休息两秒
            }
        }
    };
    
    function pidUpdate($val, $result)
    {
        static $result2;
        //正则匹配对应数据dpost&pid=61414914&ptid= 中间pid=里面的数字
        preg_match("/&pid=(\d+)/", $result['message'], $out);
        if ($out) {
            $sql2 = "SELECT pid,authorid,parentpid,message FROM  `pre_forum_post_" . $val . "` WHERE pid = '{$out[1]}';";
            $result2 = DB::fetch(DB::query($sql2, 'SILENT'));//执行创建语句,遇到错误依然执行
            if ($result2 && $result2['parentpid'] != 0) {
                $res = DB::update('forum_post_' . $val,
                    array('parentuid' => $result2['authorid']), 'pid =' . $result['pid']);
                if($res){
                    pidUpdate($val, $result2);
                    runlog('UPDATE-parentpid-success', $val.'---'.$result['pid']);
                    echo 'UPDATE-parentpid-success' . $val.'---'.$result['pid'];
                }else{
                    runlog('UPDATE-parentpid-fail', $val.'---'.$result['pid']);
                    echo 'UPDATE-parentpid-success' . $val.'---'.$result['pid'];
                }
            }else{
                DB::query("UPDATE ".DB::table('forum_post_' . $val)." SET count=count+1 WHERE pid='$out[1]'",'SILENT');
            }
            return $result2;
        }
    }
    
    //循环执行,所有得表
    foreach ($fidArr as $item) {
        $fun($item);
    }
    
    function setLastStatus($maxPid, $start, $end,$_val,$_pid)
    {
        if (!is_dir(THINKPHP_ROOT . 'data/tmp/')) {
            @mkdir(THINKPHP_ROOT. 'data/tmp/');
        }
        $data = json_encode(['max_id' => $maxPid, 'start' => $start, 'end' => $end]);
        return file_put_contents(getLastStatusFile($_val,$_pid), $data);
    }
    
    function getLastStatusFile($_val,$_pid)
    {
        return sprintf(THINKPHP_ROOT. 'data/tmp/_last_pre_forum_post__%d_pid_%d', $_val, $_pid);
    }
    
    
    $object->close(); //关闭当前链接
    
    echo 'success!';
    
    

     

    展开全文
  • php大数据导出csv

    2019-01-08 11:58:31
    博主昨天在实现一个需求,因为需要用到大数据导出,所以自己动手写了一个导出方法,因为要考虑到大数据的导出,所以不能一次性读取数据库,想到了分页获取数据,写进导出缓存中,这样避免了一次性从数据库中读取大量...

           博主昨天在实现一个需求,因为需要用到大数据导出,所以自己动手写了一个导出方法,因为要考虑到大数据的导出,所以不能一次性读取数据库,想到了分页获取数据,写进导出缓存中,这样避免了一次性从数据库中读取大量数据而造成奔溃,思路就是分页获取数据,写进导出数组中,同时清除查询数据的缓存,这样就可以避免奔溃,下面向大家分享有关教程

           博主用的是原生方法写,跟之前另一篇博客也是很相似的,大家有兴趣也可以看看(传送门)  ,我们先来封装我们的数据库查询方法,等下会用,代码如下:

    /**
     * 获取导出数据  
     * @param $getLinkClearSQl  数据库语句
     */
    function getReturnData($getLinkClearSQl)
    {
        $con = mysqli_connect("链接地址", "账号名", "密码", "数据库名");
        $getLinkClearingData = mysqli_query($con, $getLinkClearSQl);
        $returnData = array();
        //循环组合即将导出数据
        while ($rowData = mysqli_fetch_array($getLinkClearingData)) {
            $returnData[] = array(
                'day' => date('Y-m-d', strtotime($rowData["day"])) . ' ', 
                'num1' => $rowData["num1"],
                'num2' => $rowData["num2"],
                'num3' => $rowData["num3"],
                'num4' => $rowData["num4"],
            );
        }
        //返回已封装好的数据
        return $returnData;
    }
          封装好导出数据,然后再来封装我们的私有方法,该方法能够使得导出的中文不乱码,代码如下:
    
    function fputcsv2($handle, array $fields, $delimiter = ",", $enclosure = '"', 
        $escape_char = "\\")
    {
        foreach ($fields as $k => $v) {
            $fields[$k] = iconv("UTF-8", "GB2312//IGNORE", $v);  // 这里将UTF-8转为GB2312编码
        }
        fputcsv($handle, $fields, $delimiter, $enclosure, $escape_char);
    }

           接下来是我们的主体了,上面我们已经封装了两个方法,跟主体区分开,看起来会比较舒服,代码如下:

    //设置时间跟最大限制
    set_time_limit(0);
    ini_set("memory_limit", "512M");
    #设置文件名以及列名
    $fileName = "导出数据";
    $columnName = array('日期','字段1','字段2','字段3','字段4',); 
    //设置头部
    header('Content-Type: application/vnd.ms-excel;charset=utf-8');
    header("Content-Disposition:filename=" . $fileName . ".csv");
    // 打开PHP文件句柄,php://output 表示直接输出到浏览器
    $fp = fopen('php://output', 'a');
    // 将中文标题转换编码,否则乱码
    foreach ($columnName as $i => $v) {
        $columnName[$i] = $v;
    }
    //每次获取数量
    $pre_count = 100;
    // 将标题名称通过fputcsv写到文件句柄
    fputcsv2($fp, $columnName);
    $rows = array();
    //循环读取数据并导出数据
    for ($t = 0; $t < intval($linkClearingNumber / $pre_count) + 1; $t++) {
        #获取页码
        $pageNumber = $t * $pre_count;
        #重构SQL
        $getLinkClearSQl = "SELECT * FROM 表名"." limit $pageNumber,$pre_count";
        #获取数据
        $export_data = getReturnData($linkData, $getLinkClearSQl);
        #循环获取存放数据
        foreach ($export_data as $item) {
            $rows = array();
            foreach ($item as $export_obj) {
                $rows[] = iconv('utf-8', 'GB18030', $export_obj);
            }
            fputcsv($fp, $rows);
        }
        // 将已经写到csv中的数据存储变量销毁,释放内存占用
        unset($export_data);
        ob_flush();
        flush();
    }
    exit ();

            这样我们便完成了导出上万数据而不会造成网络奔溃的方法,各位小伙伴可以尝试尝试。

            更多文章请关注微信公众号

     

    展开全文
  • 虽然处理数据所需的计算能力或存储容量早已超过台计算机的上限,但这种计算类型的普遍、规模,以及价值在最近几年才经历了大规模扩展。本文将介绍大数据系统个最基本的组件:处理框架。处理框架负责对系统中的...
  • 我们的socket客户端在接收大数据(大约大于5000个byte)的时候总是不能一次性的接收所有的数据,一般是分2次。可能是1000,4000;2000,3000;4000,1000这样不固定的。但有个奇怪的现象,在debug的时候,数据是能一...
  • 当有业务需求需要一次性循环n条数据,插入或更新数据库时,如果单纯的循环,插入/更新,会消耗太多的数据库资源 一下是一种简单的解决方案 数据库的insert 是可以批量更新的,当有大量数据循环insert时,可以将数据...
  • 大数据量的业务场景:excel 导出百万数据,操作百万数据的数组,从数据库表中取出百万数据。两个解决思路:1.... 解决思路就是分批次处理。excel导出解决方案可以看我之前博文,有相应的代码示例。 操作...
  • 家阿尔文,托夫勒便在《第三浪潮》书中, 将大数据比作 第三浪潮的华彩乐章”。 在传统数据处理过程中,单个计算机的性能往往很强,可靠高(但是造价也很高),用 台计算机即可处理完所需数据。 当今世界...
  • 文章来源:http://www.dataguru.cn/forum.php?mod=viewthread&amp;tid=316241 为了广大学员更好的学习spark,对《Spark大数据快速计算平台》最初...二周内容的课程会一次性发放,但间隔时间会多一周,总的课程...
  • set_time_limit(0); ini_set ('memory_limit', '256M'); $db = $this->load->database('default',true); $sql = "SELECT * FROM `t_mobile_number_section` $condition"; ...
  • 电商网站是怎么处理大数据和并发架构网站 第点服务器负责均衡: web 负载均衡的作用就是把请求均匀的分配给各个节点,它是种动态均衡,通过一些工具实时地分析数据包,掌握网络中的数据流量状况,把请求理分配...
  • 学习大数据不做科研研究就得选择工作,商业环境下大数据求职就业有哪些?大数据架构师、资深研发工程师、工程师、管理员、运维、风控等具体岗位职责与任职要求又是怎样的呢?起来了解下。 大数据架构师 岗位...
  • 下面的方法是我对海量数据的处理方法进行了个一般的总结,当然这些方法可能并不能完全覆盖所有的问题,但是这样的一些方法也基本可以处理绝大多数遇到的问题。下面的一些问题基本直接来源于公司的面试笔试题目,...
  • 而通过ajax方法可以实现JS一次性读取php的所传送过来的大量数据。通过提交表单的方式,让php可以一次性读取JS的大量数据。 1、借用AJAX方法,通过php读取数据库将大量数据显示在网页客户端上。  a、页面一加载完,...
  • 大数据迁移总结

    2018-11-18 20:45:21
    情况是这样的,有几张表存储爬虫爬过来的数据,用text的数据类型的个字段存储,这种表每张有2万多条数据,这样的数据库有20-30个,其中的数据还有很多是重复的,现在需要把这些数据迁移到个库中,简单来说就是...
  • 大数据技术与实践总结大数据概述大数据的定义大数据的4V特征HDFS 大数据概述 大数据的定义 大数据一词由英文“big data”翻译而来,是最近几年兴起的概念,目前还没有个统一的定义。相比于过去的“信息爆炸”概念...
  • Hadoop大数据平台安装

    2019-05-09 23:22:44
    实验:Hadoop大数据平台安装 16281002 杜永坤 1、实验目的 在大数据时代,存在很多开源的分布式数据采集、计算、存储技术,本实验将熟悉并搭建几种常用的大数据采集、处理分析技术环境。 《大数据技术》实验...
  • 简单的说可以理解为 php版本的非缓冲查询,意思即是 把数据一行行 读取到php运行内存,并非一次性读取到php运行内存,众所周知,php有很多内置函数,可以帮助我们对数据进行加工操作,因为数据都在内存里面,所以能...
1 2 3 4 5 ... 20
收藏数 12,567
精华内容 5,026