Пятница, поздний вечер. Все идет хорошо, ничто не предвещает беду. Внезапно Вам сообщают, что галерея на Вашем сайте не работает. Хотя ведь работала, черть подери!!!
Судорожно смотришь в svn log, кто что делал за последние пол-дня. Хм, вроде бы чисто, никто не трогал галерею. Хотя…
В одном из базовых скриптов участвующих в формировании линков на AJAX-запросы для конкретной страницы видим:
switch($alias){//много много кейсов//...case'galleryData':$link='/gallery.php?action=galleryData';case'fooBarCheck':$link='/main/foobarcheck';break;
Кто-то похерил break у кейса ‘galleryData’ и теперь даже если $alias равен ‘galleryData’, исполнение пойдет далее и $link переприсвоится и станет ‘/main/foobarcheck’.
Повезло, что проблему так быстро выявили и пофиксили.
Занятно, что в новомодных языках, таких как Go эту проблему решили на корню: проход сквозь несколько веток свитча запрещен на уровне языка. Если же требуется такое поведение (что случается крайне редко), то нужно использовать ключевое слово fallthrough:
“In a switch statement, case labels do not fall through. You can make them fall through using the fallthrough keyword. This applies even to adjacent cases.”
В Perl же аналогичного поведения можно добиться используя явное указание ключевого слова next или же используя use Switch ‘fallthrough’;.
Линк на доку.
Нашел интересный пост на stackoverflow касаемо т.н. “Branch prediction”. Примеры на С++, Яве, С#, Go есть, но захотелось потестить локально Perl, PHP и новый язык от компании Mozilla - Rust.
О них и поговорим ниже.
Первым идет переписка программы на Perl:
#!/usr/bin/perlusestrict;useModern::Perl;my$array_size=32768;my@data;#prepare datafor(my$c=0;$c<$array_size;++$c){$data[$c]=int(rand(256))+1;}sub calc{my($data_ref,$times)=(shift,shift);my$sum=0;for(my$i=0;$i<$times;++$i){formy$v(@$data_ref){if($v>=128){$sum+=$v;}}}return$sum;}say"estimate with not sorted array";my$start=time();my$result=calc(\@data,100000);my$elapsed=time()-$start;say"sum: $result";say"elapsed time: $elapsed seconds";say"estimate with sorted array";my@sorted_data=sort{$a<=>$b}@data;$start=time();$result=calc(\@sorted_data,100000);$elapsed=time()-$start;say"sum: $result";say"elapsed time: $elapsed seconds";
Ниже аналогично на PHP:
<?phpfunctioncalc(&$arr,$times){$sum=0;for($i=0;$i<$times;++$i){foreach($arras$v){if($v>=128){$sum+=$v;}}}return$sum;}//prepare array$array_size=32768;$data=array();for($c=0;$c<$array_size;++$c){$data[]=rand(1,256);}print"estimate with not sorted array\n";$start=time();$sum=calc($data,100000);$elapsed=time()-$start;echo"elapsed time: ".$elapsed." seconds\n";echo"sum: ".$sum."\n";print"estimate with sorted array\n";sort($data);$start=time();$sum=calc($data,100000);$elapsed=time()-$start;echo"elapsed time: ".$elapsed." seconds\n";echo"sum: ".$sum."\n";
и на закуску экзотика в лице языка Rust:
externmodstd;userand=core::rand;fncalculate(d:&[int],iterations_cnt:uint)->u64{letmutsum:u64=0asu64;foriterations_cnt.times{ford.each|val|{if*val>=128{sum+=*valasu64;}}}returnsum;}fnmain(){//prepare dataletarray_size=32768;letmutdata:~[int]=~[];vec::reserve(&mutdata,array_size);letr=rand::Rng();forarray_size.times{data.push(r.gen_int_range(1,256)+1);}letiterations_count=100000;io::println("estimate with not sorted array");letmutstart=std::time::precise_time_s();letmutresult=calculate(data,iterations_count);letmutstop=std::time::precise_time_s();io::println(u64::str(result));io::println(#fmt("elapsed time: %f ms", (stop - start) * 1000f));purefnleual(a:&int,b:&int)->bool{*a<=*b}letsorted_data=std::sort::merge_sort(leual,data);io::println("estimate with sorted array");start=std::time::precise_time_s();result=calculate(sorted_data,iterations_count);stop=std::time::precise_time_s();io::println(u64::str(result));io::println(#fmt("elapsed time: %f ms", (stop - start) * 1000f));}
Также для полноты картины и для того, чтобы было с чем сравнивать, прогнал исходную программу на С++ у себя на компе.
На моем Core2Duo E6600 2.4 GHZ и с 4 гигами оперативки имеем сл. результаты:
Today I decided to refresh my knowledge of PHP (sick!). Here’s a PHP verson of the problem that has been discussed few posts ago:
<?php$src='{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение '.'{изменялось {быстро|мгновенно} случайным образом|менялось каждый раз}';while(preg_match("/\{([^\{\}]*)\}/",$src,$matches)){$alt_items=explode("|",$matches[1]);$item=$alt_items[array_rand($alt_items)];$src=str_replace($matches[0],$item,$src);}print$src;