Как написать в файл в большом приложении PHP (несколько вопросов) - PullRequest
7 голосов
/ 01 марта 2010

Каков наилучший способ записи в файлы в большом приложении php. Допустим, в секунду требуется много записей. Как лучше всего это сделать.

Могу ли я просто открыть файл и добавить данные. Или я должен открыть, заблокировать, написать и разблокировать.

Что произойдет с файлом, над которым нужно работать, и нужно записать другие данные Будет ли эта деятельность потеряна или будет сохранена? и если это будет сохранено, будет остановлено приложение.

Если вы были, спасибо за чтение!

Ответы [ 7 ]

9 голосов
/ 02 марта 2010

Вот простой пример, который подчеркивает опасность одновременной игры:

<?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

Это потому, что добавление файла является атомарным, если :

  1. Вы делаете один вызов fwrite ()
  2. и что fwrite () меньше, чем PIPE_BUF (где-то около 1-4k)
  3. и вы пишете в полностью POSIX-совместимую файловую систему

Если вы делаете более одного вызова fwrite во время добавления журнала или пишете больше, чем около 4k, все ставки выключены.

Теперь о том, имеет ли это значение: нормально ли вам иметь несколько поврежденных строк в вашем журнале под большой нагрузкой? Честно говоря, в большинстве случаев это вполне приемлемо, и вы можете избежать накладных расходов на блокировку файлов.

6 голосов
/ 01 марта 2010

У меня есть высокопроизводительное многопоточное приложение, в котором все потоки записывают (добавляют) в один файл журнала. Пока что никаких проблем с этим не замечено, каждый поток пишет несколько раз в секунду и ничего не теряется. Я думаю, что просто добавление к огромному файлу не должно быть проблемой. Но если вы хотите изменить уже существующий контент, особенно с параллелизмом - я бы пошел с блокировкой, иначе может случиться большой беспорядок ...

4 голосов
/ 01 марта 2010

Если параллелизм является проблемой, вы действительно должны использовать базы данных.

1 голос
/ 29 марта 2010

Это мои 2p.

Если только по конкретной причине не нужен уникальный файл, я бы не стал добавлять все в огромный файл.Вместо этого я бы обернул файл по времени и измерению.Для этого можно определить несколько параметров конфигурации (wrap_time и wrap_size).

Кроме того, я бы, вероятно, ввел некоторую буферизацию , чтобы избежать ожидания завершения операции записи.

Возможно, PHP не самый адаптированный язык для операций такого рода, но это все еще возможно.

1 голос
/ 29 марта 2010

Если вы просто пишете журналы, возможно, вам стоит взглянуть на функцию syslog, поскольку syslog предоставляет API. Вы также должны делегировать записи в специальный бэкэнд и выполнять работу в асинхронном порядке?

0 голосов
/ 01 марта 2010

Если вам просто нужно добавить данные, PHP должен с этим справиться, поскольку файловая система должна заботиться об одновременном добавлении.

0 голосов
/ 01 марта 2010

Использование flock ()

См. вопрос

...