如何在大型 php 应用程序中写入文件(多问)
Posted
技术标签:
【中文标题】如何在大型 php 应用程序中写入文件(多问)【英文标题】:How to write to file in large php application(multiple questions) 【发布时间】:2011-01-22 11:06:20 【问题描述】:在大型 php 应用程序中写入文件的最佳方式是什么。可以说每秒需要大量写入。最好的方法是什么。
我可以打开文件并附加数据吗?或者我应该打开、锁定、写入和解锁。
文件会发生什么,需要写入其他数据。这个活动会丢失,还是会被保存。如果这将被保存将停止应用程序。
如果你去过,谢谢你的阅读!
【问题讨论】:
【参考方案1】:如果并发是一个问题,那么您真的应该使用数据库。
【讨论】:
我正在写入日志文件。对数据库的写入已经很重了,所以对于日志文件,我只想写入文件。 文件也应该是并发的。【参考方案2】:使用flock()
看到这个question
【讨论】:
【参考方案3】:如果您只需要追加数据,PHP 应该可以,因为文件系统应该负责同时追加。
【讨论】:
标准 linux 文件系统肯定不“照顾”同时追加。举一个简单的例子来说明为什么会这样,想象一下:两个进程在彼此的毫秒内打开同一个文件,并以每秒 100 兆的速度附加一个 gig 的数据——这意味着每个进程的写入时间为 10 秒。文件系统如何确保写入不重叠?是否应该缓冲来自第二个进程的数据,直到第一个进程完成? 好吧,既然你使用了绝对荒谬的例子,我只想说:PHP 无法每秒追加 100 兆,它也无法处理这些数据。虽然,你可以对这样的假设情况是正确的,但现实是另一回事,正如上面所说的那样,附加只是有效的。吃那个。 发布了一个简单的真实示例,显示了多个同时附加的相互冲突。 ***.com/questions/2358818/…【参考方案4】:我确实有高性能的多线程应用程序,其中所有线程都在写入(附加)到单个日志文件。到目前为止,没有注意到任何问题,每个线程每秒写入多次,并且没有任何丢失。我认为只是附加到大文件应该没有问题。但是,如果您想修改已经存在的内容,尤其是并发性 - 我会选择锁定,否则可能会发生大混乱......
【讨论】:
+1。我每天都会在我的 apache 访问日志中获得重叠的条目,因此在高负载时肯定会发生一些损失。但是对于一个日志文件,被破坏的那几行真的无关紧要,而且它们当然不值得文件锁定的开销。 @Laimoncijus,你的意思是追加是原子的吗?【参考方案5】:这里有一个简单的例子,突出了同时写的危险:
<?php
for($i = 0; $i < 100; $i++)
$pid = pcntl_fork();
//only spawn more children if we're not a child ourselves
if(!$pid)
break;
$fh = fopen('test.txt', 'a');
//The following is a simple attempt to get multiple threads to start at the same time.
$until = round(ceil(time() / 10.0) * 10);
echo "Sleeping until $until\n";
time_sleep_until($until);
$myPid = posix_getpid();
//create a line starting with pid, followed by 10,000 copies of
//a "random" char based on pid.
$line = $myPid . str_repeat(chr(ord('A')+$myPid%25), 10000) . "\n";
for($i = 0; $i < 1; $i++)
fwrite($fh, $line);
fclose($fh);
echo "done\n";
如果附加是安全的,您应该得到一个包含 100 行的文件,所有这些行大约 10,000 个字符长,并且以整数开头。有时,当你运行这个脚本时,这正是你会得到的。有时,一些追加会发生冲突,但是会被破坏。
您可以使用grep '^[^0-9]' test.txt
找到损坏的行
这是因为file append is only atomic if:
-
您进行了一次 fwrite() 调用
并且 fwrite() 小于 PIPE_BUF(大约 1-4k)
然后您写入完全符合 POSIX 的文件系统
如果您在日志追加期间多次调用 fwrite,或者写入超过 4k,则所有赌注都将被取消。
现在,至于这是否重要:您是否可以在高负载下在日志中出现一些损坏的行?老实说,大多数情况下这是完全可以接受的,并且可以避免文件锁定的开销。
【讨论】:
【参考方案6】:如果你只是写日志,也许你需要看看 syslog 函数,因为syslog 提供了一个 api。 您还应该将写入委托给专门的后端并以异步方式完成工作?
【讨论】:
【参考方案7】:这些是我的 2p。
除非出于特定原因需要一个唯一的文件,否则我会避免将所有内容附加到一个大文件中。相反,我会按时间和维度包装文件。可以为此定义几个配置参数(wrap_time 和 wrap_size)。
另外,我可能会引入一些缓冲以避免等待写操作完成。
可能 PHP 不是最适合这种操作的语言,但它仍然是可能的。
【讨论】:
以上是关于如何在大型 php 应用程序中写入文件(多问)的主要内容,如果未能解决你的问题,请参考以下文章