LINUX.ORG.RU

еще один кирпичик ненависти к php

 


0

1

php совсем печален, развращает, и наличием высокоуровневых функций учит писать неправильный код.

два цикла, делают одно и тоже, но классический for быстрее в 4 раза.

<?php

for ($i = $start; $i < $end; $i+=$step)
{
//do something with array
}

foreach (range($start, $end, $step) as $i)
{
//do something with array
}

?>

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

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

<?php
$page_count = ceil(($db->querySingle('SELECT COUNT(*) FROM blog_posts') / 10));
$page_cache = '';
$page = (isset($_GET['page']))?(int) $_GET['page']:$page_count;

for ($page_id = $page_count; $page_id > 0; $page_id--) {
  if ($page == $page_id) {
    $page_cache .= ' '.$page_id;
  }
  elseif (($page_id == $page_count) || ($page_id == 1)) {
    $page_skip = 1;
    $page_cache .= ' <a href="?page='.$page_id.'">'.$page_id.'</a>';
  }
  elseif (($page < ($page_id + 2)) && ($page > ($page_id - 2))) {
    $page_skip = 1;
    $page_cache .= ' <a href="?page='.$page_id.'">'.$page_id.'</a>';
  }
  elseif ($page_skip > 0) {
    $page_skip--;
    $page_cache .= ' ...';
  }
}
echo $page_cache;
?>

<?php
$try = $db->query('
  SELECT *
  FROM blog_posts
  LIMIT '.($page * 10 - 10).', 9
  ');
?>

спасибо, извините.

★★★★★

Твой код можно ёмко описать фразой: «смешались в кучу люди, кони».
Если любишь пхп, то заюзай эту штуку http://www.tinymvc.com/ – это микрофреймворк от автора шаблонизатора Смарти.
Когда сам пописывал на пыхе, то очень был доволен.
Для твоей задачи тем более пойдёт.

Hertz ★★★★★
()
Ответ на: комментарий от Spoofing

Затормозить вим может только пользователь
Например, такой, как Я
Бип-бип...да что за фигня

oblepiha_pie
()
Ответ на: комментарий от Spoofing

vim единственный из редакторов, что не тормозит на больших файлах. бебебе

Агащаз. Ты просто не открывал действительно больших файлов.

anonymous
()
Ответ на: комментарий от Spoofing

Не знаю за vim, но я вот точно торможу на больших файлах, даже когда сам их наклепал.

heilkitty ★★
()
Ответ на: комментарий от KRoN73

Не в n, а примерно в 4 раза в PHP и в 1.5 раза в HHVM вне зависимости от размера массива :)

PHP 5.3.3-7+squeeze19

function csvOut(&$p, $d=";", $q='"', $e="\\", $q2='\'') {
	for($i=0; $i<count($p); $i++) {
		echo $q . implode($q.$d.$q, str_replace($q, $q2, $p[$i])) . $q . "\n";
	}
}

Для массива ~50000 элементов - работает более 5 минут и убивается по таймеру. С $count - пару секунд.

Tanger ★★★★★
()
Ответ на: комментарий от Spoofing

как задрот, который в играх заглядывает под каждый камушек, - я оптимизирую каждый байт кода.

скриптопараша

Deleted
()

php совсем печален, развращает, и наличием высокоуровневых функций учит писать неправильный код

развращает ... учит

Спешите видеть, php развращает малолетних и учит детей плохому.

no-such-file ★★★★★
()
for ($i = $start; $i < $end; $i+=$step)
{
//do something with array
}

foreach (range($start, $end, $step) as $i)
{
//do something with array
}

ты путашь тёплое с мягким

тормозит не foreach, а foreach + range, и должен тебе признаться это просто говнод

foreach используется для одинх ситуаций, for для других

q11q11 ★★★★★
()
Последнее исправление: q11q11 (всего исправлений: 2)
Ответ на: комментарий от VladimirMalyk

Причём, с range такая ерунда не только в php...

Shadow ★★★★★
()
Ответ на: комментарий от Spoofing

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

vim единственный из редакторов, что не тормозит на больших файлах

Странный человек. Пишешь про то, что для тебя оптимизация каждого байта — приоритет, а как только о производительности тебе пишут, воспринимаешь это в контексте производительности разработки.

Нет, я писал о производительности целевой системы. Мне плевать на тормоза редактора, но вот на больших файлах сам PHP тормозить начнёт. Как, впрочем, и ты сам год спустя. Но это уже вторичный вопрос в нашем контексте.

KRoN73 ★★★★★
()
Ответ на: комментарий от Tanger

PHP 5.3

А ничего, что он вышел 6 лет назад и уже deprecated? И что в PHP сейчас каждая новая цифра после точки — мажорное изменение?

