За последние 24 часа нас посетили 23742 программиста и 1549 роботов. Сейчас ищут 1033 программиста ...

[Бенчмарк] Поиск ключа по ini файлу

Тема в разделе "Прочие вопросы по PHP", создана пользователем Ganzal, 16 мар 2015.

  1. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    О чем этот пост?
    Данный пост рассматривает бенчмарк нескольких подходов к решению задачи озвученной в посте Поиск ключа по ini файлу.
    Букв будет очень много. Можно сразу прокрутить до главы "Просто цифры" но тогда будет не понятно что некоторые из них означают.


    Чо тестировали?
    В тесте приняли участие несколько реализаций (кодовое имя: описание):
    • INETCHIK_01: алгоритм предложенный пользователем INETCHIK в посте 419045
      Модификация кода:
      Код (PHP):
      1. error_reporting(E_ALL); // удалено. вряд ли кто-то будет включать вывод ошибок для небольшого куска кода. а поскольку тест запускается в консоли - там и так E_ALL по дефолту.
      2. $ip=getenv('REMOTE_ADDR'); // удалено. айпишник приходит при вызове метода
      3. $f='ip.txt'; // удалено. у нас свой путь к файлу
      4. if(strpos(file_get_contents($f), $ip)===false){file_put_contents($f, "$ip=1\r\n", FILE_APPEND); } // переменная $f заменена нашей реализацией имени к файлу, последовательность \r\n на PHP_EOL, другое форматирование строк
      5. else{
      6. $ar=file($f); // замена $f на нашу
      7. foreach ($ar as $k=>$v) {
      8. if(strpos($v, $ip) !==false) {
      9. $sub=substr($v, strlen($ip)+1);
      10. $ar[$k]=$ip.'='.($sub+1)."\r\n"; // замена \r\n на PHP_EOL
      11. file_put_contents($f, $ar); // замена $f на нашу
      12. break;
      13. }
      14. }
      15. } 
      выходной вариант:
      Код (PHP):
      1. class ru_php_forum_52305_INETCHIK_01 extends ru_php_forum_52305 {
      2.     public static function inc ($ip) {
      3.         if (strpos(file_get_contents(static::FILE), $ip)===false) {
      4.             file_put_contents(static::FILE, "$ip=1".PHP_EOL, FILE_APPEND);
      5.         } else {
      6.             $ar = file(static::FILE);
      7.             foreach ($ar as $k=>$v) {
      8.                 if(strpos($v, $ip) !==false) {
      9.                     $sub=substr($v, strlen($ip)+1);
      10.                     $ar[$k]=$ip.'='.($sub+1).PHP_EOL;
      11.                     file_put_contents(static::FILE, $ar);
      12.                     break;
      13.                 }
      14.             }
      15.         }
      16.     }
      17. }
      [/*:m]
    • mahmuzar_01, mahmuzar_02, mahmuzar_03: алгоритмы пользователя mahmuzar из постов 418894 (01, 02) и 418988 (03).
      Расписывать дельту не буду ибо там всего пара замен: 1) учет того что айпишник аргументом, 2) путь к файлу и 3) убрано лишнее общение скрипта с человеком.
      Первая реализация первого поста:
      Код (PHP):
      1. <?php
      2. class ru_php_forum_52305_mahmuzar_01 extends ru_php_forum_52305 {
      3.     public static function inc ($ip) {
      4.         /*
      5. //открываем файл, и сохраним его содержимое в переменной
      6. //сначала разбив на ip и его значение, которое идет после
      7. // получим такого вида массив:
      8.  * array(3) {
      9.   [0]=>
      10.   array(2) {
      11.     [0]=>
      12.     string(12) "11.11.11.11 "
      13.     [1]=>
      14.     string(3) "3
      15. "
      16.   }
      17.   [1]=>
      18.   array(2) {
      19.     [0]=>
      20.     string(12) "44.44.44.44 "
      21.     [1]=>
      22.     string(2) "1
      23. "
      24.   }
      25.   [2]=>
      26.   array(2) {
      27.     [0]=>
      28.     string(12) "88.88.88.88 "
      29.     [1]=>
      30.     string(3) "1
      31. "
      32.   }
      33. }
      34.  * 
      35.  * пример чтения файла взять из документации php.net с последюющим незначительными
      36.  * правками
      37.  * http://php.ru/manual/function.fgets.html
      38.  */
      39. $handle = @fopen(static::FILE, "r");//получим файловый указатель.
      40. $i = 0;
      41. if ($handle) {
      42.     while (($buffer = fgets($handle)) !== false) {
      43.  
      44.         $ip_data[] = explode("=", $buffer);
      45.         $i++;
      46.     }
      47.     if (!feof($handle)) {
      48.         echo "Error: unexpected fgets() fail\n";
      49.     }
      50.     fclose($handle);
      51. }
      52.  
      53. //отладка
      54. /*echo "<pre>";
      55. var_dump($ip_data);
      56. echo "</pre>";*/
      57.  
      58. /*
      59.  * теперь имея массив с данными из файла, мы  можем сравнивать IP-адреса с 
      60.  * IP-адресом из переменной $ip
      61.  * 
      62.  * 
      63.  */
      64. //пусть $ip = "88.88.88.88";
      65.  
      66. $to_write;
      67. for ($j = 0; $j < count($ip_data); $j++) {
      68.     if (strcmp($ip, trim($ip_data[$j][0])) === 0) {
      69.         $new_value = trim($ip_data[$j][1])+1;
      70.         $to_write .=$ip_data[$j][0] . "=" . $new_value . "\r\n";
      71.     } else {
      72.         $to_write .=$ip_data[$j][0] . "=" . trim($ip_data[$j][1]) . "\r\n";
      73.     }
      74.  
      75.  
      76.     
      77. }
      78.  
      79. //отладка
      80. /*echo "<pre>";
      81. var_dump($to_write);
      82. echo "</pre>";*/
      83.  
      84. /*
      85.  * Теперь, сохраним изменения в файле
      86.  * 
      87.  * Этот код тоже взять из документации
      88.  * с незначительными изменениями.
      89.  * http://php.ru/manual/function.fwrite.html
      90.  */
      91. $filename = static::FILE;
      92. // Вначале давайте убедимся, что файл существует и доступен для записи.
      93. if (is_writable($filename)) {
      94.  
      95.     //
      96.     //Открывает файл только для записи; помещает указатель в начало файла и 
      97.     //обрезает файл до нулевой длины. Если файл не существует - пробует его создать.
      98.     if (!$handle = fopen($filename, 'w')) {
      99.          echo "Не могу открыть файл ($filename)";
      100.          exit;
      101.     }
      102.  
      103.     // Записываем $to_write в наш открытый файл.
      104.     if (fwrite($handle, $to_write) === FALSE) {
      105.         echo "Не могу произвести запись в файл ($filename)";
      106.         exit;
      107.     }
      108.  
      109.     #echo "Ура! Записали ($somecontent) в файл ($filename)";
      110.  
      111.     fclose($handle);
      112.  
      113. } else {
      114.     echo "Файл $filename недоступен для записи";
      115. }
      116. unset($handle);
      117.     }
      118. }
      Вторая реализация первого поста - автор добавил блокировку файла:
      Код (PHP):
      1. class ru_php_forum_52305_mahmuzar_02 extends ru_php_forum_52305 {
      2.     public static function inc ($ip) {
      3.  
      4. /*
      5.   //открываем файл, и сохраним его содержимое в переменной
      6.   //сначала разбив на ip и его значение, которое идет после
      7.   // получим такого вида массив:
      8.  * array(3) {
      9.   [0]=>
      10.   array(2) {
      11.   [0]=>
      12.   string(12) "11.11.11.11 "
      13.   [1]=>
      14.   string(3) "3
      15.   "
      16.   }
      17.   [1]=>
      18.   array(2) {
      19.   [0]=>
      20.   string(12) "44.44.44.44 "
      21.   [1]=>
      22.   string(2) "1
      23.   "
      24.   }
      25.   [2]=>
      26.   array(2) {
      27.   [0]=>
      28.   string(12) "88.88.88.88 "
      29.   [1]=>
      30.   string(3) "1
      31.   "
      32.   }
      33.   }
      34.  * 
      35.  * пример чтения файла взять из документации php.net с последюющим незначительными
      36.  * правками
      37.  * http://php.ru/manual/function.fgets.html
      38.  */
      39. $handle = @fopen(static::FILE, "r"); //получим файловый указатель.
      40. $i = 0;
      41. if (flock($handle, LOCK_EX)) { // выполняем эксклюзивную блокировку
      42.     ftruncate($handle, 0); // очищаем файл
      43.     if ($handle) {
      44.         while (($buffer = fgets($handle)) !== false) {
      45.  
      46.             $ip_data[] = explode("=", $buffer);
      47.             $i++;
      48.         }
      49.         if (!feof($handle)) {
      50.             echo "Error: unexpected fgets() fail\n";
      51.         }
      52.  
      53.         fflush($handle);        // очищаем вывод перед отменой блокировки
      54.         flock($handle, LOCK_UN); // отпираем файл
      55.         fclose($handle);//закрываем открыйтый дескриптор файла
      56.     }
      57. }
      58.  
      59. //отладка
      60. /*echo "<pre>";
      61. var_dump($ip_data);
      62. echo "</pre>";*/
      63.  
      64. /*
      65.  * теперь имея массив с данными из файла, мы  можем сравнивать IP-адреса с 
      66.  * IP-адресом из переменной $ip
      67.  * 
      68.  * 
      69.  */
      70. //пусть $ip = "88.88.88.88";
      71. /*$ip = "88.88.88.88";*/
      72. $to_write;
      73. for ($j = 0; $j < count($ip_data); $j++) {
      74.     if (strcmp($ip, trim($ip_data[$j][0])) === 0) {
      75.         $new_value = trim($ip_data[$j][1]) + 1;
      76.         $to_write .=$ip_data[$j][0] . "=" . $new_value . "\r\n";
      77.     } else {
      78.         $to_write .=$ip_data[$j][0] . "=" . trim($ip_data[$j][1]) . "\r\n";
      79.     }
      80. }
      81.  
      82. //отладка
      83. /*echo "<pre>";
      84. var_dump($to_write);
      85. echo "</pre>";*/
      86.  
      87. /*
      88.  * Теперь, сохраним изменения в файле
      89.  * 
      90.  * Этот код тоже взять из документации
      91.  * с незначительными изменениями.
      92.  * http://php.ru/manual/function.fwrite.html
      93.  */
      94. $filename = static::FILE;
      95. // Вначале давайте убедимся, что файл существует и доступен для записи.
      96. if (is_writable($filename)) {
      97.  
      98.  
      99.     //Открывает файл только для записи; помещает указатель в начало файла и 
      100.     //обрезает файл до нулевой длины. Если файл не существует - пробует его создать.
      101.     if (!$handle = fopen($filename, 'w')) {
      102.         echo "Не могу открыть файл ($filename)";
      103.         exit;
      104.     }
      105.     if (flock($handle, LOCK_EX)) { // выполняем эксклюзивную блокировку
      106.         ftruncate($handle, 0); // очищаем файл
      107.         // Записываем $to_write в наш открытый файл.
      108.         if (fwrite($handle, $to_write) === FALSE) {
      109.             echo "Не могу произвести запись в файл ($filename)";
      110.             exit;
      111.         }
      112.  
      113.         #echo "Ура! Записали ($somecontent) в файл ($filename)";
      114.         fflush($handle);        // очищаем вывод перед отменой блокировки
      115.         flock($handle, LOCK_UN); // отпираем файл
      116.         fclose($handle);//закрываем открыйтый дескриптор файла
      117.     } else {
      118.         echo "Файл $filename недоступен для записи";
      119.     }
      120. }
      121. unset($handle);
      122.  
      123.     }
      124. }
      Ну и третья реализация, из второго поста:
      Код (PHP):
      1. class ru_php_forum_52305_mahmuzar_03 extends ru_php_forum_52305 {
      2.     public static function inc ($ip) {
      3.  
      4. //откроем файл для чтения и записи
      5. $fp = fopen(static::FILE, 'r+') or die("не удалось прочесть файл");
      6. //пусть $ip = "132.154.226.1";
      7. #$ip = "132.154.226.1";
      8.  
      9. if (flock($fp, LOCK_EX)) { // выполняем эксклюзивную блокировку
      10.     while (($line = fgets($fp)) !== false) {
      11.         //$line - это прочтенная строка из файла
      12.         $ip_from_file = trim(strstr($line, '=', TRUE));//получим из строки ip
      13.         $ip_value = trim(substr($line, strrpos($line, '=') + 1));//получим значение ip
      14.  
      15.         if (strcmp($ip, $ip_from_file) === 0) {
      16.             $to_write .= $ip_from_file . "=" . sprintf($ip_value + 1) . "\r\n";
      17.         } else {
      18.             $to_write .=$ip_from_file . "=" . $ip_value . "\r\n";
      19.         }
      20.     }
      21.     
      22.     fseek($fp, 0);//переместим указатель в начало файла
      23.     ftruncate($fp, 0); // очищаем файл
      24.     //
      25.     // Записываем $to_write в наш открытый файл.
      26.     if (fwrite($fp, $to_write) === FALSE) {
      27.         echo "Не могу произвести запись в файл";
      28.         exit;
      29.     }
      30.     
      31.     fflush($fp);        // очищаем вывод перед отменой блокировки
      32.     fclose($fp); //закрываем открытый дескриптор файла
      33. }
      34.  
      35.     }
      36. }
      [/*:m]
    • denis01_02 - на самом деле мало отношения имеет к denis01. Бегло читая обсуждение сходил по ссылке и скопировал код, понял что его алгоритм не совсем ту задачу решает, но было интересно увидеть производительность посему решил немного переписать под себя. Если denis01 захочет - кодовое имя denis01_01 зарезервировано под его вариант.
      Код (PHP):
      1. <?php
      2. class ru_php_forum_52305_denis01_02 extends ru_php_forum_52305 {
      3.     public static function inc ($ip) {
      4.         $f = file(static::FILE, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
      5.         $out = '';
      6.         
      7.         $found = false;
      8.         
      9.         foreach ($f as $key => $value) {
      10.             if (!$found) {
      11.                 $x = explode('=', $value);
      12.                 if (trim($x[0]) == $ip) {
      13.                     $x[1] = 1 + $x[1];
      14.                     $found = true;
      15.                     $out .= PHP_EOL . $x[0].'= '.$x[1];
      16.                     continue;
      17.                 }
      18.                 
      19.                 $out .= PHP_EOL . $value;
      20.             } else {
      21.                 $out .= PHP_EOL . $value;
      22.             }
      23.         }
      24.         
      25.         if (!$found) {
      26.             $out .= PHP_EOL . $ip . ' = 1';
      27.         }
      28.         
      29.         file_put_contents(static::FILE, ltrim($out));
      30.     }
      31. }
      [/*:m][/list:u]


      На этом уходим в глубокое...
      Лирическое отступление.
      • Товарищь INETCHIK просил о бенчмарке алгоритма поэтому лично я не приравниваю его код к решению задачи и допускаю что код может некорректно работать с данными. На самом деле автор может спать спокойно - результаты его алгоритма близки к эталону. Ошибка мелкая, но эту ошибку допустили все участники. Даже не поверите я. Но в данном случае ошибка приводит к невосстановимой потере данных.[/*:m]
      • Более крупная ошибка это лишние чтения. Тут уже пардоньте: как можно на бенчмарк предлагать код который ДВАЖДЫ читает файл? Это уже бутылка, разве нет?
        [/*:m]
      • mahmuzar честно говоря огорчил. Все три кода высыпаются изобилием нотисов (да, не ворнингов, как я писал в основной теме), алгоритм теряет данные, алгоритм совершает лишние действия. Но автор предложил этот код именно как решение задачи. ИМХО ну нельзя предлагать что-то сырое недоделанное в данном случае. Мы говорим не о куске кода который может быть полезен в другом проекте а именно о завершенном алгоритме который должен решать сформулированную задачу.
        Опять же прикрываться статусом новичка в данном случае считаю неприемлемо. Можно опубликовать с просьбой рассмотреть алгоритм опытными участниками но не постить "на отвяжитесь" (да, тут должно быть другое слово но мы не в подворотне) якобы готовое решение. Оно не готово. Банально потому что сам автор его не отлаживал.

        А огорчил тем что считает это нормой.
        [/*:m]
      • Весь сыр-бор с бенчмарком я начал из-за моего же предложения использовать preg_replace_callback() для решения поставленной задачи. Честно я удивлен что никто не взял на себя смелость предложить рабочий алгоритм с использованием этой функции.[/*:m]
      • А зря... Давайте подумаем над решением задачи. Её алгоритм сводится к набору следующих действий:
        1. Открыли файл.[/*:m]
        2. Почитали в поисках записи.[/*:m]
        3. Если нашли - инкремент счетчика.[/*:m]
        4. Если не нашли - записали строку со счетчиком равным единице.[/*:m]
        5. Сохранили файл.[/*:m][/list:eek:]
          Я тут не увидел ни одной реализации которая бы работала с данными именно на уровне файла. И это нормально (лениво расписывать почему). Зато все алгоритмы целиком (и это тоже хорошо) считывают файл в окружение скрипта. А дальше ищут, инкрементируют или дописывают, сохраняют.
          Почему для этих целей нельзя использовать регулярные выражения? Мы ищем некоторую строку которая должна содержать в себе переданный айпишник, знак равенстра, сколько-то цифр которые мы за счетчик примем.
          Бдыщь:
          Код (Text):
          1. ^IP=\d+$
          Человек случайно ставит пробелы вокруг равно? Бдыщь:
          Код (Text):
          1. ^IP\s*=\s*\d+$
          Человек уверен что вокруг равенства будет только по одному пробелу? Ну и пусть:
          Код (Text):
          1. ^IP = \d+$
          И моё предположение было таковым: вместо того чтоб построчно итерировать содержимое файла и в каждой строке искать айпишник и делать над ним какие-то действия - быстрее будет по регулярному выражению найти вхождение айпишника и его счетчика. И в пхп-поставке регулярных выражений есть замечательная функция которая позволит сразу при нахождении вхождения айпишника соврешить инкремент его счетчика и при этом всю тягомотину с текстом "до" и с текстом "после" возьмет на себя. А если не будет вхождения то мы по традиции допишем.

          И я наступил на грабли:
          Код (PHP):
          1. $f = file_get_contents(static::FILE);
          2.  
          3. if(false !== strstr($f, $ip.'=')) {
          4.     $f = preg_replace_callback('~^('.preg_quote($ip).')\s*=\s*(\d+)$~m', function($m) {
          5.         return $m[1] . '=' . ++$m[2];
          6.     }, $f);
          7. } else {
          8.     $f .= PHP_EOL . $ip . '=1';
          9. }
          10.  
          11. file_put_contents(static::FILE, $f);
          Моё регулярное выражение с удовольствием находит все пробелы вокруг равно. Чего не скажешь о strstr(). Если пробелов не будет - код работает. Если будет - код просто добавляет каждый раз новую строку и всё. Это называется софтфейл. Данные не теряются. Их можно пересчитать. Но поскольку счетчики плывут - таки фейл.

          Да и зачем вообще искать вхождение строки если само регулярное выражение этим занимается? Но как тогда узнать было ли вхождение? А вот так:
          Код (PHP):
          1. $done = false;
          2. $f = preg_replace_callback('~^('.preg_quote($ip).')\s*=\s*(\d+)$~m', function($m) use (&$done) {
          3.     $done = true;
          4.     return $m[1] . '=' . ++$m[2];
          5. }, file_get_contents(static::FILE));
          6.  
          7. if (!$done) {
          8.     $f .= PHP_EOL . $ip . '=1';
          9. }
          10.  
          11. file_put_contents(static::FILE, $f);
          Ну и естественно раз уж я сам упомянул состояние гонки - некоторые реализации содержат блокировку файла.[/*:m][/list:u]

          Конец лирического отступления.


          Чо тестировали? Часть Ганзала.
          Напомню что я-сука-такая один из своих исходников подпихнул другому автору, но честно признал подставу. Для тех кто не читал: речь о листинге denis01_02

          Итак, полет моей фантазии:
          • ru_php_forum_52305_preg_replace_callback_01_01: первый вариант. Пишет новые строки если есть пробелы вокруг равенства:
            Код (PHP):
            1. class ru_php_forum_52305_preg_replace_callback_01_01 extends ru_php_forum_52305 {
            2.     public static function inc ($ip) {
            3.         $f = file_get_contents(static::FILE);
            4.         
            5.         if(false !== strstr($f, $ip.'=')) {
            6.             $f = preg_replace_callback('~^('.preg_quote($ip).')\s*=\s*(\d+)$~m', function($m) {
            7.                 return $m[1] . '=' . ++$m[2];
            8.             }, $f);
            9.         } else {
            10.             $f .= PHP_EOL . $ip . '=1';
            11.         }
            12.         
            13.         file_put_contents(static::FILE, $f);
            14.     }
            15. }
            [/*:m]
          • ru_php_forum_52305_preg_replace_callback_02_01: второй вариант. Красавчик вообще:
            Код (PHP):
            1. class ru_php_forum_52305_preg_replace_callback_02_01 extends ru_php_forum_52305 {
            2.     public static function inc ($ip) {
            3.         $done = false;
            4.         $f = preg_replace_callback('~^('.preg_quote($ip).')\s*=\s*(\d+)$~m', function($m) use (&$done) {
            5.             $done = true;
            6.             return $m[1] . '=' . ++$m[2];
            7.         }, file_get_contents(static::FILE));
            8.  
            9.         if (!$done) {
            10.             $f .= PHP_EOL . $ip . '=1';
            11.         }
            12.         
            13.         file_put_contents(static::FILE, $f);
            14.     }
            15. }
            [/*:m]
          • ru_php_forum_52305_preg_replace_callback_03_01: третий заход. С блокировкой файла.
            Код (PHP):
            1. class ru_php_forum_52305_preg_replace_callback_03_01 extends ru_php_forum_52305 {
            2.     
            3.     protected static $flock_attempts_limit = 100;
            4.     protected static $fopen_attempts_limit = 10;
            5.     
            6.     public static function inc ($ip) {
            7.         $done = false;
            8.         
            9.         $fopen_attempts = 0;
            10.         $flock_attempts = 0;
            11.         
            12.         while (true) {
            13.             $ff = @fopen(static::FILE, 'cb+');
            14.             
            15.             if (!$ff) {
            16.                 fclose($ff);
            17.                 
            18.                 if (++$fopen_attempts >= static::$fopen_attempts_limit) {
            19.                     throw new Exception('FOPEN Failed');
            20.                 }
            21.                 
            22.                 usleep(100);
            23.                 
            24.                 continue;
            25.             }
            26.             
            27.             if (flock($ff, LOCK_EX|LOCK_NB)) {
            28.                 break;
            29.             }
            30.             
            31.             fclose($ff);
            32.             
            33.             if (++$flock_attempts > static::$flock_attempts_limit) {
            34.                 throw new Exception('FLOCK limit reached');
            35.             }
            36.             
            37.             usleep(100);
            38.                 
            39.         } // while(true)
            40.         
            41.         $f = preg_replace_callback('~^('.preg_quote($ip).')\s*=\s*(\d+)$~m', function($m) use (&$done) {
            42.             $done = true;
            43.             return $m[1] . '=' . ++$m[2];
            44.         }, file_get_contents(static::FILE));
            45.         
            46.         if (!$done) {
            47.             $f .= PHP_EOL . $ip . '=1';
            48.         }
            49.         
            50.         file_put_contents(static::FILE, $f);
            51.         
            52.         fclose($ff);
            53.  
            54.     }
            55. }
            [/*:m]
          • ru_php_forum_52305_preg_replace_callback_03_02: третий заход, второй подзаход. Проверил что будет если мы решили что вокруг равенства будет только по одному пробелу. То есть меняется только три строки:
            Код (PHP):
            1. $f = preg_replace_callback('~^('.preg_quote($ip).') = (\d+)$~m', function($m) use (&$done) { # эта
            2.             $done = true;
            3.             return $m[1] . ' = ' . ++$m[2]; # эта
            4.         }, file_get_contents(static::FILE));
            5.         
            6.         if (!$done) {
            7.             $f .= PHP_EOL . $ip . ' = 1'; # и эта
            8.         }
            9.         
            [/*:m]
          • ru_php_forum_52305_preg_replace_callback_03_02_01: шизофрения 3-2-1. Решил проверить что будет с функцией strstr() если она тоже будет знать о фиксированном формате. Измененные строки отмечены:
            Код (PHP):
            1.         } // while(true)
            2.         
            3.         $f = file_get_contents(static::FILE); # вот
            4.         
            5.         if (false !== strstr($f, $ip.' =')) { # вот
            6.             $f = preg_replace_callback('~^('.preg_quote($ip).') = (\d+)$~m', function($m) { # вот
            7.                 return $m[1] . ' = ' . ++$m[2]; # вот
            8.             }, $f); # вот
            9.         } else { # вот
            10.             $f .= PHP_EOL . $ip . ' = 1'; # вот
            11.         } # вот
            12.         
            13.         file_put_contents(static::FILE, $f);
            [/*:m][/list:u]


            Чо тестировали? Часть Ганзала. Вне конкурса.
            Естественно я заметил очевидную вещч - чем больше строк тем толще файл. Ваш КО. Но надо ли нам тратить много места на хранение айпишника? Самый длинный айпишник в в4 описывается 15 байтами текста хотя на самом деле это всего 4 байта. Поэтому я решил протестировать еще 3 подхода в которых айпишник сохраняется хексом и занимает всегда 8 байт. Добавляем одну строку упаковки айпи и в двух строках меняем название переменной $ip на $IP:
            Код (PHP):
            1.         } // while(true)
            2.  
            3.         $IP = sprintf("%08X", ip2long($ip)); # раз
            4.         
            5.         $f = preg_replace_callback('~^('.$IP.')\s*=\s*(\d+)$~m', function($m) use (&$done) { # два
            6.             $done = true;
            7.             return $m[1] . '=' . ++$m[2];
            8.         }, file_get_contents(static::FILE));
            9.  
            10.         if (!$done) {
            11.             $f .= PHP_EOL . $IP . '=1'; # три
            12.         }
            13.         
            14.         file_put_contents(static::FILE, $f);
            формирование имен без энтузиазма ru_php_forum_52305_prc_03_01_hex_01, ru_php_forum_52305_prc_03_02_hex_01 и ru_php_forum_52305_prc_03_02_01_hex_01.


            Чо не тестировали?
            • Не стал я писать реализацию где айпишних хранится 4 байтами и счетчик хранится тоже 4 байтами и по всему этому удобно итерируемся с офсетом в 8 байт. Хекс-реализация уже потребует конвертирования айпишника, но по крайней мере человекочитаемая база остается. А тут уже без утилит не прочитаешь.[/*:m]
            • Не стал писать на скуэльлайте. Вроде и файл. Вроде и удобно языком структурированных запросов. Но без сторонних программ в этот файл нормально не посмотришь. Отпадает.[/*:m]
            • Не стал рассматривать NoSQL вроде мемкэш рэдис монго и тп. У нас тут задача с примитивным файлом и кажется человек его хочет в блокноте открывать. Без лишнего апи.[/*:m][/list:u]


              Как тестировали?
              Примитивно.
              Создали наборы айпишников и передавали их в метод inc() каждого класса.
              Каждый набор ддосил метод в несколько раундов.
              Чтоб в меня не полетела стружка с жесткого диска - файл "базы" хранился на рам-диске.

              Наборы адресов имеют следующие имена и свойства:
              • 0: 9 зайписей для 3 уникальный айпишников скопированных из поста - 11бла 44бла и 88бла. Статистика по элементам
                Код (Text):
                1. e = 2      n = 2      cc =      4 cs =      4
                2. e = 5      n = 1      cc =      5 cs =      9
                читается эта лабуда наверное так:
                по 2 вхождения, 2 адреса, суммарно вызовов 4 (дваджы-два-же-ж), контрольная сумма 4
                по 5 вхождений, 1 адрес, суммарно вызовов 5, кс 9 (пять плюс четыре)

                на деле речь о массиве:
                Код (PHP):
                1. $ips = array(
                2.     '11.11.11.11', '11.11.11.11', '11.11.11.11',
                3.     '44.44.44.44', '11.11.11.11', '88.88.88.88',
                4.     '44.44.44.44', '11.11.11.11', '88.88.88.88',
                5. );
                [/*:m]
              • 1: 117 раз для всего лишь 5 айпишников. Стат
                Код (PHP):
                1. = 13     n = 1      cc =     13 cs =     13
                2. = 19     n = 1      cc =     19 cs =     32
                3. = 24     n = 1      cc =     24 cs =     56
                4. = 18     n = 1      cc =     18 cs =     74
                5. = 43     n = 1      cc =     43 cs =    117
                [/*:m]
              • 2: прикол который кладет половину реализаций. 123 раза, 10 уников
                Код (PHP):
                1. = 1      n = 4      cc =      4 cs =      4
                2. = 2      n = 1      cc =      2 cs =      6
                3. = 13     n = 1      cc =     13 cs =     19
                4. = 19     n = 1      cc =     19 cs =     38
                5. = 18     n = 1      cc =     18 cs =     56
                6. = 24     n = 1      cc =     24 cs =     80
                7. = 43     n = 1      cc =     43 cs =    123
                Поскольку это просто руками набитые строки плюс немного магии копи-паста - так себе данные для теста. Поэтому пишем небольшой генератор списков и рожаем себе три массива по 10000 записей с разным кол-вом уникальных и повторных записей:
                [/*:m]
              • g0: 217 уников размазались как
                Код (PHP):
                1. = 14     n = 11     cc =    154 cs =    154
                2. = 1      n = 10     cc =     10 cs =    164
                3. = 9      n = 8      cc =     72 cs =    236
                4. = 3      n = 8      cc =     24 cs =    260
                5. = 6      n = 7      cc =     42 cs =    302
                6. = 2      n = 7      cc =     14 cs =    316
                7. = 11     n = 6      cc =     66 cs =    382
                8. = 41     n = 6      cc =    246 cs =    628
                9. = 21     n = 6      cc =    126 cs =    754
                10. = 8      n = 5      cc =     40 cs =    794
                11. = 13     n = 5      cc =     65 cs =    859
                12. = 10     n = 5      cc =     50 cs =    909
                13. = 22     n = 5      cc =    110 cs =   1019
                14. = 4      n = 5      cc =     20 cs =   1039
                15. = 5      n = 5      cc =     25 cs =   1064
                16. = 23     n = 4      cc =     92 cs =   1156
                17. = 7      n = 4      cc =     28 cs =   1184
                18. = 12     n = 4      cc =     48 cs =   1232
                19. = 32     n = 3      cc =     96 cs =   1328
                20. = 15     n = 3      cc =     45 cs =   1373
                21. = 17     n = 3      cc =     51 cs =   1424
                22. = 113    n = 3      cc =    339 cs =   1763
                23. = 45     n = 3      cc =    135 cs =   1898
                24. = 16     n = 3      cc =     48 cs =   1946
                25. = 53     n = 3      cc =    159 cs =   2105
                26. = 29     n = 2      cc =     58 cs =   2163
                27. = 33     n = 2      cc =     66 cs =   2229
                28. = 27     n = 2      cc =     54 cs =   2283
                29. = 38     n = 2      cc =     76 cs =   2359
                30. = 36     n = 2      cc =     72 cs =   2431
                31. = 42     n = 2      cc =     84 cs =   2515
                32. = 57     n = 2      cc =    114 cs =   2629
                33. = 81     n = 2      cc =    162 cs =   2791
                34. = 25     n = 2      cc =     50 cs =   2841
                35. = 122    n = 2      cc =    244 cs =   3085
                36. = 56     n = 2      cc =    112 cs =   3197
                37. = 121    n = 2      cc =    242 cs =   3439
                38. = 18     n = 2      cc =     36 cs =   3475
                39. = 34     n = 2      cc =     68 cs =   3543
                40. = 35     n = 2      cc =     70 cs =   3613
                41. = 90     n = 2      cc =    180 cs =   3793
                42. = 55     n = 1      cc =     55 cs =   3848
                43. = 59     n = 1      cc =     59 cs =   3907
                44. = 37     n = 1      cc =     37 cs =   3944
                45. = 50     n = 1      cc =     50 cs =   3994
                46. = 28     n = 1      cc =     28 cs =   4022
                47. = 30     n = 1      cc =     30 cs =   4052
                48. = 39     n = 1      cc =     39 cs =   4091
                49. = 46     n = 1      cc =     46 cs =   4137
                50. = 48     n = 1      cc =     48 cs =   4185
                51. = 31     n = 1      cc =     31 cs =   4216
                52. = 26     n = 1      cc =     26 cs =   4242
                53. = 72     n = 1      cc =     72 cs =   4314
                54. = 157    n = 1      cc =    157 cs =   4471
                55. = 520    n = 1      cc =    520 cs =   4991
                56. = 153    n = 1      cc =    153 cs =   5144
                57. = 197    n = 1      cc =    197 cs =   5341
                58. = 176    n = 1      cc =    176 cs =   5517
                59. = 143    n = 1      cc =    143 cs =   5660
                60. = 165    n = 1      cc =    165 cs =   5825
                61. = 126    n = 1      cc =    126 cs =   5951
                62. = 117    n = 1      cc =    117 cs =   6068
                63. = 220    n = 1      cc =    220 cs =   6288
                64. = 265    n = 1      cc =    265 cs =   6553
                65. = 289    n = 1      cc =    289 cs =   6842
                66. = 166    n = 1      cc =    166 cs =   7008
                67. = 103    n = 1      cc =    103 cs =   7111
                68. = 251    n = 1      cc =    251 cs =   7362
                69. = 267    n = 1      cc =    267 cs =   7629
                70. = 148    n = 1      cc =    148 cs =   7777
                71. = 279    n = 1      cc =    279 cs =   8056
                72. = 129    n = 1      cc =    129 cs =   8185
                73. = 86     n = 1      cc =     86 cs =   8271
                74. = 161    n = 1      cc =    161 cs =   8432
                75. = 84     n = 1      cc =     84 cs =   8516
                76. = 79     n = 1      cc =     79 cs =   8595
                77. = 85     n = 1      cc =     85 cs =   8680
                78. = 76     n = 1      cc =     76 cs =   8756
                79. = 62     n = 1      cc =     62 cs =   8818
                80. = 51     n = 1      cc =     51 cs =   8869
                81. = 61     n = 1      cc =     61 cs =   8930
                82. = 58     n = 1      cc =     58 cs =   8988
                83. = 70     n = 1      cc =     70 cs =   9058
                84. = 91     n = 1      cc =     91 cs =   9149
                85. = 40     n = 1      cc =     40 cs =   9189
                86. = 63     n = 1      cc =     63 cs =   9252
                87. = 100    n = 1      cc =    100 cs =   9352
                88. = 114    n = 1      cc =    114 cs =   9466
                89. = 97     n = 1      cc =     97 cs =   9563
                90. = 95     n = 1      cc =     95 cs =   9658
                91. = 77     n = 1      cc =     77 cs =   9735
                92. = 105    n = 1      cc =    105 cs =   9840
                93. = 111    n = 1      cc =    111 cs =   9951
                94. = 49     n = 1      cc =     49 cs =  10000
                [/*:m]
              • g1: 1488 (оно само! ранодомом! честно!) уников
                Код (PHP):
                1. = 1      n = 340    cc =    340 cs =    340
                2. = 2      n = 233    cc =    466 cs =    806
                3. = 3      n = 172    cc =    516 cs =   1322
                4. = 4      n = 118    cc =    472 cs =   1794
                5. = 6      n = 89     cc =    534 cs =   2328
                6. = 5      n = 86     cc =    430 cs =   2758
                7. = 7      n = 66     cc =    462 cs =   3220
                8. = 8      n = 54     cc =    432 cs =   3652
                9. = 9      n = 41     cc =    369 cs =   4021
                10. = 10     n = 34     cc =    340 cs =   4361
                11. = 12     n = 27     cc =    324 cs =   4685
                12. = 11     n = 21     cc =    231 cs =   4916
                13. = 13     n = 17     cc =    221 cs =   5137
                14. = 20     n = 17     cc =    340 cs =   5477
                15. = 15     n = 16     cc =    240 cs =   5717
                16. = 14     n = 15     cc =    210 cs =   5927
                17. = 17     n = 13     cc =    221 cs =   6148
                18. = 16     n = 12     cc =    192 cs =   6340
                19. = 25     n = 12     cc =    300 cs =   6640
                20. = 19     n = 10     cc =    190 cs =   6830
                21. = 18     n = 9      cc =    162 cs =   6992
                22. = 21     n = 8      cc =    168 cs =   7160
                23. = 33     n = 7      cc =    231 cs =   7391
                24. = 23     n = 6      cc =    138 cs =   7529
                25. = 29     n = 5      cc =    145 cs =   7674
                26. = 24     n = 5      cc =    120 cs =   7794
                27. = 22     n = 5      cc =    110 cs =   7904
                28. = 31     n = 4      cc =    124 cs =   8028
                29. = 39     n = 3      cc =    117 cs =   8145
                30. = 36     n = 3      cc =    108 cs =   8253
                31. = 28     n = 3      cc =     84 cs =   8337
                32. = 35     n = 3      cc =    105 cs =   8442
                33. = 27     n = 3      cc =     81 cs =   8523
                34. = 26     n = 2      cc =     52 cs =   8575
                35. = 43     n = 2      cc =     86 cs =   8661
                36. = 32     n = 2      cc =     64 cs =   8725
                37. = 34     n = 2      cc =     68 cs =   8793
                38. = 38     n = 2      cc =     76 cs =   8869
                39. = 37     n = 2      cc =     74 cs =   8943
                40. = 46     n = 2      cc =     92 cs =   9035
                41. = 50     n = 1      cc =     50 cs =   9085
                42. = 70     n = 1      cc =     70 cs =   9155
                43. = 63     n = 1      cc =     63 cs =   9218
                44. = 49     n = 1      cc =     49 cs =   9267
                45. = 78     n = 1      cc =     78 cs =   9345
                46. = 60     n = 1      cc =     60 cs =   9405
                47. = 48     n = 1      cc =     48 cs =   9453
                48. = 55     n = 1      cc =     55 cs =   9508
                49. = 72     n = 1      cc =     72 cs =   9580
                50. = 58     n = 1      cc =     58 cs =   9638
                51. = 47     n = 1      cc =     47 cs =   9685
                52. = 51     n = 1      cc =     51 cs =   9736
                53. = 41     n = 1      cc =     41 cs =   9777
                54. = 54     n = 1      cc =     54 cs =   9831
                55. = 30     n = 1      cc =     30 cs =   9861
                56. = 40     n = 1      cc =     40 cs =   9901
                57. = 99     n = 1      cc =     99 cs =  10000
                [/*:m]
              • g2: 6921 уник
                Код (PHP):
                1. = 1      n = 5068   cc =   5068 cs =   5068
                2. = 2      n = 1186   cc =   2372 cs =   7440
                3. = 3      n = 373    cc =   1119 cs =   8559
                4. = 4      n = 163    cc =    652 cs =   9211
                5. = 5      n = 75     cc =    375 cs =   9586
                6. = 6      n = 25     cc =    150 cs =   9736
                7. = 7      n = 15     cc =    105 cs =   9841
                8. = 8      n = 8      cc =     64 cs =   9905
                9. = 9      n = 5      cc =     45 cs =   9950
                10. = 10     n = 1      cc =     10 cs =   9960
                11. = 16     n = 1      cc =     16 cs =   9976
                12. = 24     n = 1      cc =     24 cs =  10000
                [/*:m][/list:u]

                Предпоследнее что нужно знать перед чтением результатов это что за BASE такой. Это два режима с которым тест начинает насиловать файл.
                Если перед нами INIT значит сценарий записал 3 айпишника как это предоставил автор темы.
                А строка COPY значит что мы перед тестом копируем уже готовый толстый файл с 6900+ адресов и начинаем тупо накручивать у них счетчики.
                Зачем?
                Если изначально база пустая и в нее налетают уники - она постепенно растет. И производительность полного цикла уменьшается. Поэтому результат INIT-теста в самом начале практически как скорость фотона но постепенно замедляется. А среднюю мы считаем по всему тесту. А вот COPY практически не будет изменять размер файла. Только когда десятки-сотни-тысячи будут лишний разряд накидывать. Следовательно весь тест будет более равномерным.

                После воодушевляющих результатов чужих реализаций решил COPY-тест проводить только со своими алгоритмами. Я честно запускал их но при результатах допустим в 1416 секунд на один тест - я бы всю эту херню, которую никто не прочитает, закончил бы только к апрелю. Я уж молчу про гигабайты нотисов mahmuzar-а - и так понятно что алгоритм не работает и не вижу смысла его дальше насиловать.

                Ну и последнее - код класса который мы расширияем всей толпой:
                Код (PHP):
                1. abstract class ru_php_forum_52305 {
                2.     const BASE = '/var/tmp/ramdrive/base.txt';
                3.     const FILE = '/var/tmp/ramdrive/ru_php_forum_52305.txt';
                4.     const DIR = '/var/tmp/ramdrive';
                5.     
                6.     public static function init () {
                7.         file_put_contents(static::FILE,
                8.                 '11.11.11.11 = 3' . PHP_EOL .
                9.                 '44.44.44.44 = 1' . PHP_EOL .
                10.                 '88.88.88.88 = 1'
                11.             );
                12.     }
                13.     
                14.     abstract public static function inc ($ip);
                15.     
                16.     public static function test () {
                17.         if (CFG::$alloc) {
                18.             static::init();
                19.         } else {
                20.             copy(static::BASE, static::FILE);
                21.         }
                22.         
                23.         global $ips;
                24.         
                25.         $begin = microtime(true);
                26.         for($i = 0; $i < CFG::$rounds; $i++) {
                27.             foreach ($ips as $ip) {
                28.                 static::inc($ip);
                29.                 
                30.             }
                31.         }
                32.         
                33.         $ela = microtime(true) - $begin;
                34.         
                35.         echo sprintf("%-60s : %0.6f %0.6f %8d\n", get_called_class(), $ela, ($ela / CFG::$idone), memory_get_peak_usage()); flush();
                36.         
                37.         copy(static::FILE, static::DIR.'/'.date('Y-md-His.').(++CFG::$pc).'.'.get_called_class());
                38.     }
                39. }
                После последнего: bench.php
                Код (PHP):
                1. class CFG {
                2.     public static
                3.             $pc = 100,
                4.             $rounds = 1,
                5.             $idone = 0,
                6.             $alloc = true
                7.         ;
                8. }
                9.  
                10. require_once 'ru_php_forum_52305.php';
                11.  
                12. $tests = array(
                13.     'ru_php_forum_52305_INETCHIK_01',
                14.     'ru_php_forum_52305_strstr_01',
                15.     'ru_php_forum_52305_preg_replace_callback_01_01',
                16.     'ru_php_forum_52305_preg_replace_callback_02_01',
                17.     'ru_php_forum_52305_preg_replace_callback_03_01',
                18.     'ru_php_forum_52305_preg_replace_callback_03_02',
                19.     'ru_php_forum_52305_preg_replace_callback_03_02_01',
                20.     'ru_php_forum_52305_mahmuzar_01',
                21.     'ru_php_forum_52305_mahmuzar_02',
                22.     'ru_php_forum_52305_mahmuzar_03',
                23.     'ru_php_forum_52305_denis01_02',
                24.     'ru_php_forum_52305_prc_03_01_hex_01',
                25.     'ru_php_forum_52305_prc_03_02_hex_01',
                26.     'ru_php_forum_52305_prc_03_02_01_hex_01',
                27. );
                28.  
                29. $datas = array(
                30.     '0', '1', '2', 'g0', 'g1', 'g2',
                31. );
                32.  
                33. foreach ($tests as $test) {
                34.     require_once $test . '.php';
                35. }
                36.  
                37. // INIT-test
                38. foreach ($datas as $d) {
                39.     require_once './ips/data_'.$d.'.php';
                40.     
                41.     $ips_cnt = count($ips);
                42.     $ips_unq = count(array_unique($ips));
                43.     CFG::$idone = $ips_cnt * CFG::$rounds;
                44.     
                45.     echo sprintf("\n"
                46.             . "BANK   : %8s\n"
                47.             . "CNT    : %8d\n"
                48.             . "UNQ    : %8d\n"
                49.             . "ROUNDS : %8d\n"
                50.             . "BASE   : %8s\n"
                51.             
                52.             , $d, $ips_cnt, $ips_unq, CFG::$rounds, (CFG::$alloc 'INIT' : 'COPY')
                53.         );
                54.     
                55.     foreach ($tests as $test) {
                56.         $test::test();
                57.     }
                58. }
                59.  
                60. // COPY-test
                61. $tests2 = array(
                62.     'ru_php_forum_52305_preg_replace_callback_03_01',
                63.     'ru_php_forum_52305_preg_replace_callback_03_02',
                64.     'ru_php_forum_52305_preg_replace_callback_03_02_01',
                65.     'ru_php_forum_52305_denis01_02',
                66.     'ru_php_forum_52305_prc_03_01_hex_01',
                67.     'ru_php_forum_52305_prc_03_02_hex_01',
                68.     'ru_php_forum_52305_prc_03_02_01_hex_01',
                69. );
                70.  
                71. CFG::$alloc = false;
                72.  
                73. foreach ($datas as $d) {
                74.     require_once './ips/data_'.$d.'.php';
                75.     
                76.     $ips_cnt = count($ips);
                77.     $ips_unq = count(array_unique($ips));
                78.     CFG::$idone = $ips_cnt * CFG::$rounds;
                79.     
                80.     echo sprintf("\n"
                81.             . "BANK   : %8s\n"
                82.             . "CNT    : %8d\n"
                83.             . "UNQ    : %8d\n"
                84.             . "ROUNDS : %8d\n"
                85.             . "BASE   : %8s\n"
                86.             
                87.             , $d, $ips_cnt, $ips_unq, CFG::$rounds, (CFG::$alloc 'INIT' : 'COPY')
                88.         );
                89.     
                90.     foreach($tests2 as $test) {
                91.         $test::test();
                92.     }
                93. }
                И после-после последнего:
                Код (Text):
                1. Core2Quad Q6600 2.4GHz / 8Gb PC2-6400
                2.  
                3. Linux *** 3.13.0-46-generic #79-Ubuntu SMP Tue Mar 10 20:06:50 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
                4.  
                5. PHP 5.5.9-1ubuntu4.6 (cli) (built: Feb 13 2015 19:17:11)
                6. Copyright (c) 1997-2014 The PHP Group
                7. Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
                8.     with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies

                Просто цифры...
                Код (Text):
                1. BANK   :        0
                2. CNT    :        9
                3. UNQ    :        3
                4. ROUNDS :    10000
                5. BASE   :     INIT
                6. ru_php_forum_52305_INETCHIK_01                               : 3.870133 0.000043   661592   fail-1
                7. ru_php_forum_52305_INETCHIK_02                               : 4.122872 0.000046   661592   fail-1
                8. ru_php_forum_52305_strstr_01                                 : 3.154187 0.000035   663256   softfail
                9. ru_php_forum_52305_preg_replace_callback_01_01               : 3.475129 0.000039   663256   fail-1
                10. ru_php_forum_52305_preg_replace_callback_02_01               : 3.679745 0.000041   663856   ok
                11. ru_php_forum_52305_preg_replace_callback_03_01               : 6.453295 0.000072   665680   ok
                12. ru_php_forum_52305_preg_replace_callback_03_02               : 6.373738 0.000071   666208   ok
                13. ru_php_forum_52305_preg_replace_callback_03_02_01            : 6.217962 0.000069   666208   ok
                14. ru_php_forum_52305_mahmuzar_01                               : 6.193531 0.000069   666208   ok, NOTICE
                15. ru_php_forum_52305_mahmuzar_02                               : 5.141390 0.000057   666208   ok, NOTICE
                16. ru_php_forum_52305_mahmuzar_03                               : 3.445506 0.000038   666208   ok, NOTICE
                17. ru_php_forum_52305_denis01_02                                : 2.954315 0.000033   667184   ok
                18. ru_php_forum_52305_prc_03_01_hex_01                          : 4.538740 0.000050   670584   ok known
                19. ru_php_forum_52305_prc_03_02_hex_01                          : 4.504284 0.000050   670584   ok known
                20. ru_php_forum_52305_prc_03_02_01_hex_01                       : 4.283247 0.000048   670584   ok known
                90000 вызовов но только три адреса.
                Размер файла в принципе маленький и меняется только при смене разрядности счетчиков.
                mahmuzar попал в эталонный результат.
                INETCHIK тоже, если не считать что изначальные показатели 3-1-1 куда-то исчезли - остальное посчитано правильно. Конечно это провал. Нельзя терять данные. Но он у нас тут ради спортивного интереса.
                Моя 01_01 удваивает записи и потом корректно накручивает счетчики. Дважды. Провал.
                Хекс в силу отсутствия правильного метода инициализации считает только свои записи. Справился, но с пометкой.
                не-denis01 тоже молодец.

                Код (Text):
                1. BANK   :        1
                2. CNT    :      117
                3. UNQ    :        5
                4. ROUNDS :     1000
                5. BASE   :     INIT
                6. ru_php_forum_52305_INETCHIK_01                               : 5.378934 0.000046   686184   fail-2
                7. ru_php_forum_52305_INETCHIK_02                               : 5.759252 0.000049   686184   fail-2
                8. ru_php_forum_52305_strstr_01                                 : 4.228255 0.000036   686352   softfail
                9. ru_php_forum_52305_preg_replace_callback_01_01               : 4.500838 0.000038   686352   fail-2 DQF
                10. ru_php_forum_52305_preg_replace_callback_02_01               : 4.332482 0.000037   686352   ok
                11. ru_php_forum_52305_preg_replace_callback_03_01               : 8.515412 0.000073   687416   ok
                12. ru_php_forum_52305_preg_replace_callback_03_02               : 5.606118 0.000048   687568   ok
                13. ru_php_forum_52305_preg_replace_callback_03_02_01            : 5.449189 0.000047   687568   ok
                14. ru_php_forum_52305_mahmuzar_01                               : 8.795043 0.000075   687568   fail DQF
                15. ru_php_forum_52305_mahmuzar_02                               : 10.208894 0.000087   687568  fail DQF
                16. ru_php_forum_52305_mahmuzar_03                               : 6.443252 0.000055   687568   fail DQF
                17. ru_php_forum_52305_denis01_02                                : 4.170596 0.000036   687568   ok
                18. ru_php_forum_52305_prc_03_01_hex_01                          : 5.897252 0.000050   688352   ok known
                19. ru_php_forum_52305_prc_03_02_hex_01                          : 5.907418 0.000050   688352   ok known
                20. ru_php_forum_52305_prc_03_02_01_hex_01                       : 5.695299 0.000049   688352   ok known
                117000 на пять адресов.
                Комментарий про размер файла.
                INETCHIK все посчитал. Но опять кроме 3-1-1 изначальных. Спорт.
                01_01 опять всё два раза. Дисквалифицируем. 01_01 опять всё два раза. Дисквалифицируем.
                Остальные реализации в норме.
                Кроме mahmuzar. Его код почему-то знает только про 3 айпишника и поэтому полностью игнорирует оставшиеся два. Собственно дальше будет ровно та же картина - полная потеря данных для айпишников которых не было в изначальном списке. Тоже дисквалифицируем.

                Код (Text):
                1. BANK   :        2
                2. CNT    :      123
                3. UNQ    :       10
                4. ROUNDS :     1000
                5. BASE   :     INIT
                6. ru_php_forum_52305_INETCHIK_01                               : 6.721457 0.000055   699208   fail-3 DQF
                7. ru_php_forum_52305_INETCHIK_02                               : 7.017045 0.000057   699208   fail-3 DQF
                8. ru_php_forum_52305_strstr_01                                 : 5.045653 0.000041   699208   softfail
                9. ru_php_forum_52305_preg_replace_callback_01_01               : 4.887270 0.000040   699208   DQF
                10. ru_php_forum_52305_preg_replace_callback_02_01               : 4.565532 0.000037   699208   ok
                11. ru_php_forum_52305_preg_replace_callback_03_01               : 6.196004 0.000050   699208   ok
                12. ru_php_forum_52305_preg_replace_callback_03_02               : 6.244183 0.000051   699208   ok
                13. ru_php_forum_52305_preg_replace_callback_03_02_01            : 6.092158 0.000050   699208   ok
                14. ru_php_forum_52305_mahmuzar_01                               : 6.482335 0.000053   699208   DQF
                15. ru_php_forum_52305_mahmuzar_02                               : 7.397730 0.000060   699208   DQF
                16. ru_php_forum_52305_mahmuzar_03                               : 4.793424 0.000039   699208   DQF
                17. ru_php_forum_52305_denis01_02                                : 4.917484 0.000040   699208   ok
                18. ru_php_forum_52305_prc_03_01_hex_01                          : 6.361200 0.000052   699208   ok known
                19. ru_php_forum_52305_prc_03_02_hex_01                          : 6.313532 0.000051   699208   ok known
                20. ru_php_forum_52305_prc_03_02_01_hex_01                       : 6.146749 0.000050   699208   ok known
                Ранее было объявлено про прикол. Вот он. 123000 вызовов на 10 адресов.
                Было у меня 5 адресов. Я убрал по последней цифре у каждого из них. И получил еще 5 адресов. Например 11.11.11.11 и 11.11.11.1. К сожалению только я додумался искать в строке не только айпишник но и знак равенства - мои алгоритмы не заливают стату адреса 11.11.11.1 в стату адресов 11.11.11.11, 11.11.11.12, 11.11.11.13 и так далее. Поэтому с этого этапа реализация INETCHIK-а окончательно участвует ради строчек в бенчмарке.

                Далее более интересные тесты - с большими и более произвольными списками.
                Код (Text):
                1. BANK   :       g0
                2. CNT    :    10000
                3. UNQ    :      217
                4. ROUNDS :        5
                5. BASE   :     INIT
                6. ru_php_forum_52305_INETCHIK_01                               : 13.857843 0.000277  3441584   DQF
                7. ru_php_forum_52305_INETCHIK_02                               : 22.517048 0.000450  3441584   DQF
                8. ru_php_forum_52305_strstr_01                                 : 9.038891 0.000181  3441584
                9. ru_php_forum_52305_preg_replace_callback_01_01               : 3.477516 0.000070  3441584   DQF
                10. ru_php_forum_52305_preg_replace_callback_02_01               : 3.366447 0.000067  3441584
                11. ru_php_forum_52305_preg_replace_callback_03_01               : 3.998600 0.000080  3441584
                12. ru_php_forum_52305_preg_replace_callback_03_02               : 4.057613 0.000081  3441584
                13. ru_php_forum_52305_preg_replace_callback_03_02_01            : 4.130979 0.000083  3441584
                14. ru_php_forum_52305_mahmuzar_01                               : 2.557624 0.000051  3441584   DQF
                15. ru_php_forum_52305_mahmuzar_02                               : 2.883417 0.000058  3441584   DQF
                16. ru_php_forum_52305_mahmuzar_03                               : 1.880305 0.000038  3441584   DQF
                17. ru_php_forum_52305_denis01_02                                : 9.633680 0.000193  3441584
                18. ru_php_forum_52305_prc_03_01_hex_01                          : 4.697958 0.000094  3441584
                19. ru_php_forum_52305_prc_03_02_hex_01                          : 6.077962 0.000122  3441584
                20. ru_php_forum_52305_prc_03_02_01_hex_01                       : 6.333923 0.000127  3441584
                21.  
                22. BANK   :       g1
                23. CNT    :    10000
                24. UNQ    :     1488
                25. ROUNDS :        5
                26. BASE   :     INIT
                27. ru_php_forum_52305_INETCHIK_01                               : 87.801011 0.001756  4919664   DQF
                28. ru_php_forum_52305_INETCHIK_02                               : 132.797057 0.002656  4919664   DQF
                29. ru_php_forum_52305_strstr_01                                 : 53.846996 0.001077  4919664
                30. ru_php_forum_52305_preg_replace_callback_01_01               : 13.169129 0.000263  4919664   DQF
                31. ru_php_forum_52305_preg_replace_callback_02_01               : 12.383472 0.000248  4919664
                32. ru_php_forum_52305_preg_replace_callback_03_01               : 13.058233 0.000261  4919664
                33. ru_php_forum_52305_preg_replace_callback_03_02               : 13.490592 0.000270  4919664
                34. ru_php_forum_52305_preg_replace_callback_03_02_01            : 14.267716 0.000285  4919664
                35. ru_php_forum_52305_mahmuzar_01                               : 2.552806 0.000051  4919664   DQF
                36. ru_php_forum_52305_mahmuzar_02                               : 2.938797 0.000059  4919664   DQF
                37. ru_php_forum_52305_mahmuzar_03                               : 1.875671 0.000038  4919664   DQF
                38. ru_php_forum_52305_denis01_02                                : 67.447713 0.001349  4919664
                39. ru_php_forum_52305_prc_03_01_hex_01                          : 18.196488 0.000364  4919664
                40. ru_php_forum_52305_prc_03_02_hex_01                          : 16.626948 0.000333  4919664
                41. ru_php_forum_52305_prc_03_02_01_hex_01                       : 14.505341 0.000290  4919664
                42.  
                43. BANK   :       g2
                44. CNT    :    10000
                45. UNQ    :     6921
                46. ROUNDS :        5
                47. BASE   :     INIT
                48. ru_php_forum_52305_INETCHIK_01                               : 395.248355 0.007905  4925080   DQF
                49. ru_php_forum_52305_INETCHIK_02                               : 826.754699 0.016535  4925080   DQF
                50. ru_php_forum_52305_strstr_01                                 : 380.741465 0.007615  4925080
                51. ru_php_forum_52305_preg_replace_callback_01_01               : 71.081354 0.001422  4925080   DQF
                52. ru_php_forum_52305_preg_replace_callback_02_01               : 69.636063 0.001393  4925080
                53. ru_php_forum_52305_preg_replace_callback_03_01               : 71.205819 0.001424  4925080
                54. ru_php_forum_52305_preg_replace_callback_03_02               : 73.955237 0.001479  4925080
                55. ru_php_forum_52305_preg_replace_callback_03_02_01            : 75.101566 0.001502  4925080
                56. ru_php_forum_52305_mahmuzar_01                               : 3.623693 0.000072  4925080   DQF
                57. ru_php_forum_52305_mahmuzar_02                               : 3.243513 0.000065  4925080   DQF
                58. ru_php_forum_52305_mahmuzar_03                               : 1.853292 0.000037  4925080   DQF
                59. ru_php_forum_52305_denis01_02                                : 519.210724 0.010384  4925080
                60. ru_php_forum_52305_prc_03_01_hex_01                          : 44.325944 0.000887  4925080
                61. ru_php_forum_52305_prc_03_02_hex_01                          : 47.474540 0.000949  4925080
                62. ru_php_forum_52305_prc_03_02_01_hex_01                       : 52.828695 0.001057  4925080
                По 50000 вызовов для 217-1488-6921 уника соответственно. Не смотрите на суперские результаты mahmuzar - его код работает только с айпишниками которые уже вписаны в файл и ВООБЩЕ ВСЕ новые тупо пролетают мимо.
                А вот регулярки начинают огрызаться на построчную итерацию.
                Напомню 02_01 быстра отсутствием необходимости блокировать файл.
                Обязательные пробелы надувают файл а это значит надо больше текста читать из файла, прогонять регуляркой, записывать в файл. Пара байт (по пробелу вокруг знака равенства) на 7000 строк это 14000 байт лишнего текста.
                Реализации 03_02_01 вполне логично тормозят - им приходится лишний раз искать вхождение строки перед возможным запуском регулярки. И чем больше записей в файле тем дольше идет поиск.

                Осталось только показать цифры для изначально больших файлов.
                Код (Text):
                1. BANK   :        0
                2. CNT    :    10000
                3. UNQ    :     6921
                4. ROUNDS :        5
                5. BASE   :     COPY
                6. ru_php_forum_52305_INETCHIK_01                               : 413.891201 0.008278  4925080   DQF
                7. ru_php_forum_52305_strstr_01                                 : 437.573011 0.008751  5033496
                8. ru_php_forum_52305_preg_replace_callback_01_01               : 70.348374 0.001407  5033496   DQF
                9. ru_php_forum_52305_preg_replace_callback_02_01               : 54.230805 0.001085  5033496
                10. ru_php_forum_52305_preg_replace_callback_03_01               : 76.500927 0.001530  5033496
                11. ru_php_forum_52305_preg_replace_callback_03_02               : 79.567291 0.001591  5033496
                12. ru_php_forum_52305_preg_replace_callback_03_02_01            : 79.572252 0.001591  5033496
                "Ой всё!" - сказал мне сервак, - "Хватит тянуть кота за мудя! Выкидывай говнокодеров!". Да, я разговариваю с железом. Вернее оно мне говорит а я слышу.
                Собственно что тут произошло? Ну ладно 413-437 это мне не сложно было подождать. Я просто тормознул тест на 1416-ой секунде работы алгоритма mahmuzar_01 - начали заканчиваться 10 гигабайт места на диске. И я даже не знаю почему...
                Вот почему как уже было сказано выше - я оставил для COPY-теста только работающий код.

                Небольшое увеличение по всем фронтам в тестах 0-1-2 связано с тем что я занял сервак другой обработкой не отвлекаясь от этой. Извините, приоритеты.
                Код (Text):
                1. BANK   :        0
                2. CNT    :        9
                3. UNQ    :        3
                4. ROUNDS :    10000
                5. BASE   :     COPY
                6. ru_php_forum_52305_preg_replace_callback_03_01               : 134.456337 0.001494   944688
                7. ru_php_forum_52305_preg_replace_callback_03_02               : 99.816503 0.001109   945344
                8. ru_php_forum_52305_preg_replace_callback_03_02_01            : 92.148603 0.001024  1044432
                9. ru_php_forum_52305_denis01_02                                : 341.410875 0.003793  1838440
                10. ru_php_forum_52305_prc_03_01_hex_01                          : 137.035402 0.001523  1838440
                11. ru_php_forum_52305_prc_03_02_hex_01                          : 94.545498 0.001051  1838440
                12. ru_php_forum_52305_prc_03_02_01_hex_01                       : 123.672071 0.001374  1838440
                13.  
                14. BANK   :        1
                15. CNT    :      117
                16. UNQ    :        5
                17. ROUNDS :     1000
                18. BASE   :     COPY
                19. ru_php_forum_52305_preg_replace_callback_03_01               : 182.791637 0.001562  1838440
                20. ru_php_forum_52305_preg_replace_callback_03_02               : 132.566221 0.001133  1838440
                21. ru_php_forum_52305_preg_replace_callback_03_02_01            : 200.064098 0.001710  1838440
                22. ru_php_forum_52305_denis01_02                                : 726.709365 0.006211  1927816
                23. ru_php_forum_52305_prc_03_01_hex_01                          : 169.096030 0.001445  1927816
                24. ru_php_forum_52305_prc_03_02_hex_01                          : 168.650735 0.001441  1927816
                25. ru_php_forum_52305_prc_03_02_01_hex_01                       : 211.011557 0.001804  1927816
                26.  
                27. BANK   :        2
                28. CNT    :      123
                29. UNQ    :       10
                30. ROUNDS :     1000
                31. BASE   :     COPY
                32. ru_php_forum_52305_preg_replace_callback_03_01               : 184.295725 0.001498  1927816
                33. ru_php_forum_52305_preg_replace_callback_03_02               : 185.558124 0.001509  1927816
                34. ru_php_forum_52305_preg_replace_callback_03_02_01            : 195.600845 0.001590  1927816
                35. ru_php_forum_52305_denis01_02                                : 914.613231 0.007436  1999600
                36. ru_php_forum_52305_prc_03_01_hex_01                          : 182.474893 0.001484  1999600
                37. ru_php_forum_52305_prc_03_02_hex_01                          : 172.108521 0.001399  1999600
                38. ru_php_forum_52305_prc_03_02_01_hex_01                       : 210.593596 0.001712  1999600
                39.  
                40. BANK   :       g0
                41. CNT    :    10000
                42. UNQ    :      217
                43. ROUNDS :        5
                44. BASE   :     COPY
                45. ru_php_forum_52305_preg_replace_callback_03_01               : 84.114852 0.001682  3388424
                46. ru_php_forum_52305_preg_replace_callback_03_02               : 84.218770 0.001684  3388424
                47. ru_php_forum_52305_preg_replace_callback_03_02_01            : 90.425789 0.001809  3388424
                48. ru_php_forum_52305_denis01_02                                : 350.144183 0.007003  3487864
                49. ru_php_forum_52305_prc_03_01_hex_01                          : 82.383787 0.001648  3487864
                50. ru_php_forum_52305_prc_03_02_hex_01                          : 83.376514 0.001668  3487864
                51. ru_php_forum_52305_prc_03_02_01_hex_01                       : 93.390521 0.001868  3487864
                52.  
                53. BANK   :       g1
                54. CNT    :    10000
                55. UNQ    :     1488
                56. ROUNDS :        5
                57. BASE   :     COPY
                58. ru_php_forum_52305_preg_replace_callback_03_01               : 90.086613 0.001802  4857136
                59. ru_php_forum_52305_preg_replace_callback_03_02               : 73.125031 0.001463  4857136
                60. ru_php_forum_52305_preg_replace_callback_03_02_01            : 67.266207 0.001345  4857136
                61. ru_php_forum_52305_denis01_02                                : 424.768950 0.008495  4857136
                62. ru_php_forum_52305_prc_03_01_hex_01                          : 91.502942 0.001830  4857136
                63. ru_php_forum_52305_prc_03_02_hex_01                          : 92.499745 0.001850  4857136
                64. ru_php_forum_52305_prc_03_02_01_hex_01                       : 111.306154 0.002226  4857136
                65.  
                66. BANK   :       g2
                67. CNT    :    10000
                68. UNQ    :     6921
                69. ROUNDS :        5
                70. BASE   :     COPY
                71. ru_php_forum_52305_preg_replace_callback_03_01               : 77.004190 0.001540  4886552
                72. ru_php_forum_52305_preg_replace_callback_03_02               : 81.621627 0.001632  4886552
                73. ru_php_forum_52305_preg_replace_callback_03_02_01            : 89.057038 0.001781  4886552
                74. ru_php_forum_52305_denis01_02                                : 507.786773 0.010156  4886552
                75. ru_php_forum_52305_prc_03_01_hex_01                          : 75.289561 0.001506  4886552
                76. ru_php_forum_52305_prc_03_02_hex_01                          : 78.195882 0.001564  4886552
                77. ru_php_forum_52305_prc_03_02_01_hex_01                       : 93.307614 0.001866  4886552

                Что я тут вижу?
                • Регулярки хорошо справились с задачей.[/*:m]
                • Пробелы замедляют работу ибо размер данных увеличивается и на всех этапах - чтение файла, выполнение регулярки, запись в файл.[/*:m]
                • Это всего несколько секунд на несколько десятков тысяч вызовов. Обычная загрузка центрального процессора другими задачами куда сильнее тормозит процессы.[/*:m]
                • А с пробелами кстати файлы красивее.[/*:m]
                • Идея упаковки в хекс на мой взгляд экономит скорее дисковое пространство. По крайней мере по таким небольшим дельтам времён (впрочем как в одну так и в другую сторону) - я бы не бросился делать файл "базы" менее читаемым.[/*:m]
                • Поиск подстроки насасывает.[/*:m]
                • Построчная итерация файла с поиском подстроки см предыдущий пункт.[/*:m]
                • В результатах есть два кода, которые не имеют описания:
                  • ru_php_forum_52305_INETCHIK_02: автор предложил вторую реализацию алгоритма, но цифры подсказывают что лучше б он так не делал.
                    Код (PHP):
                    1. class ru_php_forum_52305_INETCHIK_02 extends ru_php_forum_52305 {
                    2.     public static function inc ($ip) {
                    3.         $ar=file(static::FILE);
                    4.  
                    5.         if(strpos(file_get_contents(static::FILE), $ip)===false){
                    6.             $data="$ip=1" . PHP_EOL; 
                    7.         }
                    8.         else{
                    9.             foreach ($ar as $k=>$v) {
                    10.                 if(strpos($v, $ip) !==false) {
                    11.                     $sub=trim(substr($v, strlen($ip)+1));
                    12.                     $ar[$k]=$ip.'='.($sub+1). PHP_EOL;
                    13.                     $data=$ar[$k];
                    14.                     break;
                    15.                 }
                    16.             }
                    17.         }
                    18.  
                    19.         array_unshift($ar, $data);
                    20.         file_put_contents(static::FILE, array_unique($ar));
                    21.     }
                    22. }
                    [/*:m]
                  • ru_php_forum_52305_strstr_01: конечно помимо регулярок и того кода, который-не-писал-denis01, я пытался познать алгоритм построчной итерации файла и наклепал вот эту хрень:
                    Код (PHP):
                    1. class ru_php_forum_52305_strstr_01 extends ru_php_forum_52305 {
                    2.     public static function inc ($ip) {
                    3.         $f = file(static::FILE, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES);
                    4.         $done = false;
                    5.  
                    6.         $IP = $ip . '=';
                    7.  
                    8.         foreach ($f as &$s) {
                    9.             if (false !== strstr($s, $IP)) {
                    10.                 $s = $ip . '=' . 
                    11.                         (1 + array_slice(
                    12.                                 explode('=', $s)
                    13.                             , 1, 1)[0]
                    14.                     );
                    15.                 $done = true;
                    16.             }
                    17.         }
                    18.  
                    19.         if (!$done) {
                    20.             $f[] = $ip . '=1';
                    21.         }
                    22.  
                    23.         file_put_contents(static::FILE, implode(PHP_EOL, $f));
                    24.     }
                    25.  
                    26. }
                    В тестах помечена как softfail потому что она расслаивает данные, если вдруг в строке пробел слева от знака равенства. Данные не потеряны, но требуют обработки. Фу-фу-фу. Впрочем, у других данные вообще теряются. И в среднем теряют ещё и дольше чем этот алгоритм.[/*:m][/list:u][/*:m]
                  • Для нескольких тысяч строк счетчиков - вполне хватит. Для бОльшего... Наверное лучше пробовать разбивать "базу" на несколько файлов. Но тогда почему бы вообще сразу не перейти на более подходящий инструмент?[/*:m][/list:u]

                    Спасибо за внимание.
                    ЗЫ. Вообще мой никнейм 11 лет и 2 дня назад задумывался как Газаль, но за последние несколько месяцев меня постепенно приучили к жесткому Л на конце.
                    Теперь мне интересно сколько людей это прочитает хотя бы наполовину.
     
  2. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Безумие :)
    Молоток.
     
  3. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    Побольше бы тут подобных тестов, и соревнований.
    Браво. Прочитал усе, до последней строчки. Надо работать надо собой)
    По поводу кода:
    А что требовалось? разве не это?) нету в базе, значит пропускаем, и записываем прочтенную строку в файл обратно, не?.
    Или я что-то не понимаю.
     
  4. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    Дядь, давай поразмышляем логически))) Если твой код медленно НЕ добавляет то что с ним будет если он станет добавлять? =)
     
  5. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    что-то я не пойму.. Если примеры работают с одним и тем же файлом, то почему когда мой не добавляет, твой должен добавлять изменения в файл?))
     
  6. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    все мои алгоритмы добавляют. я для себя задачу понял как "есть - плюс, нет - добавить". и ты наверное понимаешь что если задача будет "плюс если есть" то я напишу алгоритм вида
    Код (PHP):
    1. $done = false;
    2. $f = preg_replace_callback('~^('.preg_quote($ip).')\s*=\s*(\d+)$~m', function($m) use (&$done) {
    3.     $done = true;
    4.     return $m[1] . '=' . ++$m[2];
    5. }, file_get_contents(static::FILE));
    6.  
    7. if ($done) {
    8.     file_put_contents(static::FILE, $f);
    9. }
    и не буду вообще трогать файл на запись если его содержимое не меняется.
     
  7. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.

    сам удивился, увидев, что результат не меняется. А у вас меняется. Получается мой код работает иначе.
    По условию, добавить не говорится, поэтому пропускал.
     
  8. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    мне вариант с регулярками нравится больше. ибо он быстрый и гибкий.
    но в качестве доп. варианта, предложу такой(он жестко привязан к структуре файла, подразумевая что там ДО и ПОСЛЕ символа '=' ЕСТЬ пробелы)
    Код (PHP):
    1. $ip = '88.88.88.88';
    2. $file = 'ip.txt'; // line format: IPV4 = \d+
    3. //
    4. $s = file_get_contents($file);
    5. if ( ($p = strpos($s, $ip)) !==false ) {
    6.   $p_cnt = $p +strlen($ip) +3;
    7.   $p_nl = strpos($s, PHP_EOL, $p_cnt);
    8.   $cnt = intval( $p_nl!==false ? substr($s, $p_cnt, $p_nl-$p_cnt) : substr($s, $p_cnt) );
    9.   file_put_contents($file, substr_replace($s, $cnt+1, $p_cnt, strlen($cnt)), LOCK_EX );
    10. } else { // new ip
    11.   file_put_contents($file, $ip.' = 1'.PHP_EOL, LOCK_EX | FILE_APPEND );
    12. } 
     
  9. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    кстати. или я чегото не понимаю. или у тебя тут большой глюк.
    при добавлении нового адреса, он его добавляет в конец файла.
    если далее мы меняем адрес на предыдущий(например), но вместо того чтоб заменить его в строке, добавляет его еще раз. в конце файла.
    это неприемлемо.

    если изначально файл пустой, то при вызове добавляется пустая строка, и потом только - адрес и счетчик...
    зачем?
    Добавлено спустя 30 минут 3 секунды:
    Ganzal,
    кароч, ты заюзал модификатор m - похоже, плохо понимая принцип его работы.
    что тут сказать? ))) читай мануал) и исправляй свой код.
     
  10. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    согласен, непреемлемо. но ни один мой листинг так не делает. ты про какой? собственно я ниже покажу тест а ты пальцем ткни.

    ну это я может быть перенервничал при добавлении константы. как ты понимаешь это на работу вообще никак не влияет. тест ниже.

    я всю свою сознательную жизнь считаю что модификатор m включает режим поиска по всему значению переменной и тогда ^ и $ ищут соответственно начала строк и их окончания. сделал ~^IP = (\d+)$~ - перфоманс просел во много раз. сделал ~IP = (\d+)~ - перфоманс незначительно но всё же просел. честно может я чего-то недопонимаю в регулярках. ткни пальцев и на примерах расскажи почему тут нельзя использовать модификатор m

    листинг #1 - проседание перфоманса ~^IP = (\d+)$~ то есть без m-модификатора.
    Код (Text):
    1. ru_php_forum_52305_preg_replace_callback_02_02               : 4.514682 0.000050   577488
    2. ru_php_forum_52305_preg_replace_callback_03_02               : 6.192382 0.000069   578512
    3. ru_php_forum_52305_preg_replace_callback_04_fix_flock        : 118.919845 0.001321  4883376
    4. ru_php_forum_52305_preg_replace_callback_04_fix              : 129.900431 0.001443  4883376
    листинг 2 - в моей 04 регулярка заменена на ~IP = (\d+)~ то есть убран не только модификатор m но и указатели на начало-конец строки. заодно проверяем код runcore. кстати портировал я его так:
    Код (PHP):
    1. <?php
    2. class ru_php_forum_52305_runcore_01 extends ru_php_forum_52305 {
    3.     public static function inc ($ip) {
    4.         $s = file_get_contents(static::FILE);
    5.         if ( ($p = strpos($s, $ip)) !== false ) {
    6.           $p_cnt = $p +strlen($ip) +3;
    7.           $p_nl = strpos($s, PHP_EOL, $p_cnt);
    8.           $cnt = intval( $p_nl!==false ? substr($s, $p_cnt, $p_nl-$p_cnt) : substr($s, $p_cnt) );
    9.           file_put_contents(static::FILE, substr_replace($s, $cnt+1, $p_cnt, strlen($cnt)), LOCK_EX );
    10.         } else { // new ip
    11.           file_put_contents(static::FILE, $ip.' = 1'.PHP_EOL, LOCK_EX | FILE_APPEND );
    12.         } 
    13.     }
    14. }
    результаты:
    Код (Text):
    1. BANK   :        0
    2. CNT    :        9
    3. UNQ    :        3
    4. ROUNDS :    10000
    5. BASE   :     INIT
    6. ru_php_forum_52305_strstr_01                                 : 3.171433 0.000035   583528
    7. ru_php_forum_52305_preg_replace_callback_02_02               : 3.189578 0.000035   584656
    8. ru_php_forum_52305_preg_replace_callback_03_02               : 4.205186 0.000047   585856
    9. ru_php_forum_52305_preg_replace_callback_04_fix_flock        : 4.127870 0.000046   586496
    10. ru_php_forum_52305_preg_replace_callback_04_fix              : 3.081571 0.000034   586496
    11. ru_php_forum_52305_denis01_02                                : 2.948388 0.000033   586496
    12. ru_php_forum_52305_runcore_01                                : 2.624432 0.000029   586496
    13.  
    14. BANK   :        1
    15. CNT    :      117
    16. UNQ    :        5
    17. ROUNDS :     1000
    18. BASE   :     INIT
    19. ru_php_forum_52305_strstr_01                                 : 4.242355 0.000036   604192
    20. ru_php_forum_52305_preg_replace_callback_02_02               : 4.153071 0.000035   604464
    21. ru_php_forum_52305_preg_replace_callback_03_02               : 5.510890 0.000047   605128
    22. ru_php_forum_52305_preg_replace_callback_04_fix_flock        : 5.423911 0.000046   605128
    23. ru_php_forum_52305_preg_replace_callback_04_fix              : 4.032159 0.000034   605128
    24. ru_php_forum_52305_denis01_02                                : 4.124032 0.000035   605128
    25. ru_php_forum_52305_runcore_01                                : 3.404929 0.000029   605128
    26.  
    27. BANK   :        2
    28. CNT    :      123
    29. UNQ    :       10
    30. ROUNDS :     1000
    31. BASE   :     INIT
    32. ru_php_forum_52305_strstr_01                                 : 5.006127 0.000041   616776
    33. ru_php_forum_52305_preg_replace_callback_02_02               : 4.502291 0.000037   616776
    34. ru_php_forum_52305_preg_replace_callback_03_02               : 6.035958 0.000049   616776
    35. ru_php_forum_52305_preg_replace_callback_04_fix_flock        : 5.948806 0.000048   616776
    36. ru_php_forum_52305_preg_replace_callback_04_fix              : 4.498139 0.000037   616776
    37. ru_php_forum_52305_denis01_02                                : 7.007652 0.000057   616776
    38. ru_php_forum_52305_runcore_01                                : 5.054683 0.000041   616776
    39.  
    40. BANK   :       g0
    41. CNT    :    10000
    42. UNQ    :      217
    43. ROUNDS :        5
    44. BASE   :     INIT
    45. ru_php_forum_52305_strstr_01                                 : 13.191535 0.000264  3360280
    46. ru_php_forum_52305_preg_replace_callback_02_02               : 5.127474 0.000103  3360280
    47. ru_php_forum_52305_preg_replace_callback_03_02               : 6.081731 0.000122  3360280
    48. ru_php_forum_52305_preg_replace_callback_04_fix_flock        : 8.747257 0.000175  3360280
    49. ru_php_forum_52305_preg_replace_callback_04_fix              : 7.788782 0.000156  3360280
    50. ru_php_forum_52305_denis01_02                                : 14.836580 0.000297  3360280
    51. ru_php_forum_52305_runcore_01                                : 2.366116 0.000047  3360280
    52.  
    53. BANK   :       g1
    54. CNT    :    10000
    55. UNQ    :     1488
    56. ROUNDS :        5
    57. BASE   :     INIT
    58. ru_php_forum_52305_strstr_01                                 : 74.099817 0.001482  4836424
    59. ru_php_forum_52305_preg_replace_callback_02_02               : 19.241393 0.000385  4836424
    60. ru_php_forum_52305_preg_replace_callback_03_02               : 20.174599 0.000403  4836424
    61. ru_php_forum_52305_preg_replace_callback_04_fix_flock        : 35.618944 0.000712  4836424
    62. ru_php_forum_52305_preg_replace_callback_04_fix              : 34.687058 0.000694  4836424
    63. ru_php_forum_52305_denis01_02                                : 77.375614 0.001548  4836424
    64. ru_php_forum_52305_runcore_01                                : 2.897272 0.000058  4836424
    65.  
    66. BANK   :       g2
    67. CNT    :    10000
    68. UNQ    :     6921
    69. ROUNDS :        5
    70. BASE   :     INIT
    71. ru_php_forum_52305_strstr_01                                 : 341.792648 0.006836  4868864
    72. ru_php_forum_52305_preg_replace_callback_02_02               : 48.996806 0.000980  4868864
    73. ru_php_forum_52305_preg_replace_callback_03_02               : 52.620071 0.001052  4868864
    74. ru_php_forum_52305_preg_replace_callback_04_fix_flock        : 65.520326 0.001310  4868864
    75. ru_php_forum_52305_preg_replace_callback_04_fix              : 68.319577 0.001366  4868864
    76. ru_php_forum_52305_denis01_02                                : 585.529199 0.011711  4868864
    77. ru_php_forum_52305_runcore_01                                : 11.719550 0.000234  4868864
    круто, но... код runcore теряет стату... проводим маленькое тестирование. его же проводим из-за замечания на пустой файл и неверный конец строки. код теста:
    Код (PHP):
    1. require_once 'ru_php_forum_52305.php';
    2.  
    3. $tests = array(
    4.     'ru_php_forum_52305_preg_replace_callback_03_02',
    5.     'ru_php_forum_52305_preg_replace_callback_03_02_eol',
    6.     
    7.     'ru_php_forum_52305_runcore_01',
    8. );
    9.  
    10. foreach($tests as $test) {
    11.     require_once './' . $test . '.php';
    12. }
    13.  
    14. $ips = array(
    15.     '11.11.11.11',
    16.     '22.22.22.22',
    17.     '33.33.33.33',
    18.     
    19.     '11.11.11.11',
    20.     '44.44.44.44',
    21.     '33.33.33.33',
    22.     
    23.     '11.11.11.1',
    24.     '22.22.22.2',
    25.     '11.11.11.11',
    26. );
    27.  
    28. foreach($tests as $test) {
    29.     unlink($test::FILE);
    30.     echo "\n\n=============================\n{$test}\n";
    31.     
    32.     foreach ($ips as $ip) {
    33.         $test::inc($ip);
    34.         var_dump(file_get_contents($test::FILE));
    35.     }
    36.     
    37.     echo "\n\n=============================\n\n";
    38. }] 
    выводы моих скриптов. их будем брат за "эталон". eol это просто модификация где константа не в начале добавляемой строки а в конце согласно замечанию runcore.
    Код (Text):
    1. =============================
    2. ru_php_forum_52305_preg_replace_callback_03_02
    3.  
    4. IP=11.11.11.11
    5. ---
    6. string(16) "
    7. 11.11.11.11 = 1"
    8. ---
    9.  
    10. IP=22.22.22.22
    11. ---
    12. string(32) "
    13. 11.11.11.11 = 1
    14. 22.22.22.22 = 1"
    15. ---
    16.  
    17. IP=33.33.33.33
    18. ---
    19. string(48) "
    20. 11.11.11.11 = 1
    21. 22.22.22.22 = 1
    22. 33.33.33.33 = 1"
    23. ---
    24.  
    25. IP=11.11.11.11
    26. ---
    27. string(48) "
    28. 11.11.11.11 = 2
    29. 22.22.22.22 = 1
    30. 33.33.33.33 = 1"
    31. ---
    32.  
    33. IP=44.44.44.44
    34. ---
    35. string(64) "
    36. 11.11.11.11 = 2
    37. 22.22.22.22 = 1
    38. 33.33.33.33 = 1
    39. 44.44.44.44 = 1"
    40. ---
    41.  
    42. IP=33.33.33.33
    43. ---
    44. string(64) "
    45. 11.11.11.11 = 2
    46. 22.22.22.22 = 1
    47. 33.33.33.33 = 2
    48. 44.44.44.44 = 1"
    49. ---
    50.  
    51. IP=11.11.11.1
    52. ---
    53. string(79) "
    54. 11.11.11.11 = 2
    55. 22.22.22.22 = 1
    56. 33.33.33.33 = 2
    57. 44.44.44.44 = 1
    58. 11.11.11.1 = 1"
    59. ---
    60.  
    61. IP=22.22.22.2
    62. ---
    63. string(94) "
    64. 11.11.11.11 = 2
    65. 22.22.22.22 = 1
    66. 33.33.33.33 = 2
    67. 44.44.44.44 = 1
    68. 11.11.11.1 = 1
    69. 22.22.22.2 = 1"
    70. ---
    71.  
    72. IP=11.11.11.11
    73. ---
    74. string(94) "
    75. 11.11.11.11 = 3
    76. 22.22.22.22 = 1
    77. 33.33.33.33 = 2
    78. 44.44.44.44 = 1
    79. 11.11.11.1 = 1
    80. 22.22.22.2 = 1"
    81. ---
    82.  
    83.  
    84. =============================
    85.  
    86.  
    87.  
    88. =============================
    89. ru_php_forum_52305_preg_replace_callback_03_02_eol
    90.  
    91. IP=11.11.11.11
    92. ---
    93. string(16) "11.11.11.11 = 1
    94. "
    95. ---
    96.  
    97. IP=22.22.22.22
    98. ---
    99. string(32) "11.11.11.11 = 1
    100. 22.22.22.22 = 1
    101. "
    102. ---
    103.  
    104. IP=33.33.33.33
    105. ---
    106. string(48) "11.11.11.11 = 1
    107. 22.22.22.22 = 1
    108. 33.33.33.33 = 1
    109. "
    110. ---
    111.  
    112. IP=11.11.11.11
    113. ---
    114. string(48) "11.11.11.11 = 2
    115. 22.22.22.22 = 1
    116. 33.33.33.33 = 1
    117. "
    118. ---
    119.  
    120. IP=44.44.44.44
    121. ---
    122. string(64) "11.11.11.11 = 2
    123. 22.22.22.22 = 1
    124. 33.33.33.33 = 1
    125. 44.44.44.44 = 1
    126. "
    127. ---
    128.  
    129. IP=33.33.33.33
    130. ---
    131. string(64) "11.11.11.11 = 2
    132. 22.22.22.22 = 1
    133. 33.33.33.33 = 2
    134. 44.44.44.44 = 1
    135. "
    136. ---
    137.  
    138. IP=11.11.11.1
    139. ---
    140. string(79) "11.11.11.11 = 2
    141. 22.22.22.22 = 1
    142. 33.33.33.33 = 2
    143. 44.44.44.44 = 1
    144. 11.11.11.1 = 1
    145. "
    146. ---
    147.  
    148. IP=22.22.22.2
    149. ---
    150. string(94) "11.11.11.11 = 2
    151. 22.22.22.22 = 1
    152. 33.33.33.33 = 2
    153. 44.44.44.44 = 1
    154. 11.11.11.1 = 1
    155. 22.22.22.2 = 1
    156. "
    157. ---
    158.  
    159. IP=11.11.11.11
    160. ---
    161. string(94) "11.11.11.11 = 3
    162. 22.22.22.22 = 1
    163. 33.33.33.33 = 2
    164. 44.44.44.44 = 1
    165. 11.11.11.1 = 1
    166. 22.22.22.2 = 1
    167. "
    168. ---
    169.  
    170.  
    171. =============================
    есть претензии к показателям? вроде корректно и добавлено и учтено.

    а вот вывод сценария runcore я отдельно вынес. во-первых прошу обратить внимание на замечание пхп-машины - всё на самом деле ок. поскольку я тестирую свою версию с блокировкой файла - она создает пустой файл при выполнении fopen(), а версия runcore просто пытается прочитать файл который мы удаляем перед тестом. во-вторых прошу обратит внимание как ломается статистика счетчиков. а вот это уже критично.
    Код (Text):
    1. =============================
    2. ru_php_forum_52305_runcore_01
    3.  
    4. IP=11.11.11.11
    5. ---
    6. PHP Warning:  file_get_contents(/var/tmp/ramdisk/ru_php_forum_52305.txt): failed to open stream: No such file or directory in /lab/ru_php_forum/52305/ru_php_forum_52305_runcore_01.php on line 4
    7. string(16) "11.11.11.11 = 1
    8. "
    9. ---
    10.  
    11. IP=22.22.22.22
    12. ---
    13. string(32) "11.11.11.11 = 1
    14. 22.22.22.22 = 1
    15. "
    16. ---
    17.  
    18. IP=33.33.33.33
    19. ---
    20. string(48) "11.11.11.11 = 1
    21. 22.22.22.22 = 1
    22. 33.33.33.33 = 1
    23. "
    24. ---
    25.  
    26. IP=11.11.11.11
    27. ---
    28. string(48) "11.11.11.11 = 2
    29. 22.22.22.22 = 1
    30. 33.33.33.33 = 1
    31. "
    32. ---
    33.  
    34. IP=44.44.44.44
    35. ---
    36. string(64) "11.11.11.11 = 2
    37. 22.22.22.22 = 1
    38. 33.33.33.33 = 1
    39. 44.44.44.44 = 1
    40. "
    41. ---
    42.  
    43. IP=33.33.33.33
    44. ---
    45. string(64) "11.11.11.11 = 2
    46. 22.22.22.22 = 1
    47. 33.33.33.33 = 2
    48. 44.44.44.44 = 1
    49. "
    50. ---
    51.  
    52. IP=11.11.11.1
    53. ---
    54. string(64) "11.11.11.11 =32
    55. 22.22.22.22 = 1
    56. 33.33.33.33 = 2
    57. 44.44.44.44 = 1
    58. "
    59. ---
    60.  
    61. IP=22.22.22.2
    62. ---
    63. string(64) "11.11.11.11 =32
    64. 22.22.22.22 =21
    65. 33.33.33.33 = 2
    66. 44.44.44.44 = 1
    67. "
    68. ---
    69.  
    70. IP=11.11.11.11
    71. ---
    72. string(64) "11.11.11.11 =33
    73. 22.22.22.22 =21
    74. 33.33.33.33 = 2
    75. 44.44.44.44 = 1
    76. "
    77. ---
    78.  
    79.  
    80. =============================
    Добавлено спустя 35 минут 56 секунд:
    кстати, runcore, ты используешь LOCK_EX при записи в файл. а ты не тестировал что будет если файл уже заблокирован? я спрашиваю к тому что мой говнокод блокировки файла годами проверен на моих пхп-демонах и он именно ждет блокировки (положенное кол-во итераций) и если блокировки не случилось - в данном случае завершает сценарий. а что будет с file_put_contents() будет ждать или просто тупо не запишет? опять же я блокирую файл на всё время чтения-обработки-записи дабы счетчики не изменились между чтением и записью. мне кажется твой код подвержен фейлу по состоянию гонки...

    Добавлено спустя 7 минут 14 секунд:
    я понял откуда это. в алгоритме-который-не-писал-denis01 я заменил $out = $out.PHP_EOL.$x[0].':'.$x[1]; на $out .= PHP_EOL . $x[0].'= '.$x[1]; а уже потом написал свою реализацию strstr_01 и потом уже были все регулярки. короче это копипаст кусочка кода denis01 который успешно прошел через все мои алгоритмы. но как мы понимаем - на логику оно вообще не влияет. подумаешь пустая строка в начале файла. сотри её и она там больше не появится.
     
  11. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    я про тот который ты привел последним. в теме. я его процитировал. как еще точнее указать ?
    ты же сам его привел в своем сообщении.

    Добавлено спустя 11 минут 21 секунду:
    про то что ломается статистика. завтра гляну почему ломается мой вариант.
    а твой последний результат кода какой? твоего алгоритма.
     
  12. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    наверное надо было отдельно уточнить. у меня упор на preg_replace_callback версий 02_01 - базовая, 03_01 - базовая с блокировкой, 03_02 - базовая с блокировкой и пробелами вокруг равно. hex-версии работают но файл при них требует утилит для конвертирования айпишника. поэтому они тут чисто для примера.
    остальные - могут не работать так как мне лениво было вдумчиво писать код либо я в отчете уже признал их недееспособность.

    все коды опубликованы. версия 03_02_eol это 03_02 только PHP_EOL в конец строки перемещен.
    04_fix это версия 02_02 с измененной регуляркой - без ^$m. 02_02 в свою очередь просто вариант 02_01 с пробелами вокруг равенства. не стал её включать в результаты так как есть версия 03_02 - с пробелами и файловой блокировкой - тяжелее и интереснее.
    04_fix_flock это 03_02 соответственно регуляркой без ^$m.
    то есть "fix" тут обозначает что "фиксированный" формат с пробелами вокруг равно.
     
  13. INETCHIK

    INETCHIK Активный пользователь

    С нами с:
    13 фев 2014
    Сообщения:
    35
    Симпатии:
    0
    если статистика очищается каждый день, возможно лучше будет, если создать файл в отдельной директорий для каждого нового айпи и в качестве имени файла выбрать айпи.
    Далее код с минимальной проверкой.


    Код (PHP):
    1. <?php
    2. if(!is_dir('iplist/')) mkdir('iplist/');
    3. $f='iplist/'.getenv('REMOTE_ADDR'); //директория/имя_файла
    4.  
    5. //exists -r -w
     
  14. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    об этом ничего не сказано в оригинальной задаче, но думаю это слишком сильная девиация.

    к тому же можно провести простой тест. создаем 1000000 записей в файле. при 15 байтах на адрес + допустим 13 байтах на запись счетчика получаем примерно 28мб файл. этот файл легко открывается любым текстовым редактором. можно искать адрес, можно искать значение.

    теперь создаем 1млн файлов в каталоге. и пробуем хотя бы войти в каталог. сложно? а то ж.
    далее. поиск адреса это по сути поиск нода, значит тут всё от файловой системы будет зависеть. а вот поиск по значениям уже требует перечитки каждого файла. а это одинаково накладно для всех фс.
    еще минусы:
    * ноды в файловой системе не безлимитны. у меня например в среднем 10млн на раздел. даже если весь раздел будет отдан этой реализации - она сможет в себе уместить только примерно 10млн адресов. из 4млрд. а вот файлик в 100-120 гб вполне можно разместить.
    * в каждом файле мы будем хранить короткое строчное представление числового значения счетчика. напомню, 10 байт хватает для записи 10млрд. но сам файл будет выравнен под форматирование жесткого диска. например в старые добрые 512 байт. плюс запись о файле в метафайловой таблице. то есть оверхед на хранение короткого числа вообще жуткий.
    так что не особо важно как часто будут производиться действия (а в задаче вообще ничего ни о чем кроме инкремента счетчиков не было сказано) - файл на адрес это имхо не лучшая реализация.
     
  15. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    убрал баг указанный Ганзалом. и блокировку, по ней нужно отдельно тестить. спорить не буду. в исходном задании об этом ничего не было, поэтому можно на этом не заострять внимание пока. главное сам подход к решению. а проблема блокировки или будет у всех или ни у кого.
    Код (PHP):
    1. class ru_php_forum_52305_runcore_01 extends ru_php_forum_52305 {
    2.         public static function inc ($ip) {
    3.             $s = file_get_contents(static::FILE);
    4.             $ip = ' '.$ip.' = ';
    5.             if ( ($p = strpos($s, $ip)) !== false ) {
    6.               $p_cnt = $p +strlen($ip);
    7.               $p_nl = strpos($s, PHP_EOL, $p_cnt);
    8.               $cnt = intval( $p_nl!==false ? substr($s, $p_cnt, $p_nl-$p_cnt) : substr($s, $p_cnt) );
    9.               file_put_contents(static::FILE, substr_replace($s, $cnt+1, $p_cnt, strlen($cnt)) );
    10.             } else { // new ip
    11.               file_put_contents(static::FILE, $ip.'1'.PHP_EOL, FILE_APPEND );
    12.             } 
    13.         }
    14.     } 
    Добавлено спустя 30 минут 21 секунду:
    насчет твоего кода.ХЗ если честно. скопировал твой вариант. проверил. глючит.
    Код (PHP):
    1. define('FILE', './ip.txt');
    2. //
    3. function inc_ganzal($ip) {
    4.   $done = false;
    5.   $f = preg_replace_callback('~^('.preg_quote($ip).')\s*=\s*(\d+)$~m', function($m) use (&$done) {
    6.     $done = true;
    7.     return $m[1] . '=' . ++$m[2];
    8.   if (!$done) {
    9.     $f .= PHP_EOL . $ip . '=1';
    10.   }
    11. }
    12. //
    13. $ips = [
    14.     '11.11.11.11',
    15.     '22.22.22.22',
    16.     '33.33.33.33',
    17.     '11.11.11.11',
    18.     '44.44.44.44',
    19.     '33.33.33.33',
    20.     '11.11.11.1',
    21.     '22.22.22.2',
    22.     '11.11.11.11',
    23. ];
    24. foreach($ips as $ip) {
    25.   inc_ganzal($ip);
    26. }
    27. echo '<pre>';
    выводит
    PHP Version 5.4.32
    PCRE (Perl Compatible Regular Expressions) Support enabled
    PCRE Library Version 8.32 2012-11-30


    ААУУ. народ. затестите у себя кто нить еще, код что выше. у кого что выдаст?
     
  16. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    хм...

    тестовый сервер (на котором всё это писалось-запускалось) и один произвольно взятый боевой сервер:
    Код (Text):
    1. PHP 5.5.9-1ubuntu4.6 (cli) (built: Feb 13 2015 19:17:11)
    2. Copyright (c) 1997-2014 The PHP Group
    3. Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    4.     with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies
    5.  
    6. PCRE (Perl Compatible Regular Expressions) Support => enabled
    7. PCRE Library Version => 8.31 2012-07-06
    Код (Text):
    1. $ php runcore.php
    2. <pre>
    3. 11.11.11.11=3
    4. 22.22.22.22=1
    5. 33.33.33.33=2
    6. 44.44.44.44=1
    7. 11.11.11.1=1
    8. 22.22.22.2=1
    нашел пых на винде:
    Код (Text):
    1. PHP 5.5.18 (cli) (built: Oct 15 2014 13:05:29)
    2. Copyright (c) 1997-2014 The PHP Group
    3. Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    4.     with Xdebug v2.2.7, Copyright (c) 2002-2015, by Derick Rethans
    5.  
    6.  
    7. PCRE (Perl Compatible Regular Expressions) Support => enabled
    8. PCRE Library Version => 8.34 2013-12-15
    Код (Text):
    1. $ php runcore.php
    2. <pre>
    3. 11.11.11.11=1
    4. 22.22.22.22=1
    5. 33.33.33.33=1
    6. 11.11.11.11=1
    7. 44.44.44.44=1
    8. 33.33.33.33=1
    9. 11.11.11.1=1
    10. 22.22.22.2=1
    11. 11.11.11.11=1
    наличие странного поведения признаю. пойду подумаю что может быть не так.
     
  17. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    да, у меня тестовый на винде.
     
  18. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    ну и вполне очевидно почему так происходит:
    Код (PHP):
    1. <?php
    2. echo PHP_OS, "\n";
    3.  
    4. $ips = [
    5.     '11.11.11.11' => 'INC',
    6.     '22.22.22.22' => 'INC',
    7.     '33.33.33.33' => 'INC',
    8.     '11.11.11.11' => 'INC',
    9.     '44.44.44.44' => 'ADD',
    10.     '33.33.33.33' => 'INC',
    11.     '11.11.11.1'  => 'INC',
    12.     '22.22.22.2'  => 'ADD',
    13.     '11.11.11.11' => 'INC',
    14. ];
    15.  
    16. $base = [
    17.     '11.11.11.11',
    18.     '22.22.22.22',
    19.     '33.33.33.33',
    20.     '11.11.11.1',
    21.     '11.11.11.11',
    22. ];
    23.  
    24. $tests = [
    25.     'EOL' => 'PHP_EOL',
    26.     'lf' => '\n',
    27.     'crlf' => '\r\n',
    28.     'cr' => '\r',
    29. ];
    30.  
    31. $test_EOL = implode(PHP_EOL, $base);
    32. $test_lf = implode("\n", $base);
    33. $test_crlf = implode("\r\n", $base);
    34. $test_cr = implode("\r", $base);
    35.  
    36. foreach ($tests as $name => $eol) {
    37.     echo "\nTEST {$name}, EOL={$eol}\n";
    38.     $test = ${'test_' . $name};
    39.     foreach ($ips as $ip => $expected) {
    40.         $action = (preg_match('~^'.preg_quote($ip).'$~m', $test) ? 'INC' : 'ADD');
    41.         
    42.         echo sprintf("IP = %15s EXP = %s ACT = %s RESULT : %s\n", $ip, $expected, $action, ($expected==$action 'ok' : 'FAIL'));
    43.     }
    44. } 
    lin
    Код (Text):
    1. Linux
    2.  
    3. TEST EOL, EOL=PHP_EOL
    4. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    5. IP =     22.22.22.22 EXP = INC ACT = INC RESULT : ok
    6. IP =     33.33.33.33 EXP = INC ACT = INC RESULT : ok
    7. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    8. IP =      11.11.11.1 EXP = INC ACT = INC RESULT : ok
    9. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    10.  
    11. TEST lf, EOL=\n
    12. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    13. IP =     22.22.22.22 EXP = INC ACT = INC RESULT : ok
    14. IP =     33.33.33.33 EXP = INC ACT = INC RESULT : ok
    15. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    16. IP =      11.11.11.1 EXP = INC ACT = INC RESULT : ok
    17. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    18.  
    19. TEST crlf, EOL=\r\n
    20. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    21. IP =     22.22.22.22 EXP = INC ACT = ADD RESULT : FAIL
    22. IP =     33.33.33.33 EXP = INC ACT = ADD RESULT : FAIL
    23. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    24. IP =      11.11.11.1 EXP = INC ACT = ADD RESULT : FAIL
    25. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    26.  
    27. TEST cr, EOL=\r
    28. IP =     11.11.11.11 EXP = INC ACT = ADD RESULT : FAIL
    29. IP =     22.22.22.22 EXP = INC ACT = ADD RESULT : FAIL
    30. IP =     33.33.33.33 EXP = INC ACT = ADD RESULT : FAIL
    31. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    32. IP =      11.11.11.1 EXP = INC ACT = ADD RESULT : FAIL
    33. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    win
    Код (Text):
    1. WINNT
    2.  
    3. TEST EOL, EOL=PHP_EOL
    4. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    5. IP =     22.22.22.22 EXP = INC ACT = ADD RESULT : FAIL
    6. IP =     33.33.33.33 EXP = INC ACT = ADD RESULT : FAIL
    7. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    8. IP =      11.11.11.1 EXP = INC ACT = ADD RESULT : FAIL
    9. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    10.  
    11. TEST lf, EOL=\n
    12. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    13. IP =     22.22.22.22 EXP = INC ACT = INC RESULT : ok
    14. IP =     33.33.33.33 EXP = INC ACT = INC RESULT : ok
    15. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    16. IP =      11.11.11.1 EXP = INC ACT = INC RESULT : ok
    17. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    18.  
    19. TEST crlf, EOL=\r\n
    20. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    21. IP =     22.22.22.22 EXP = INC ACT = ADD RESULT : FAIL
    22. IP =     33.33.33.33 EXP = INC ACT = ADD RESULT : FAIL
    23. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    24. IP =      11.11.11.1 EXP = INC ACT = ADD RESULT : FAIL
    25. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    26.  
    27. TEST cr, EOL=\r
    28. IP =     11.11.11.11 EXP = INC ACT = ADD RESULT : FAIL
    29. IP =     22.22.22.22 EXP = INC ACT = ADD RESULT : FAIL
    30. IP =     33.33.33.33 EXP = INC ACT = ADD RESULT : FAIL
    31. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    32. IP =      11.11.11.1 EXP = INC ACT = ADD RESULT : FAIL
    33. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    Добавлено спустя 38 минут 9 секунд:
    тихо беседу сам с собою веду...

    лечится так:
    --- $action = (preg_match('~^'.preg_quote($ip).'$~m', $test) ? 'INC' : 'ADD');
    +++ $action = (preg_match('~^'.preg_quote($ip).'\s*$~m', $test) ? 'INC' : 'ADD');

    lin
    Код (Text):
    1. Linux
    2.  
    3. TEST EOL, EOL=PHP_EOL
    4. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    5. IP =     22.22.22.22 EXP = INC ACT = INC RESULT : ok
    6. IP =     33.33.33.33 EXP = INC ACT = INC RESULT : ok
    7. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    8. IP =      11.11.11.1 EXP = INC ACT = INC RESULT : ok
    9. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    10.  
    11. TEST lf, EOL=\n
    12. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    13. IP =     22.22.22.22 EXP = INC ACT = INC RESULT : ok
    14. IP =     33.33.33.33 EXP = INC ACT = INC RESULT : ok
    15. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    16. IP =      11.11.11.1 EXP = INC ACT = INC RESULT : ok
    17. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    18.  
    19. TEST crlf, EOL=\r\n
    20. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    21. IP =     22.22.22.22 EXP = INC ACT = INC RESULT : ok
    22. IP =     33.33.33.33 EXP = INC ACT = INC RESULT : ok
    23. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    24. IP =      11.11.11.1 EXP = INC ACT = INC RESULT : ok
    25. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    26.  
    27. TEST cr, EOL=\r
    28. IP =     11.11.11.11 EXP = INC ACT = ADD RESULT : FAIL
    29. IP =     22.22.22.22 EXP = INC ACT = ADD RESULT : FAIL
    30. IP =     33.33.33.33 EXP = INC ACT = ADD RESULT : FAIL
    31. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    32. IP =      11.11.11.1 EXP = INC ACT = ADD RESULT : FAIL
    33. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    win
    Код (Text):
    1. WINNT
    2.  
    3. TEST EOL, EOL=PHP_EOL
    4. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    5. IP =     22.22.22.22 EXP = INC ACT = INC RESULT : ok
    6. IP =     33.33.33.33 EXP = INC ACT = INC RESULT : ok
    7. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    8. IP =      11.11.11.1 EXP = INC ACT = INC RESULT : ok
    9. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    10.  
    11. TEST lf, EOL=\n
    12. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    13. IP =     22.22.22.22 EXP = INC ACT = INC RESULT : ok
    14. IP =     33.33.33.33 EXP = INC ACT = INC RESULT : ok
    15. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    16. IP =      11.11.11.1 EXP = INC ACT = INC RESULT : ok
    17. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    18.  
    19. TEST crlf, EOL=\r\n
    20. IP =     11.11.11.11 EXP = INC ACT = INC RESULT : ok
    21. IP =     22.22.22.22 EXP = INC ACT = INC RESULT : ok
    22. IP =     33.33.33.33 EXP = INC ACT = INC RESULT : ok
    23. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    24. IP =      11.11.11.1 EXP = INC ACT = INC RESULT : ok
    25. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    26.  
    27. TEST cr, EOL=\r
    28. IP =     11.11.11.11 EXP = INC ACT = ADD RESULT : FAIL
    29. IP =     22.22.22.22 EXP = INC ACT = ADD RESULT : FAIL
    30. IP =     33.33.33.33 EXP = INC ACT = ADD RESULT : FAIL
    31. IP =     44.44.44.44 EXP = ADD ACT = ADD RESULT : ok
    32. IP =      11.11.11.1 EXP = INC ACT = ADD RESULT : FAIL
    33. IP =      22.22.22.2 EXP = ADD ACT = ADD RESULT : ok
    маководов даже и не собираюсь ублажать, пардон.

    Добавлено спустя 5 минут 1 секунду:
    блин, я там в $base случайно 11,11,11,11 продублировал...
    а регулярку хочу вот такую
    Код (Text):
    1. ~^'.preg_quote($ip).'\s*=\s*(\d+)\D*$~m
    Добавлено спустя 31 минуту 18 секунд:
    ну и безусловно поздравления новому лидеру теста:
    Код (Text):
    1.  
    2. BANK   :        0
    3. CNT    :        9
    4. UNQ    :        3
    5. ROUNDS :    10000
    6. BASE   :     INIT
    7. ru_php_forum_52305_preg_replace_callback_03_01               : 4.247025 0.000047   593680
    8. ru_php_forum_52305_preg_replace_callback_03_02               : 4.210094 0.000047   594448
    9. ru_php_forum_52305_preg_replace_callback_05_01               : 4.234770 0.000047   594864
    10. ru_php_forum_52305_preg_replace_callback_05_02               : 4.241270 0.000047   595408
    11. ru_php_forum_52305_preg_replace_callback_05_02_noflock       : 3.134184 0.000035   595408
    12. ru_php_forum_52305_runcore_01                                : 2.582040 0.000029   595408
    13. ru_php_forum_52305_runcore_02                                : 2.490332 0.000028   595432
    14.  
    15. BANK   :        1
    16. CNT    :      117
    17. UNQ    :        5
    18. ROUNDS :     1000
    19. BASE   :     INIT
    20. ru_php_forum_52305_preg_replace_callback_03_01               : 5.526047 0.000047   613136
    21. ru_php_forum_52305_preg_replace_callback_03_02               : 5.513646 0.000047   613136
    22. ru_php_forum_52305_preg_replace_callback_05_01               : 5.552962 0.000047   613256
    23. ru_php_forum_52305_preg_replace_callback_05_02               : 5.534556 0.000047   613256
    24. ru_php_forum_52305_preg_replace_callback_05_02_noflock       : 4.106169 0.000035   613256
    25. ru_php_forum_52305_runcore_01                                : 3.368238 0.000029   613256
    26. ru_php_forum_52305_runcore_02                                : 3.202887 0.000027   613256
    27.  
    28. BANK   :        2
    29. CNT    :      123
    30. UNQ    :       10
    31. ROUNDS :     1000
    32. BASE   :     INIT
    33. ru_php_forum_52305_preg_replace_callback_03_01               : 5.922501 0.000048   623976
    34. ru_php_forum_52305_preg_replace_callback_03_02               : 5.881683 0.000048   623976
    35. ru_php_forum_52305_preg_replace_callback_05_01               : 5.925225 0.000048   623976
    36. ru_php_forum_52305_preg_replace_callback_05_02               : 5.924031 0.000048   623976
    37. ru_php_forum_52305_preg_replace_callback_05_02_noflock       : 4.437509 0.000036   623976
    38. ru_php_forum_52305_runcore_01                                : 3.535712 0.000029   623976
    39. ru_php_forum_52305_runcore_02                                : 3.422978 0.000028   623976
    40.  
    41. BANK   :       g0
    42. CNT    :    10000
    43. UNQ    :      217
    44. ROUNDS :        5
    45. BASE   :     INIT
    46. ru_php_forum_52305_preg_replace_callback_03_01               : 3.876294 0.000078  3367736
    47. ru_php_forum_52305_preg_replace_callback_03_02               : 3.914231 0.000078  3367736
    48. ru_php_forum_52305_preg_replace_callback_05_01               : 3.967946 0.000079  3367736
    49. ru_php_forum_52305_preg_replace_callback_05_02               : 4.004731 0.000080  3367736
    50. ru_php_forum_52305_preg_replace_callback_05_02_noflock       : 3.378140 0.000068  3367736
    51. ru_php_forum_52305_runcore_01                                : 1.565151 0.000031  3367736
    52. ru_php_forum_52305_runcore_02                                : 1.512397 0.000030  3367736
    53.  
    54. BANK   :       g1
    55. CNT    :    10000
    56. UNQ    :     1488
    57. ROUNDS :        5
    58. BASE   :     INIT
    59. ru_php_forum_52305_preg_replace_callback_03_01               : 12.936603 0.000259  4841752
    60. ru_php_forum_52305_preg_replace_callback_03_02               : 13.319694 0.000266  4841752
    61. ru_php_forum_52305_preg_replace_callback_05_01               : 12.973185 0.000259  4841752
    62. ru_php_forum_52305_preg_replace_callback_05_02               : 13.375181 0.000268  4841752
    63. ru_php_forum_52305_preg_replace_callback_05_02_noflock       : 12.793856 0.000256  4841752
    64. ru_php_forum_52305_runcore_01                                : 2.913258 0.000058  4841752
    65. ru_php_forum_52305_runcore_02                                : 3.102064 0.000062  4841752
    66.  
    67. BANK   :       g2
    68. CNT    :    10000
    69. UNQ    :     6921
    70. ROUNDS :        5
    71. BASE   :     INIT
    72. ru_php_forum_52305_preg_replace_callback_03_01               : 47.169284 0.000943  4842912
    73. ru_php_forum_52305_preg_replace_callback_03_02               : 63.810053 0.001276  4842912
    74. ru_php_forum_52305_preg_replace_callback_05_01               : 70.986210 0.001420  4842912
    75. ru_php_forum_52305_preg_replace_callback_05_02               : 73.925443 0.001479  4842912
    76. ru_php_forum_52305_preg_replace_callback_05_02_noflock       : 72.972932 0.001459  4842912
    77. ru_php_forum_52305_runcore_01                                : 14.079614 0.000282  4842912
    78. ru_php_forum_52305_runcore_02                                : 19.455407 0.000389  4842912
    где мои 05 это с обновленной регуляркой, _01 произвольные пробелы, _02 фиксированные пробелы, runcore_01 первый алгоритм который провалился, _02 - второй, который дает почти актуальные данные (почти потому что метод инициализации подсовывает другой формат окончания строки. только и всего), но однозначно показывает уверенно быстрый результат. поскольку в нем нет блокировки - preg_replace_callback_05_02_noflock тоже без блокировки для сравнения. жаль я поленился написать итерацию с офсетом =)
     
  19. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    молодец, разобрался где собака порылась)
    по сути, мой вариант, это та же твоя регулярка, тока сделанная вручную через строковые функции. профит от этого есть небольшой, зато это трудоемко, медленно пишется и чревато многими ошибками.
    регулярки, как видно, работают ОЧЕНЬ шустро, быстро пишутся и достаточно наглядны.
     
  20. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    Теперь я буду думать, как это делается))
     
  21. INETCHIK

    INETCHIK Активный пользователь

    С нами с:
    13 фев 2014
    Сообщения:
    35
    Симпатии:
    0