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

static size_t _php_stream_write_buffer(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
{vv
size_t didwrite = , 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) == && stream->readpos != stream->writepos) {
stream->readpos = stream->writepos = ; stream->ops->seek(stream, stream->position, SEEK_SET, &stream->position TSRMLS_CC);
} while (count > ) {
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 > ) {
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) == ) {
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."\n",FILE_APPEND);

用shell模拟并发

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

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

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

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

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

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

最新文章

  1. 2016HUAS_ACM暑假集训3C - Til the Cows Come Home
  2. java如何操作注册表(Preferences类)(在windows的注册表中保存、读取)
  3. 安装 jdk、tomcat
  4. PHP之SQL防注入代码集合(建站常用)
  5. Python 全栈开发 -- 开发环境篇
  6. java学习:AWT组件和事件处理的笔记(1)--Frame
  7. nodejs 下载网页及相关资源文件
  8. xzzx
  9. 事务之使用JDBC进行事务的操作2
  10. C++ Sqlite3的基本使用
  11. php进阶--菜鸟之路
  12. 3、调试AngularJs
  13. mfc视类中错误:IntelliSense: declaration is incompatible with。。。解决方案
  14. Java and C# Comparison
  15. PostgreSQL分布式架构之——PL/Proxy
  16. vue 中 命名视图的用法
  17. 使用开源库 MagicalRecord 操作 CoreData
  18. Deploy Openstack all-in-one Shell Script
  19. navigator.geolocation在IOS10系统中无法定位问题
  20. python抓取链家房源信息(二)

热门文章

  1. 重启Finder
  2. C# 启动进程和杀死进程
  3. [JavaScript] 用html5 js实现浏览器全屏
  4. MYSQL中插入数据时出现的问题:
  5. Lua 笔记
  6. Altium自定义的快捷键设置
  7. leetcode面试准备: Maximal Rectangle
  8. 转:Web service是什么?
  9. tlplayer for wince 版本正式商用
  10. apache开源项目--Ignite