Для массива ~50000 элементов - работает более 5 минут и убивается по таймеру

function csvOut(&$p, $d=";", $q='"', $e="\\", $q2='\'') {
	for($i=0; $i<count($p); $i++) {
		echo $q . implode($q.$d.$q, str_replace($q, $q2, $p[$i])) . $q . "\n";
	}
}

А ничего, что тут count() занимает ничтожную часть времени даже от конкатенации (которую, вообще, надо нафиг выносить из цикла — раньше, ещё на Бейсике, это было первое, чему учили сразу после изучения самих циклов), не говоря уже про чудовищные на этом фоне тормоза самого echo?

А ничего, что у тебя код вообще не работает, поскольку implode требует массив вторым аргументом? :)

KRoN73 ★★★★★
()

Вот ещё вам:

$results = array(array(1), array(2), array(3));
foreach ($results as $id => &$item)
  $item['test'] = $id;

foreach ($results as $id => $item)
  $item['test'];
// 1, 2, 2(!!!)
// FFUUU----

https://bugs.php.net/bug.php?id=29992 // 11 лет багу, и эти макаки считают такое поведение нормальным

Ты смешиваешь пхп и хтмл?

А как же «это фича такая в php!!111»?

anonymous
()
Ответ на: комментарий от KRoN73

А ничего, что он вышел 6 лет назад и уже deprecated?

5.3.3-7 - последняя версия в debian squeeze: https://packages.debian.org/squeeze/php5

А ничего, что тут count() занимает ничтожную часть времени даже от конкатенации

А вот и нет! Не знаю, как реализован count в php5.3, но он работает (по крайней мере в том месте) за линейное время от количества элементов в массиве.

А ничего, что у тебя код вообще не работает, поскольку implode требует массив вторым аргументом? :)

Работает: $p[$row][$col] -> str_replace(..., ..., $p[$row]) - array.

Tanger ★★★★★
()

два цикла, делают одно и тоже, но классический for быстрее в 4 раза.

покажи мне, как ты классическим for сделаешь такое:

foreach(array as key=>value)
{
}

foreach (range($start, $end, $step) as $i)

facepalm

emulek
()
Ответ на: комментарий от Spoofing

еще INDEX никаких нету, тоже не знаю зачем.

без INDEX будет жутко тупить.

emulek
()
Ответ на: комментарий от Deleted

Пхппроблемы.

так можно и в сишечке C++11 сделать. Если мозгов нет.

emulek
()
Ответ на: комментарий от KRoN73

http://pastebin.com/6cLTBW66

$ php t.php 
Foo: 4.4623129367828
Foo2: 0.0013799667358398

А если не использовать ссылку на массив (т.е. копировать его при передаче в функцию), результаты будут лучше:

$ php t.php 
Foo: 0.0026450157165527
Foo2: 0.0006279945373535

P.S на php5.6 то же самое: http://sandbox.onlinephpfunctions.com/code/b97eb25eb4b5f1875e09b7bf7c367a87a6...

Tanger ★★★★★
()
Последнее исправление: Tanger (всего исправлений: 1)
Ответ на: комментарий от emulek

зачем писать очевидное?

Мне, например, очевидно, что вызов count должен работать за O(1). А вот оказалось, что не всегда.

Tanger ★★★★★
()
Ответ на: комментарий от Spoofing

я оптимизирую каждый байт кода.

начни с индексов. И убери наконец $page из запроса. На, просвещайся: http://habrahabr.ru/post/137664/ Используй форму с массивом, всё равно потом что-то ещё засунешь.

структура крайне проста.

это пока так. Ну и на всегда, т.к. твой код придётся полностью переписать.

самое главное — все это летает. time wget сообщает о 3 милисекундах.

одна единственная страница? Не сомневаюсь. Только не понимаю, на кой ляд ты SQL прикрутил? Делал-бы в файлах, так будет даже быстрее.

не удивлюсь, если только на инициализацию php кода какого-нибудь фреймворка тратится по пол секунды.

да. За то там больше одной страницы показывает, НАМНОГО больше. И юзеров СРАЗУ Over9000.

не церемонясь пишу быстрый лапше-код.

тяп-ляп. Как раз про тебя сказано.

emulek
()
Ответ на: комментарий от KRoN73

Более того, если у тебя будет 9000 строк в одном файле

у тебя include сломалось?

emulek
()
Ответ на: комментарий от Tanger

5.3.3-7 - последняя версия в debian squeeze

Ну так это проблема Debian'а, что использует более не поддерживаемые версии :)

http://pastebin.com/6cLTBW66

