测试PHP几种方法写入文件的效率

前置条件:

所有测试生成的都写入一个新文件,如果时同一个文件名,那么每次执行脚本前,需要把该日志文件删掉,确保每次执行时日志文件都是重新创建的。

每次执行都是往日志文件中使用多进程写入90000行日志。每种方式分成四种对照组测试:

30*3000 加锁(即30个进程每个进程写入3000行,总共90000行,写入时需对日志文件上独占锁)。

30*3000 不加锁(即30个进程每个进程写入3000行,总共90000行,写入时日志文件不上锁)。

90*1000 加锁(即90个进程每个进程写入1000行,总共90000行,写入时需对日志文件上独占锁)。

90*1000 不加锁(即90个进程每个进程写入1000行,总共90000行,写入时日志文件不上锁)。

 

方式一:

使用file_put_contents() 函数写入文件。为了避免内容覆盖,须使用FILE_APPEND模式写入。

加锁:(n=3000 | n=1000)

for($i=0;$i<n,$i++){

  $msg = "test text";

  file_put_contents($log, $msg, FILE_APPEND|LOCK_EX);

}

 

不加锁:(n=3000 | n=1000)

for($i=0;$i<n,$i++){

  $msg = "test text";

  file_put_contents($log, $msg, FILE_APPEND);

}

执行情况如下表:

序号

进程数

每个进程写入行数

是否加锁

第一次执行平均耗时(s)

第二次执行平均耗时(s)

第三次执行平均耗时(s)

1-1

30

3000

Y

2.831

2.815

2.861

1-2

30

3000

N

2.826

2.855

2.751

1-3

90

1000

Y

2.407

2.396

2.278

1-4

90

1000

N

1.779

2.052

2.01

 

 

方式二:

加锁:(n=3000 | n=1000)

$handle = fopen($log,’a’);

flock($handle,LOCK_EX);

for($i=0;$i<n,$i++){

  $msg = "test text";

  fwrite($handle,$msg);

}

flock($handle,LOCK_UN);

fclose($handle);

 

不加锁:(n=3000 | n=1000)

$handle = fopen($log,’a’);

for($i=0;$i<n,$i++){

  $msg = "test text";

  fwrite($handle,$msg);

}

fclose($handle);

执行情况如下表:

序号

进程数

写入行数/每个进程

是否加锁

第一次执行平均耗时(s)

第二次执行平均耗时(s)

第三次执行平均耗时(s)

2-1

30

3000

Y

0.66

0.659

0.658

2-2

30

3000

N

1.272

1.17

1.161

2-3

90

1000

Y

0.83

0.855

0.836

2-4

90

1000

N

0.952

1.097

0.947

 

 

以方式一跟方式二的表格为参照,同一种方式,上不上锁,性能相差不是很大,从效率上讲,方式二要比方式一高效。

最根本的原因是file_put_contents()函数每次执行相当于执行了 fopen(),fwrite(),fclose()三个函数,所以单次执行耗时会比较长。

如果把方式二做个调整,比如把fopen()和fclose都放进for循环里,那么方式二跟方式一基本没太大差别。

for($i=0;$i<n,$i++){

  $handle = fopen($log,’a’);

  $msg = "test text";

  fwrite($handle,$msg);

  fclose($handle);

}

 

不上锁的情况,日志写进去时无序的,各个进程之间穿插着写入日志。

上锁的情况,日志相对有序,基本是一个进程写完才轮到另一个进程。但是进程之间也是无序的。所以,同一个进程写的日志才是有序的。

<?php
 
set_time_limit(30);
$log = ‘/data/tmp/a.log‘;

for($i = 0;$i<30;$i++){
    pcntl_signal(SIGCHLD, SIG_IGN);
    $fid = pcntl_fork();
    if($fid === 0){
        try {
        $start = microtime(true);       
        $handle = fopen($log,‘a‘);
        flock($handle,LOCK_EX);
        for($j=0;$j<3000;$j++){ 
            $start_time = microtime(true);
            //TODO 其他业务逻辑
            //打点记录并行任务执行状况
            $fid = posix_getpid();
            $ffid = posix_getppid();
            $date = date(‘YmdHis‘);
            $end_time = microtime(true);
            $usetime = round($end_time-$start_time,2);
            $msg =  PHP_EOL."序号:{$i}:{$j}; 时间:{$date}; 当前进程ID:{$fid}; 父进程ID:{$ffid}; 任务开始:{$start_time}; 任务结束:{$end_time}; 耗时:{$usetime}";
            //file_put_contents($log,$msg,FILE_APPEND|LOCK_EX);
            fwrite($handle,$msg);
        }
        flock($handle,LOCK_UN);
        fclose($handle);
        unset($handle);
        $end = microtime(true);
        $s = round($end-$start,3);
        echo PHP_EOL.$s.‘,‘;
        //echo "进程:{$i},开始:{$start},结束:{$end},耗时:{$s}".PHP_EOL;
        }finally{
            if(function_exists("posix_kill")){
                posix_kill(getmypid(),SIGTERM);
            }else{
                system(‘kill -9 ‘.getmypid());
            }
        }
    }
}

echo ‘over‘.PHP_EOL;

 

 

 

 

 

 

测试PHP几种方法写入文件的效率

上一篇:MongoDB(三):MongoDB概念解析


下一篇:隐藏你的Webshell