zoukankan      html  css  js  c++  java
  • PHP写日志什么时候需要加锁?

    先分析fwrite,直接找到PHP源代码:

    static size_t _php_stream_write_buffer(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
    {vv
        size_t didwrite = 0, towrite, justwrote;
    
        /* if we have a seekable stream we need to ensure that data is written at the
         * current stream->position. This means invalidating the read buffer and then
         * performing a low-level seek */
        if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && stream->readpos != stream->writepos) {
            stream->readpos = stream->writepos = 0;
    
            stream->ops->seek(stream, stream->position, SEEK_SET, &stream->position TSRMLS_CC);
        }
    
    
        while (count > 0) {
            towrite = count;
        //chunk_size是8K
    if (towrite > stream->chunk_size) towrite = stream->chunk_size;     //分多次调用 justwrote = stream->ops->write(stream, buf, towrite TSRMLS_CC); /* convert justwrote to an integer, since normally it is unsigned */ if ((int)justwrote > 0) { buf += justwrote; count -= justwrote; didwrite += justwrote; /* Only screw with the buffer if we can seek, otherwise we lose data * buffered from fifos and sockets */ if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { stream->position += justwrote; } } else { break; } } return didwrite; }

    上图中红色注释是我加的。可以看出,fwrite会判断写入的内容长度,如果大于8K,会分多次write。每次write是直接调用了系统的write,这个是原子的。因为有多次write,就会有被中断的可能,就可能会出现错乱。

    结论:写入小于8K,是原子性操作,不用加锁。反之需要。

    error_log和file_put_contents函数

    看这两个函数的源代码,发现最终也会调用_php_stream_write_buffer,所以结果是一样的。

    程序验证:

    先构造一个脚本,每次写10000字节(超过8K)

    $a=str_repeat($argv[1],10000);
    $i=0;
    while($i++<10000)
    file_put_contents('temp',$a."
    ",FILE_APPEND);

    用shell模拟并发

    for((j=0;j<10;j++));do
            php test.php a&
            php test.php b&
    done

    结果可以明显看出来,出现了大量的错乱。

    wc -l temp 
    200000 temp
    grep -P '(ab|ba)' temp|wc -l
    54579

    如果把每次10000字节,改成8000如何呢,下面结果很明显了?

    wc -l temp 
    200000 temp
    grep -P '(ab|ba)' temp|wc -l       
    0

    TIP:怎么快速找到源代码呢?参考我的一篇博客中的方法:http://www.cnblogs.com/hxdoit/p/5193598.html

  • 相关阅读:
    如何使用GOOGLE高级搜索技巧
    你所认为的极限,可能只是别人眼中的起点
    飞机选座——附:东航320选坐攻略
    古诗词里,从初识到相爱到分离到重逢的漫长过程
    从零开始学摄影
    Python之运维
    Linux用户和组密令大全
    centos7 下安装生物信息软件的问题小总结
    VMware锁定文件失败开启模块diskearly的操作失败未能启动虚拟机
    linux 基本命令整理--转
  • 原文地址:https://www.cnblogs.com/hxdoit/p/5544424.html
Copyright © 2011-2022 走看看