Хм. Да, для 5000 элементов разрыв, действительно, большой. Был неправ. Просто не могу вспомнить, когда последний раз работал с такими массивами и без foreach(). Сейчас специально перешерстил свой фреймворк — на 841 foreach только 15 for..<..count() и во всех случаях — одиночный вызов для массива в единицы-десяток элементов. Ещё в трёх местах, где массивы более крупные, по старой памяти формат for($i=0, $count = count($array); $i < $count; $i++)

KRoN73 ★★★★★
()
Ответ на: комментарий от emulek

Да, действительно. Хорошо, что напомнил.

Hertz ★★★★★
()
Ответ на: комментарий от anonymous

и эти макаки считают такое поведение нормальным

>>> a=[1,2,3]
>>> b=a
>>> b[1]='qwe'
>>> a
[1, 'qwe', 3]

Опаньки.

11 лет багу

Я, вот, в упор не вижу там бага, как не вижу бага, например, в предыдущем примере из Python. Нужно хоть немного понимать, как работают ссылки и указатели, прежде чем пользоваться ими.

KRoN73 ★★★★★
()

полуркал на тему оптимизации sqlite, про индексы пока еще ни сном ни худом, в базе 4 записи, думаю в данный момент индекс погоды не сделает.

но вот что я затестил на писюке Pentium G3258 (2 ядра), 8гб памяти, SSD 64гб:

./ab -n 2700 -c 90 -k -H «Accept-Encoding: gzip, deflate» http://example.com/blog/

когда 90 человек одновременно открывают по 30 страничек.

средний результат 950-1000 запросов в секунду.

далее, сделал просто tar cf /tmp/www.tar /srv/www; mount -t tmpfs -o size=1M tmpfs /srv/www; tar xf /tmp/www.tar -C / поместив весь сайт включая sqlite3.db в tmpfs.

количество запросов выросло на 500 штук, средний результат стал 1450-1500 запросов, причем PHP начал с ними не справляться, выдавая ошибку

[13-Apr-2015 22:41:26] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

окей, увеличил ему чилдренов, было 5, сделал 8 (2 ядра процессора * 4). ошибками php-fpm сыпать в лог перестал, но остались ошибки у ab-утилиты (failed requests), в среднем 100 ошибок на 3000 запросов в секунду.

$db = new SQLite3('../sqlite3.db');

$db->busyTimeout(5000);

добавил волшебную строку, увеличивающую таймаут и от ошибок избавился теперь уже насовсем.

теперь пришло время чистить код, хз что там оптимизировать в запросах, когда один SELECT и один JOIN для 4х записей в базе.

удалил постраничную навигацию, получил ускорение до +100 запросов, всего ~1650.

удалил вообще весь код кроме отвечающего за «/blog/», получил +300, всего ~1950.

ИТОГО, поднял количество запросов с 1000 до 2000, проведя некоторую отпимизацию, а именно:

1) у php делаем pm.max_children = (кол-во ядер * 4)

2) обязательно указываем таймаут к базе $db->busyTimeout(5000);

3) смена журнала $db->exec('PRAGMA journal_mode=WAL;'); НЕ ДАЛО НИКАКОГО ЭФФЕКТА ВООБЩЕ, только полный OFF дает всего каких-то +50 запросов

4) tmpfs ускорил аж до +500 запросов, но сие понятно зависит конкретно от проекта, условий в которых работает железо и прочая-прочая-прочая.

5) чистота - залог здоровья. надо раскидывать все по разным файлам и делать include по необходимости, реально, парсер PHP съедает ощутимое количество ресурсов, что негативно отражается на количестве запросов.

ощщем, tmpfs пока идет нафиг, все остальное - ок. итого имею 1500 запросов в секунду. =)

Spoofing ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

Да, для 5000 элементов разрыв, действительно, большой.

Оказывается тут какая-то фича именно с передачей по ссылке.

Tanger ★★★★★
()
Ответ на: комментарий от Spoofing

5) чистота - залог здоровья. надо раскидывать все по разным файлам и делать include по необходимости, реально, парсер PHP съедает ощутимое количество ресурсов, что негативно отражается на количестве запросов.

Так ты чтоли opcode кеш apc/xcache/memcache не включал ?

greenplastik
()
Ответ на: комментарий от greenplastik

про memcached слышал, что с него странички отдают в nginx, а про opcode cache слышу первый раз, ща... погуглю.

Spoofing ★★★★★
() автор топика
Ответ на: комментарий от greenplastik

поставил php-opcache, жесть!

1800 запросов в секунду, и это на ровном месте, я ничего не убирал, весь говнокод в одном файле.

засунул в tmpfs, получил 2600 запросов в среднем, плюс-минус 200.

спасибо за подсказку, работает прозрачно, жрать не просит.

Spoofing ★★★★★
() автор топика
Ответ на: комментарий от Spoofing

