测试 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
$msg="test text";
file_put_contents($log,$msg,FILE_APPEND|LOCK_EX);
}
不加锁:(n=3000 | n=1000)for($i=0;$i
$msg="test text";
file_put_contents($log,$msg,FILE_APPEND);
}
执行情况如下表:序号进程数每个进程写入行数是否加锁第一次执行平均耗时 (s)第二次执行平均耗时 (s)第三次执行平均耗时 (s)
1-1303000Y2.8312.8152.861
1-2303000N2.8262.8552.751
1-3901000Y2.4072.3962.278
1-4901000N1.7792.0522.01
方式二:
加锁:(n=3000 | n=1000)$handle=fopen($log,'a');
flock($handle,LOCK_EX);
for($i=0;$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
$msg="test text";
fwrite($handle,$msg);
}
fclose($handle);
执行情况如下表:序号进程数写入行数 / 每个进程是否加锁第一次执行平均耗时 (s)第二次执行平均耗时 (s)第三次执行平均耗时 (s)
2-1303000Y0.660.6590.658
2-2303000N1.2721.171.161
2-3901000Y0.830.8550.836
2-4901000N0.9521.0970.947
以方式一跟方式二的表格为参照, 同一种方式, 上不上锁, 性能相差不是很大, 从效率上讲, 方式二要比方式一高效.
最根本的原因是 file_put_contents() 函数每次执行相当于执行了 fopen(),fwrite(),fclose() 三个函数, 所以单次执行耗时会比较长.
如果把方式二做个调整, 比如把 fopen() 和 fclose 都放进 for 循环里, 那么方式二跟方式一基本没太大差别.for($i=0;$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;
来源: http://www.bubuko.com/infodetail-3724444.html