Предотвращение тупика, вызванного стадом - PullRequest
5 голосов
/ 24 апреля 2011

Я пытаюсь смоделировать запись файла на загруженном сайте.Я написал следующий код, который в конечном итоге приводит к зависанию компьютера.

$loop = 10000;
$sleep = 500000;
$i =0;

while($i < $loop) {

    $mtime = microtime();
    $mtime = explode(" ",$mtime);
    $mtime = $mtime[1] + $mtime[0];
    $starttime = $mtime; 

    $handler = fopen($file,"a+");
    if($handler) {
    if (flock($handler, LOCK_EX)) {
        $mtime = microtime();
        $mtime = explode(" ",$mtime);
        $mtime = $mtime[1] + $mtime[0];
        $endtime = $mtime;
        $totaltime = ($endtime - $starttime); 

        fwrite($handler,"Script 1 took $totaltime secs\n");
    }

    flock($handler, LOCK_UN);
    fclose($handler);
}
$i++;
usleep($sleep);
}

Я не могу использовать LOCK_NB, потому что он не будет работать на Windows.Код работает нормально, если менее 13 процессов одновременно выполняют вышеуказанный код.Как мне справиться с этой тупиковой ситуацией?

Ответы [ 4 ]

2 голосов
/ 07 сентября 2012

Читая ваш код, я думаю, вы должны переместить "flock ($ handler, LOCK_UN);" внутри условного блока if (flock ($ handler, LOCK_EX)) {} ".

Чтобы точно выяснить, что и где застревает, я бы добавил метки даты (и сбрасывал, чтобы ничего не зависло в буфере вывода) отладки вывода как до, так и после каждого вызова flock (), fopen (), fwrite () и fclose () и перенаправить вывод каждого экземпляра скрипта в свой собственный файл.

Затем, после замораживания + перезапуска, вы можете просмотреть конец каждого файла и посмотреть, что делал каждый скрипт при перезапуске. Сравнивая метки даты, вы сможете увидеть, какие сценарии «заморозили» первыми.

1 голос
/ 12 сентября 2011

Перед тем, как написать еще немного php-кода, я рекомендую вам использовать приложение AB (тест Apache), поставляемое с Apache, и имитировать высокую нагрузку на локальный хост EX>

ab -n 1000 -c 200 http://localhost/your.php

С этим вы можете симулировать 200 одновременных пользователей и 1000 запросов.

1 голос
/ 25 апреля 2011

Hy

Попробуйте с file_put_contents():

<?php

$file = 'file.txt';

$str = "some text\n";

file_put_contents($file, $str, FILE_APPEND | LOCK_EX);

?>

0 голосов
/ 08 сентября 2014

Попробуйте "защитить" LOCK_EX с помощью дополнительного mkdir() механизма блокировки, как описано здесь: https://stackoverflow.com/a/7927642/318765

Пример:

<?php
$file = 'deadlock.txt';
$loop = 10000;
$sleep = 500000;
$i = 0;
while ($i < $loop) {
    $starttime = microtime(true);
    $handler = fopen($file, 'a+');
    if ($handler) {
        if (!file_exists($file . '_lock')) {
            if (mkdir($file . '_lock')) {
                if (flock($handler, LOCK_EX)) {
                    $endtime = microtime(true);
                    $totaltime = ($endtime - $starttime);
                    $totaltime = number_format($endtime - $starttime, 10);
                    if ($totaltime > 1) {
                        break;
                    }
                }
                flock($handler, LOCK_UN);
                fclose($handler);
                rmdir($file . '_lock');
            }
        }
    }
    $i++;
    usleep($sleep);
}
?>

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

В Linux я использую этот mkdir() трюк без flock(), поскольку он атомарный. Я не знаю, работает ли это и в Windows.

...