А ты его настройки ещё покрути. Сможешь и больше выжать.

dhameoelin ★★★★★
()
<?php
$db = new SQLite3('../sqlite3.db');
$db->busyTimeout(5000);
$db->exec('PRAGMA synchronous = OFF;');
$db->exec('PRAGMA journal_mode = MEMORY;');
?>

остановился на таких настройках, плюс стоит php-opcache, утилита ab упирается в 2600 запросов, иногда их 2602... короче, сама уже ab работает на пределе железахерню несу.

думаю мой бложек никогда не будет читать хотя бы 1 человек в секунду, не говоря о 2600. =)

всем спасибо.

Spoofing ★★★★★
() автор топика
Последнее исправление: Spoofing (всего исправлений: 1)
Ответ на: комментарий от KRoN73

в упор не вижу там бага

Так же, как и макаки по ссылке. Что вобщем-то тебе отнюдь не в плюс.

Тем не менее, итерация по массиву поломана. И мне начхать, какую инопланетную логику это реализует, это неожиданное поведение.

anonymous
()
Ответ на: комментарий от anonymous
// https://bugs.php.net/bug.php?id=29992

$array = array(1,2,3);

unset($item);
foreach( $array as &$item ){
};

var_dump( $array );

unset($item);
foreach( $array as $item ){
};

var_dump( $array );

Так переменную $item нужно очищать после/перед использованием.

greenplastik
()
Ответ на: комментарий от greenplastik

...и ещё один вариант чисто похапешного костыля.

my $i = 1;
foreach my $item (@results) {
  $item->{test} = $i++;
}

say $_->{test} for @results;
# 1, 2, 3; как и ожидалось

Почему в данном случае мне не приходится заниматься подобным онанизмом с переменными?

anonymous
()
Ответ на: комментарий от anonymous

Почему в данном случае мне не приходится заниматься подобным онанизмом с переменными?

Потомучто ты не понимаешь как в php работает присваивание по ссылке «&» (assigment by reference). http://php.net/manual/ru/language.operators.assignment.php .

greenplastik
()

fastcgi_cache — альтернатива op-cache

это не php, это чистая статика, php вообще не дергается. так вот,

fastcgi_cache_path /var/cache/nginx levels= keys_zone=all:16m max_size=512m inactive=10m;

location ~ \.php$ {
     fastcgi_cache all;
#     fastcgi_cache_key "$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri";
     fastcgi_cache_key "$host|$uri$is_args$args|$cookie_PHPSESSID";
     fastcgi_cache_use_stale updating error timeout invalid_header http_500;

     fastcgi_cache_valid 2h;
     fastcgi_cache_valid 200 302 304 3d;
     fastcgi_cache_valid 301 7d;
     fastcgi_cache_valid 404 1d;
     fastcgi_cache_valid any 2h;

     fastcgi_hide_header "Set-Cookie";
     fastcgi_ignore_headers "Cache-Control" "Expires" "Set-Cookie";
}

кэширование делается по куке PHPSESSID, хотя можно и сделать вариант который перед ним. чтобы не кормить анонимусов излишними сессиями и не засирать кэш, то лучше session_start без необходимости не вызывать.

ну так вот, данная конфа после обработки php файликов помещает их в кэш на 10 минут, после чего отдает уже статику. количество запросов судя по ab — 12000 в секунду!!! двенадцать тысяч, да! это чистая статика отдается.

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

либо.. ЛОР мне подкинул идею, здесь на каждый комментарий свой ?lastmod=UNIX-time, тобишь к ссылке с измененившимся контентом приписываем ластмод и кэшируется уже новая страничка с новым комментарием, а старая сама будет удалена через 10 минут.

если контента реально можно, то процесс можно ускорять самому, а именно по крону удалять все файлы, к которым обращались 10 минут назад:

*/10 * * * * find /var/cache/nginx -maxdepth 1 -amin +10 -delete
Spoofing ★★★★★
() автор топика

по итогам треда

хотите 20,000 (двадцать тысяч запросов) в секунду? только статика! только кэширование! только fastcgi_cache! только оптимизация сетевого стека ядра!

хотите 5,000 (пять тысяч запросов)? берете процессор не ниже Core i5, помещаете весь проект в tmpfs, включая БД, в которой отключаете параноидальный режим сохранения данных (synchronous = OFF; journal_mode = OFF;), подключаете opcache, ставите max_children равное (кол-во ядер * 4).

до 1,000 запросов в секунду сидите на жопе ровно и ничего не делаете.

Spoofing ★★★★★
() автор топика
Ответ на: по итогам треда от Spoofing

попробуй MySQL(MariaDB), зачем ты мучаешься с встраиваемой Sqlite?

только статика!

толку-то от статики?

emulek
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.