Ну как сказать :)
TMTOWTDI во всей красе ))
Второй вариант кстати проще к понимаю что происходит. Конечно при условии, что знаешь, что не истинное логическое выражение возвращает пустую строку, а истинное единицу )))
Я не люблю строить такие логические цепочки. Хотя вру. Люблю, но только с || или or ))) Они как-то понятнее смотрятся ) Да и применение находят чаще )
Без интерпретатора не так просто угадать результат )))
Из той же оперы:
sub some {return 'A' if 0} что вернет?
Или еще из прекрасного )))
sub some {return}
warn Dumper {
some => some,
some => some,
};
warn Dumper {
some, some,
some, some,
};
Продолжать можно долго )))))
Мда. Реализация PHP адова. mod_php нихрена не mod, fcgi нихрена не fcgi.
Как это должно происходить. Стартовый скрипт должен заинклюдить как можно больше модулей. Потом этот жирный процесс форкается много раз, за счет чего экономится память. После этого каждый процесс в бесконечном цикле обрабатывает запросы. Да, приходится немного поплясать с бубном, следить за базаром и после каждого запроса обнулять кучу переменных, но оно того стоит. FGCI по большому счету то же самое. Эти технологии были придуманы, чтобы сэкономить время на подгрузке модулей и на компилировании исходника. mod_perl так и работает кстати.
В случае с PHP на каждый запрос компилируется исходник и выполняется. Отсюда масса времени уходит на подгрузку модулей и на компиляцию. Все эти акселераторы и кешеры кода по большому счету и обеспечивают более менее подобие работы нормального mod или FCGI.
Вывод: все описанные проблемы и бубны следствие не правильной архитектуры самого языка.
Я смотрю тут перловики со стажем :)
C-style тут не при чем, сейчас докажу :) Он конечно медленнее range, но не трагически.
Этот кусок перлкода можно ускорить раза в полтора, тупо объявив все переменные локальными.
Не забывайте use strict; Он конечно жрет часть памяти и производительности, но это стоит того, эти потери много меньше, чем от пропущенного my ;)
Ну и использование контексных переменный чуть-чуть ускоряет.
Про use integer уже сказали, его можно применять контекстно. Да и хак это такой же, как на Java вместо float использовать int ;)
#~ use strict;
use Benchmark;
Benchmark::timethese(1_000, {
'A' => sub {
#~ use integer;
$r = 0;
for ($i = 0; $i < 100; $i++) {
for ($j = 0; $j < 100; $j++) {
$r = ($r + ($i * $j) % 100) % 47;
}
}
},
'B' => sub {
#~ use integer;
my $r = 0;
for (my $i = 0; $i < 100; $i++) {
for (my $j = 0; $j < 100; $j++) {
$r = ($r + ($i * $j) % 100) % 47;
}
}
},
'C' => sub {
#~ use integer;
my $r = 0;
for my $i (0..99) {
for my $j (0..99) {
$r = ($r + ($i * $j) % 100) % 47;
}
}
},
'D' => sub {
#~ use integer;
my $r = 0;
for my $i (0..99) {
$r = ($r + ($i * $_) % 100) % 47 for 0..99;
}
},
});
У нас же не один демон мемкеша :) Для каждого типа сущности свой кеш, или даже несколько кешей. Сейчас у нас 20 мемкешей. Так что там все нормально. А держать все в мемкешах просто приходится. От этого никуда не денешься.
Ну судя по графикам во всех мемкешах лежит что-то около 7М ключей. Это примерно половина всех сущностей, вторая половина, видимо, не востребована )
Строить хеш совершенно не интересно )
Ну у нас в среднем 12М хитов в сутки и подобное решение вымерло бы очень быстро :) Тем более при конкурентном доступе. Даже при размере кешхеадера в 100Кб это решение оказалось бы узким местом.
Я считаю, что вы где-то в архитектуре приняли неверное решение. При обновлении того же списка комментариев, куда менее затратно обновить все необходимые значения в кеше, чем почистить кеш и подкинуть работы базе данных. Кеш обычно вводится, когда база или какой-то ресурсоемкий код оказывается узким местом. И решение задачи типа «выльем воду из чайника, чем сведем задачу к предыдущей» в данном случае выглядит странным.
Меня больше настораживает другое, что я описал в комменте ниже.
Как бы допоперация поиска стоит не так много. Тот же механизм блокировок через memcached чего стоит ))) Это не жалко, да и времени не так много займет. А вот передача пожирневшего «кешхеадер» будет стоить достаточно дорого :) Не столько процессорного времени, сколько iowait. А это может оказаться очень неприятно )
Т.е. вы предлагаете хранить структуру, которая помнит о всех объектах, хранящихся в кеше?
А если структура вырастет? По личному опыту знаю, что если в memcached класть данные размером порядка 1Мб, то это чревато частыми ошибками записи (причем почему-то больше записи) или чтения этих данных из кеша. К тому же передавать мегабайт данных по сети это далеко не мгновенно (если кеш находится на другой машине).
Иными словами если ваш «кешхеадер» разростется, это приведет к тормозам, которые будет трудно найти :)
Все сказанное мной относится к очень нагруженному проекту. На не очень больших нагрузках этого может и не случаться.
P.S.: если memcached начинает вытеснять данные, это сигнал, что в архитектуре допущен косячок :) Это не критично, но лучше такого не далать. Хотя бы из чувства прекрасного )))
PPS: Если у вас достаточно серьезный проект и вам нужен специфический функционал, то лучше будет взять исходники memcached и дописать то, что необходимо. Оно будет того стоить )
memcached устроен так, что он совершенно не тратит ресурсы на поиск данных, другими словами, скорость поиска нужного значения не зависит от количества данных в memcached.
Использовать мемкеш для хранения структур данных это вполне жизнеспособная и распространенная практика ). memcachedb это все тот же memcache, только данные он хранит не в памяти, а на диске, используя движок BDB.
TMTOWTDI во всей красе ))
Второй вариант кстати проще к понимаю что происходит. Конечно при условии, что знаешь, что не истинное логическое выражение возвращает пустую строку, а истинное единицу )))
Я не люблю строить такие логические цепочки. Хотя вру. Люблю, но только с || или or ))) Они как-то понятнее смотрятся ) Да и применение находят чаще )
perl -MData::Dumper -e 'warn Dumper [map {$_ if $_ == 4} 1..10];'
Без интерпретатора не так просто угадать результат )))
Из той же оперы:
sub some {return 'A' if 0} что вернет?
Или еще из прекрасного )))
sub some {return}
warn Dumper {
some => some,
some => some,
};
warn Dumper {
some, some,
some, some,
};
Продолжать можно долго )))))
Если что, то для меня все примеры понятны :)
Поигравшись с last (кстати next ведет себя так же в ваших примерах и коментариях ниже) сообразил для себя прикольный финт ушами :)
if (1) {{
print 1;
next if 1;
print 2;
}};
Мне всегда не хватало такой конструкции )))
Но что такое контекст забывать нельзя :) А Perl это контекстный язык %)
Правильно будет:
perl -MData::Dumper -e '@a = map { my $x = $_; +{$x => $x} } qw/a b/; print Dumper(\@a)'
Как это должно происходить. Стартовый скрипт должен заинклюдить как можно больше модулей. Потом этот жирный процесс форкается много раз, за счет чего экономится память. После этого каждый процесс в бесконечном цикле обрабатывает запросы. Да, приходится немного поплясать с бубном, следить за базаром и после каждого запроса обнулять кучу переменных, но оно того стоит. FGCI по большому счету то же самое. Эти технологии были придуманы, чтобы сэкономить время на подгрузке модулей и на компилировании исходника. mod_perl так и работает кстати.
В случае с PHP на каждый запрос компилируется исходник и выполняется. Отсюда масса времени уходит на подгрузку модулей и на компиляцию. Все эти акселераторы и кешеры кода по большому счету и обеспечивают более менее подобие работы нормального mod или FCGI.
Вывод: все описанные проблемы и бубны следствие не правильной архитектуры самого языка.
Какой смысл в переменной $r?
Спасибо за наводку, возможно пригодится )
* Sign Up * Login * ????: Русский
А вот с русским там проблемы ) Причем как-то местами…
C-style тут не при чем, сейчас докажу :) Он конечно медленнее range, но не трагически.
Этот кусок перлкода можно ускорить раза в полтора, тупо объявив все переменные локальными.
Не забывайте use strict; Он конечно жрет часть памяти и производительности, но это стоит того, эти потери много меньше, чем от пропущенного my ;)
Ну и использование контексных переменный чуть-чуть ускоряет.
Про use integer уже сказали, его можно применять контекстно. Да и хак это такой же, как на Java вместо float использовать int ;)
#~ use strict;
use Benchmark;
Benchmark::timethese(1_000, {
'A' => sub {
#~ use integer;
$r = 0;
for ($i = 0; $i < 100; $i++) {
for ($j = 0; $j < 100; $j++) {
$r = ($r + ($i * $j) % 100) % 47;
}
}
},
'B' => sub {
#~ use integer;
my $r = 0;
for (my $i = 0; $i < 100; $i++) {
for (my $j = 0; $j < 100; $j++) {
$r = ($r + ($i * $j) % 100) % 47;
}
}
},
'C' => sub {
#~ use integer;
my $r = 0;
for my $i (0..99) {
for my $j (0..99) {
$r = ($r + ($i * $j) % 100) % 47;
}
}
},
'D' => sub {
#~ use integer;
my $r = 0;
for my $i (0..99) {
$r = ($r + ($i * $_) % 100) % 47 for 0..99;
}
},
});
>perl math.pl
Benchmark: timing 1000 iterations of A, B, C, D…
A: 5 wallclock secs ( 5.04 usr + 0.00 sys = 5.04 CPU) @ 198.49/s (n=1000)
B: 4 wallclock secs ( 3.82 usr + 0.00 sys = 3.82 CPU) @ 261.64/s (n=1000)
C: 4 wallclock secs ( 3.54 usr + 0.00 sys = 3.54 CPU) @ 282.41/s (n=1000)
D: 3 wallclock secs ( 3.26 usr + 0.00 sys = 3.26 CPU) @ 306.65/s (n=1000)
>Exit code: 0 Time: 16.124
PS: Пардон за форматирование, теги не работают :(
У нас же не один демон мемкеша :) Для каждого типа сущности свой кеш, или даже несколько кешей. Сейчас у нас 20 мемкешей. Так что там все нормально. А держать все в мемкешах просто приходится. От этого никуда не денешься.
Строить хеш совершенно не интересно )
Я считаю, что вы где-то в архитектуре приняли неверное решение. При обновлении того же списка комментариев, куда менее затратно обновить все необходимые значения в кеше, чем почистить кеш и подкинуть работы базе данных. Кеш обычно вводится, когда база или какой-то ресурсоемкий код оказывается узким местом. И решение задачи типа «выльем воду из чайника, чем сведем задачу к предыдущей» в данном случае выглядит странным.
Как бы допоперация поиска стоит не так много. Тот же механизм блокировок через memcached чего стоит ))) Это не жалко, да и времени не так много займет. А вот передача пожирневшего «кешхеадер» будет стоить достаточно дорого :) Не столько процессорного времени, сколько iowait. А это может оказаться очень неприятно )
А если структура вырастет? По личному опыту знаю, что если в memcached класть данные размером порядка 1Мб, то это чревато частыми ошибками записи (причем почему-то больше записи) или чтения этих данных из кеша. К тому же передавать мегабайт данных по сети это далеко не мгновенно (если кеш находится на другой машине).
Иными словами если ваш «кешхеадер» разростется, это приведет к тормозам, которые будет трудно найти :)
Все сказанное мной относится к очень нагруженному проекту. На не очень больших нагрузках этого может и не случаться.
P.S.: если memcached начинает вытеснять данные, это сигнал, что в архитектуре допущен косячок :) Это не критично, но лучше такого не далать. Хотя бы из чувства прекрасного )))
PPS: Если у вас достаточно серьезный проект и вам нужен специфический функционал, то лучше будет взять исходники memcached и дописать то, что необходимо. Оно будет того стоить )