本文介绍了如何在一段时间内重试PHP flock()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要打开一个日志文件进行写入.麻烦的是,很多事情可能同时发生,我不想发生冲突.每次写入都将是一行,通常大约为150个字节(且始终小于1K),并且严格要求按时间顺序进行存储.

I need to open a log file for writing. Trouble is, many things may do this at the same time, and I don't want conflicts. Each write will be a single line, generally about 150 bytes (and always less than 1K), and getting things in chronological order is not strictly required.

思考我想要的是尝试flock(),如果失败,请继续尝试几秒钟.如果尝试多次后仍无法建立锁,请放弃.

I think what I want is to attempt to flock(), and if it fails, keep trying for a few seconds. If a lock can't be established after a number of tries, then give up.

$fh=fopen($logfile, "a");

if (flock($fh, LOCK_EX|LOCK_NB)) {
  $locked=TRUE;
} else {
  $locked=FALSE;
  // Retry lock every 0.1 seconds for 3 seconds...
  $x=0; while($x++ < 30) {
    usleep(100000);
    if (flock($fh, LOCK_EX|LOCK_NB)) {
      $locked=TRUE;
      break;
    }
  }
}

if ($locked) {
  if (fwrite($fh, strftime("[%Y-%m-%d %T] ") . $logdata . "\n")) {
    print "Success.\n";
  } else {
    print "Fail.\n";
  }
  flock($fh, LOCK_UN)
} else {
  print "Lock failed.\n";
}

我有两个问题,一个是一般问题,另一个是具体问题.首先,除了以不同的方式(do...while等)实现相同的解决方案外,还有一种更好的处理此类问题的通用策略,该策略仅在PHP中运行吗?其次,有没有更好的方法可以在PHP中实现呢? (是的,我将它们分开是因为我对策略部分真的很感兴趣.)

I have two questions, one general and one specific. First, aside from implementing the same solution in different ways (do...while, etc), is there a better general strategy for handling this kind of problem, that runs solely in PHP? Second, is there a better way of implementing this in PHP? (Yes, I separated these because I'm really interested in the strategy part.)

我考虑过的另一种方法是使用 syslog(),但是PHP代码可能需要运行在可能无法选择系统级管理(即向/etc/syslog.conf中添加内容)的平台上.

One alternative I've considered is to use syslog(), but the PHP code may need to run on platforms where system-level administration (i.e. adding things to /etc/syslog.conf) may not be available as an option.

更新:根据 randy 的建议,在上面的代码中添加了|LOCK_NB.

UPDATE: added |LOCK_NB to the code above, per randy's suggestion.

推荐答案

以我在PHP中制作日志的长期经验(在Linux下!),我从未遇到过冲突问题(即使有数百个同时进行和并发写入的情况).如此简单的跳过锁管理:

In my long experience in PHP making logs (under linux!) I've never experienced problems of conflicts (even with hundreds of simultaneus and concurrent writes). So simple skip lock maagement:

$fh=fopen($logfile, "a");
if (fwrite($fh, strftime("[%Y-%m-%d %T] ") . $logdata . "\n")) {
    print "Success.\n";
  } else {
    print "Fail.\n";
  }
fclose($fh);

关于此策略,文件记录(带锁或不带锁)不是最佳解决方案,因为每个带有" a "的fopen都意味着必须进行一次搜寻系统调用才能设置光标放在文件末尾. syslog 保持文件打开以避免这种开销.

About this strategy the file logging (with or without lock) is not the best solution, because every fopen with the "a" imply a seek syscall to set the cursor at the end of the file. syslog keeping the file open avoid this overhead.

当然,对于大"文件,开销会变得很重要(在性能上),一个简单的解决方案是创建名称为日期(或日期时间)的日志文件.

Of course the overhead become significative (in performance) with "big" files, an easy solution is create log file with date (or date-time) in the name.

添加

apache程序包包含一个测试程序: ab ,允许并发执行查询,您可以测试我的论文,用10to1000个线程完成1000000个查询来强调服务器.

apache package include a tester program: ab, allowing doing query in concurrency, you can test my thesis stressing your server with 1000000 of query done by 10to1000 threads.

添加-在评论之后

不,这不是不可能的任务.

No, it'not an impossible task.

我从 http://php中找到了便笺. net/manual/en/function.fwrite.php

I found a note from http://php.net/manual/en/function.fwrite.php

了解一个字节的块有多大(通常为4k):

to know how big is a block in bytes (usual 4k):

实现写入的原子性"是为了阻止其他代理"进行写入(当您在"ps ax"中看到处于"D"状态的进程)时,但是 PHP 流设施可以解决此问题,请参阅:* stream_set_blocking *.这种方法可能会引入部分写入,因此您将必须验证记录的完整性.

The "atomicity" of write is realized blocking other "agents" to write (when you see process in "D" status in "ps ax"), BUT PHP stream facility can solve this problem, see: *stream_set_blocking*.This approach can introduce partial writes, so you will have to validate the integrity of your records.

无论如何, fwrite (网络或文件)很容易被阻止/失败,无论使用 flock 如何.恕我直言,羊群只会带来开销.

In any case a fwrite (network or file) is susceptible to block/failure regardless of use of flock. IMHO flock introduce only overhead.

关于您最初的问题和您的目标(试图在高度规避风险的环境中实施公司政策),即使fwrite也可能有问题,我只能想象一个简单的解决方案:使用数据库

About your original questions AND your goal (trying to implement corporate policy in a highly risk-averse environment), where even a fwrite can be problematic, I can only imagine a simple solution: use a DB

  • 最复杂的部分不是PHP,而是用C编写的!
  • 完全控制操作流程
  • 并发级别

这篇关于如何在一段时间内重试PHP flock()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 11:16