Jako třetí parametr file_put_contents() zkus uvést konstantu LOCK_EX
Používám téměř výhradně tyto dvě funkce, ostatní jsem odstavil jako nepotřebné. Výsledky po úpravě volání mě zajímají.
file_put_contents("523.txt",$s,LOCK_EX);
Ještě bych k tomu dodal, že pokud ty funkce používají buffering na úrovni souborového systému, což předpokládám, není nutné se obávat nespolehlivosti a nekonzistence. Ukaž příklad, kdy k něčemu takovému došlo a rozebereme příčiny. Bez zámků se to stává jen u souborů >8 KiB.
echo "file_get_contents/file_put_contents test ".time()."<br>";
die;
while ( time()<1570604800 )
{
usleep(500);
}
$file = "temp.jpg";
echo "<h4>523 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("523");
file_put_contents("523.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>948 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("948");
file_put_contents("948.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>1371 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("1371");
file_put_contents("1371.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>1913 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("1913");
usleep( 50 );
file_put_contents("1913.txt",$s,LOCK_EX);
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>2701 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("2701");
file_put_contents("2701.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>4495 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("4495");
file_put_contents("4495.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>6758 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("6758");
usleep( 50 );
file_put_contents("6758.txt",$s,LOCK_EX);
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "flock test ".time()."<br>";
die;
while ( time()<1570612500 )
{
usleep(500);
}
$file = "temp.jpg";
echo "<h4>523 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("523.txt");
file_put_contents("523.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>948 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("948.txt");
file_put_contents("948.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>1371 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("1371.txt");
file_put_contents("1371.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>1913 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("1913.txt");
usleep( 50 );
file_put_contents("1913.txt",$s,LOCK_EX);
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>2701 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("2701.txt");
file_put_contents("2701.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>4495 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("4495.txt");
file_put_contents("4495.txt",$s,LOCK_EX);
usleep( 50 );
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
echo "<h4>6758 at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$s = file_get_contents("6758.txt");
usleep( 50 );
file_put_contents("6758.txt",$s,LOCK_EX);
$time_elapsed_secs = microtime(true) - $start;
echo "time: $time_elapsed_secs s<br>";
}
$s = file_get_contents("523");
Tohle čte ze souboru, který zřejmě neexistuje.
Souborové systémy mají vlastní buffery a cache. Zkus z jednoho procesu neustále modifikovat jeden soubor a z druhého ho číst. Uvidíš, že je to spolehlivé.
V T2 máš chybuKód: [Vybrat]$s = file_get_contents("523");
Tohle čte ze souboru, který zřejmě neexistuje.
Nevím sice, o co se pokoušíš, ale obávám se, že ses vydal chybnou cestou. Pokud ti dělají starosti kolize, měl bys použít databázi, která se o takové problémy sama postará a k tomu ti nabídne luxusní přístupové metody. PHP v základní výbavě nabízí 5 různých databází, ze kterých si určitě vybereš.
Takže co je účelem zkoumání čtení a zápisu souborů? Konfigurace, blog, diskuzní fórum, ... ?
523 0,00251909
948 0,000630766
1371 0,002995359
1913 0,006401292
2701 0,002551624
4495 0,002908468
6758 0,019312313
a T4:Nevím sice, o co se pokoušíš, ale obávám se, že ses vydal chybnou cestou. Pokud ti dělají starosti kolize, měl bys použít databázi, která se o takové problémy sama postará a k tomu ti nabídne luxusní přístupové metody. PHP v základní výbavě nabízí 5 různých databází, ze kterých si určitě vybereš.
Takže co je účelem zkoumání čtení a zápisu souborů? Konfigurace, blog, diskuzní fórum, ... ?
Takže přiznáváš, že u funkcí file_get_contents a file_put_contents existuje riziko kolize. Protože z tvého příspěvku to vyplývá. Se stejným přístupem mlžit a neříct to explicitně jsem se potkal na více místech internetu. To je ten důvod, proč jsem se vydal tou cestou, abych to prozkoumal. Jestliže považuješ file_get_contents a file_put contents za natolik nespolehlivé, že chceš raději používat databázi, nepřímo mi tím potvrzuješ výsledek mého zkoumání. Ale chtěl bych to slyšet explicitně, něco jako "Ano, už to tak asi bude" nebo "Z výsledků to vyplývá" nebo "Nevěřím tomu, jdu si to ověřit"... To je taky možnost.
Myslím že ten rozdíl v rychlosti T2 a T3/T4 dokazuje, že T3 a T4 neprovádí bezpečné čtení a zápis.
Problém je, pokud soubor přečteš, modifikuješ a uložíš. Tyto tři úkony nejsou v jedné transakci a proto při souběhu můžeš přijít o data.
Myslím že ten rozdíl v rychlosti T2 a T3/T4 dokazuje, že T3 a T4 neprovádí bezpečné čtení a zápis.
Nedokazuje to vůbec nic.
Problém je, pokud soubor přečteš, modifikuješ a uložíš. Tyto tři úkony nejsou v jedné transakci a proto při souběhu můžeš přijít o data.Díky. To mi bohatě stačí. Proč ale tyto informace nejsou uvedeny v manuálu. To je přece důležitá informace. Když do googlu zadám např. "php file_get_contents you can lose data" tak nenajdu nic s tímto výskytem. Takže očividně se tato informace tají. Jak jinak si vysvětlit, že před tímto nezbytným faktem nevarují?
Zajímavé je ale to, že v manuálu těch funkcí není nic o tom, že data jsou bufferované.Ale jo, dokazuje to přesně to co si říkal. Je totiž z toho patrné, že ty data se nečtou z disku (rozuměj - z plotny), ale z bufferu.Myslím že ten rozdíl v rychlosti T2 a T3/T4 dokazuje, že T3 a T4 neprovádí bezpečné čtení a zápis.Nedokazuje to vůbec nic.
Díky moc za odpovědi. Moc jsem se poučil a teď už mám klid. Takže teď už vím, že file_get_contents a file_put_contents jsou vlastně k ničemu. Neumím si představit k čemu bych je využil, když existuje riziko, že dva lidé odešlou do stejného souboru data, ale uloží se jen jeden, ten druhej ne. Je to úleva.
PS: Tys nikdy nedělal kočku v mikrovlnce? ;D
if file exists jirka do:
copy jirka jirka.backup
rename jirka jirka.2
open jirka.2
read jirka.2
add jirka.2
save jirka.2
close jirka.2
rename jirka.2 jirka
else:
while (delay) do:
if file jirka exists do ...
endwhile;
endif;
Dík za článek. A proč prostě soubor nepřejmenovat?
Dík za článek. A proč prostě soubor nepřejmenovat?
Přejmenování se pro docílení atomicity skutečně používá. V daném případě musíš ještě ošetřit situaci, kdy proces přejmenuje soubor a následně chcípne. Co teď?
Dal by se do toho zakomponovat i test if jirka.2 exists do:
Dík za článek. A proč prostě soubor nepřejmenovat?To mě nepřijde jako dobré řešení. Více procesů ve stejnou chvíli může vyhodnotit první řádek jako true a budou chtít provádět copy, rename.... Ten co bude o setinku pomalejší vyhodí chybu. Já jsem kdysi používal zámek pomocí vytváření a ověřování adresáře, protože mkdir je atomická a rychlá funkce. Pro permanentní zápisy do souboru je nejlepší databáze, tak jak ti Kid už napsal.Kód: [Vybrat]if file exists jirka do:
Vtip je v tom, že pokud se se souborem pracuje, tak k němu žádný jiný program/skript nemůže. Je to geniálně jednoduché a nevyžaduje to zámky.
copy jirka jirka.backup
rename jirka jirka.2
open jirka.2
read jirka.2
add jirka.2
save jirka.2
close jirka.2
rename jirka.2 jirka
else:
while (delay) do:
if file jirka exists do ...
endwhile;
endif;
Dal by se do toho zakomponovat i test if jirka.2 exists do:
Dík za článek. A proč prostě soubor nepřejmenovat?To mě nepřijde jako dobré řešení. Více procesů ve stejnou chvíli může vyhodnotit první řádek jako true a budou chtít provádět copy, rename.... Ten co bude o setinku pomalejší vyhodí chybu. Já jsem kdysi používal zámek pomocí vytváření a ověřování adresáře, protože mkdir je atomická a rychlá funkce. Pro permanentní zápisy do souboru je nejlepší databáze, tak jak ti Kid už napsal.Kód: [Vybrat]if file exists jirka do:
Vtip je v tom, že pokud se se souborem pracuje, tak k němu žádný jiný program/skript nemůže. Je to geniálně jednoduché a nevyžaduje to zámky.
copy jirka jirka.backup
rename jirka jirka.2
open jirka.2
read jirka.2
add jirka.2
save jirka.2
close jirka.2
rename jirka.2 jirka
else:
while (delay) do:
if file jirka exists do ...
endwhile;
endif;
Dal by se do toho zakomponovat i test if jirka.2 exists do:
Mě připadá že vytváření adresáře je složitější proces než přejmenování.Myslím, že jsem se rozhodl pro mkdir, protože mě to někdo doporučil jako nejrychlejší atomickou funkci vhodnou k zamykání souborů. Předpokládám, že zamykat soubor potřebuješ především kvůli kolizi více procesů při zápisu, ale né při čtení. Pokud použiješ rename, tak si daný soubor zablokuješ i pro procesy, které si chtějí jen číst a nehodlají zapisovat, resp. musel bys i ve čtecích funkcích ošetřit, že se soubor může jmenovat jirka nebo jirka.2.
function atomicFuse($n, $c, $disableDelay = false){
$start = false;
if ( !file_exists("$n.t") )
$start = mkdir("$n.t");
if ( !$disableDelay ){
if ( $start == false )
{
$n = $n*30;
switch($c): // Delay example increase:
case 0: break; // 0,01569 total
case 1: break; // 0,03138 total
case 2: $n = $n*2; break; // 0,06276 total
case 3: $n = $n*4; break; // 0,12552 total
// case 4: You need at least *6 or *8 to get out of problems with extrem times
case 4: $n = $n*6; break; // 0,21966 t.(upper limit)
case 5: $n = $n*6; break; // 0,3138 total extrem
case 6: $n = $n*4; break; // 0,36087 total extrem
case 7: $n = $n*4; break; // 0,42363 total extrem
default: break;
endswitch;
usleep($n);
echo ($n)."<br>";
}
}
return $start;
}
$start = atomicFuse($n,0);
if (!$start) $start = atomicFuse($n,1);
if (!$start) $start = atomicFuse($n,2);
if (!$start) $start = atomicFuse($n,3);
if (!$start) $start = atomicFuse($n,4);
if (!$start) $start = atomicFuse($n,5);
if (!$start) $start = atomicFuse($n,6);
if (!$start) $start = atomicFuse($n,7);
if (!$start) $start = atomicFuse($n, false);
if (!$start) echo "<b>Atomicity failed.</b> ";
if ( $start )
{
echo "<b>Atomicity OK.</b> ";
// perform atomic action
$success = rmdir("$n.t"); // remove atomic fuse
}
function atomicFuse($n, $c, $disableDelay = false){
$start = false;
if ( !file_exists("$n.t") )
$start = mkdir("$n.t");
if ( !$disableDelay ){
if ( $start == false )
{
$n = $n*30;
switch($c): // Delay example increase:
case 0: break; // 0,01569 total
case 1: break; // 0,03138 total
case 2: $n = $n*2; break; // 0,06276 total
case 3: $n = $n*4; break; // 0,12552 total
// case 4: You need at least *6 or *8 to get out of problems with extrem times
case 4: $n = $n*8; break; // 0,25104 t.(upper limit)
// In case of heavy traffic:
case 5: $n = $n*8; break; // 0,36087 total extrem
case 6: $n = $n*10; break; // 0,51777 total extrem
case 7: $n = $n*20; break; // 1,03554 total extrem
default: $n = $n*8; break;
endswitch;
usleep($n);
echo ($n)."<br>";
}
}
return $start;
}
Můžeš mi prosím napovědět k čemu ten výsledek testu je? O čem ty čísla svědčí ve vztahu k tvému úvodnímu příspěvku?
Kód: [Vybrat]function atomicFuse($n, $c, $disableDelay = false){
$start = false;
if ( !file_exists("$n.t") )
$start = mkdir("$n.t");
...
if (@mkdir("$n.t")) {
// akce
rmdir("$n.t");
}
Vyloučíš tím kolizi.
Ta prodleva je zdrojem problémů u T8. ... V praxi stejně ke kolizi dojde málokdy a když k ní dojde tak ověřením ji mohu obnovit ze zálohy.Jestli se bavíme o situaci kdy máš soubor zamknutý, tak dokážeš ty "problémy" a "kolize" ke kterým dojde málokdy nějak jednoduše pojmenovat? Z toho co jsi psal před tím jsem to nepochopil. Jediný "problém" co mě napadá by měl být ten "maximum execution time" o kterém jsem psal. A pokud ti dochází k jiným kolizím při zamknutém souboru, tak bych řekl, že to zamykání máš špatně, např. kvůli tomu file_exists o kterém psal Kid (https://forum.root.cz/index.php?topic=21940.msg318442#msg318442).
$locked = flock($fp, LOCK_SH);
$s = fread($fp, $fsize );
$success = flock($fp, LOCK_UN);
$success = fclose($fp);
$fp = fopen($tname, "w");
$locked = flock($fp, LOCK_EX);
$success = fwrite($fp, $s);
$success = fflush($fp);
$success = flock($fp, LOCK_UN);
$success = fclose($fp);
$locked = flock($fp, LOCK_SH)
function atomicFuse($n, $c, $disableDelay = false){
$start = false;
if ( @mkdir("$n.t") )
$start = true;
if ( !$disableDelay ){
if ( $start == false )
{
$n = $n*30;
...
V té funkci je $start = true když je povoleno provádět atomicitní operaci jinak je false.Zamknuté to je. Stručně:Kód: [Vybrat]$locked = flock($fp, LOCK_SH);
$s = fread($fp, $fsize );
$success = flock($fp, LOCK_UN);
$success = fclose($fp);
$fp = fopen($tname, "w");
$locked = flock($fp, LOCK_EX);
$success = fwrite($fp, $s);
$success = fflush($fp);
$success = flock($fp, LOCK_UN);
$success = fclose($fp);
$fp = fopen($tname, "r+");
flock($fp, LOCK_EX);
$s = fread($fp, $fsize);
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, $s);
fclose($fp);
Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/
Začíná se mi pomalu vybavovat, proč jsem se tenkrát rozhodl využít pro zamykání mkdir ;)
Čím si vysvětluješ, že ani flock nepomůže k zajištění atomicity?Připadá mi, že se snažíte testovat nějaké bufferování nebo co, ale přitom máte zmatek v tom, co je atomicita a jak se používají zámky. Zámky nezajišťují atomicitu – zajistí jenom to, že ze/do souboru může současně číst/zapisovat jenom jeden proces. Nezajistí ale, že ten zápis bude atomický. Navíc vůbec nepředpokládáte, že získání zámku může selhat, ani že může selhat otevření souboru – myslím, že zrovna v těchto případech je to dost odvážný předpoklad.
Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/Mohl byste to rozepsat? Atomicita znamená, že se daná funkce provede celá nebo vůbec a že nikdo nemůže vidět nějaký vnitřní mezistav té funkce. V případě zámků atomicita znamená, že na souboru nějaký zámek je nebo není – nemůže nastat stav, že by tam zámek byl tak trochu. Atomicita se ale samozřejmě posuzuje z hlediska jedné funkce – to, že se něco může stát před voláním flock() nemá na atomicitu funkce flock() vliv.
Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.
Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.
Myslel jsem to tak, jak se píše v tom odkazu, tzn. že mezi fopen a flock se může dostat jiný proces. Spolehlivější mně připadá zapisování s file_put_contents, který může mít parametr LOCK_EX. (To samozřejmě v praxi neřeší problém čtení, kde mezi čtením a zápisem může druhý PHP proces zapsat do čteného souboru - tím dojde ke ztrátě dat z tohoto druhé PHP procesu, protože daný soubor v zápětí přepíše ten první PHP proces. Tohle si musí programátor ošetřit ručně.)Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/Mohl byste to rozepsat? Atomicita znamená, že se daná funkce provede celá nebo vůbec a že nikdo nemůže vidět nějaký vnitřní mezistav té funkce. V případě zámků atomicita znamená, že na souboru nějaký zámek je nebo není – nemůže nastat stav, že by tam zámek byl tak trochu. Atomicita se ale samozřejmě posuzuje z hlediska jedné funkce – to, že se něco může stát před voláním flock() nemá na atomicitu funkce flock() vliv.
Ano uklízení po mkdir() musíš ošetřit ručně. Nevím jak je to přesně u flock(), ale předpokládám, že i tam se ti zámek může seknout a pak musíš mít nějakou vlastní funkci, která ji natvrdo odblokuje.Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/V podstatě tam píší jen to, že mezi voláním fopen() a flock() si ten soubor může zamknout někdo jiný. Tedy nic, co by se nedalo ošetřit testem návratové hodnoty flock().
Začíná se mi pomalu vybavovat, proč jsem se tenkrát rozhodl využít pro zamykání mkdir ;)
Zamykání přes mkdir() má nevýhodu v tom, že když ten proces spadne, kdo to po něm uklidí?
Ano souhlasím, jen jsem narážel na to, že tady Exkalibr pořád háže nějaké čísla s počtem chyb, které mají jen tu vypovídací hodnotu, že to má špatně zamknuté. Jestli je tam 1 chyba nebo 30 chyb, tak je to jedno.Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.
V testech je naopak výhodné, pokud se ty procesy co nejvíc potlučou mezi sebou - proto jsou ty časové odstupy zbytečné a kontraproduktivní.
Myslel jsem to tak, jak se píše v tom odkazu, tzn. že mezi fopen a flock se může dostat jiný proces.To ale neznamená, že flock() není atomický.
Pokud bych to tedy měl říci přesně, tak flock() je atomická funkce, ale ke svému využití potřebuje fopen(), a spojení fopen()+flock() atomické není.To, že volání dvou funkcí po sobě není atomické, je naprostý základ. Bez pochopení téhle věci je zbytečné pokoušet se programovat cokoli se zámky nebo řešit nějakou atomicitu.
Ano uklízení po mkdir() musíš ošetřit ručně. Nevím jak je to přesně u flock(), ale předpokládám, že i tam se ti zámek může seknout a pak musíš mít nějakou vlastní funkci, která ji natvrdo odblokuje.Myslím, že flock není atomický - https://www.reddit.com/r/PHP/comments/9ec4tz/a_locking_file_cache_in_php/e6cqg19/V podstatě tam píší jen to, že mezi voláním fopen() a flock() si ten soubor může zamknout někdo jiný. Tedy nic, co by se nedalo ošetřit testem návratové hodnoty flock().
Začíná se mi pomalu vybavovat, proč jsem se tenkrát rozhodl využít pro zamykání mkdir ;)
Zamykání přes mkdir() má nevýhodu v tom, že když ten proces spadne, kdo to po něm uklidí?
Nevýhodu vidím v tom, že testem návratové hodnoty flock() vytvoříš smyčku mezi flock() a fopen(). Pokud bys pustil vytěžující scripty (o což se Exkalibr snaží), tak by se smyčka nemusela stihnout dokončit do konce běhu PHP scriptu a script by spadl. Pokud si uděláš vlastní funkcí pomocí mkdir(), tak ji zavoláš ještě před fopen().
Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.
Pokud skript spadne, tak spadne. Obvykle to ničemu nevadí a je to zcela běžné. Klient si ho spustí znovu.
Správně se to dělá tak, že se proces nejprve pokusí zamknout všechny soubory, které bude potřebovat ke své práci. Pokud některý ze zámků selže, všechny odemkne, počká náhodnou dobu a pokusí se znovu nasadit všechny zámky.
Pokud skript spadne, tak spadne. Obvykle to ničemu nevadí a je to zcela běžné. Klient si ho spustí znovu.
Pokud spadne tak tam zůstane ten vytvořený adresář, který nikdo nesmazal. Ten script pak nepůjde provést. Musel bych tam spouštět čas od času udržovací script, který by promazal ty staré adresáře - ale to je zase zátěž na víc a navíc to neřeší problém úplně. Protože nějakou dobu to spustit nepůjde.
Správně se to dělá tak, že se proces nejprve pokusí zamknout všechny soubory, které bude potřebovat ke své práci. Pokud některý ze zámků selže, všechny odemkne, počká náhodnou dobu a pokusí se znovu nasadit všechny zámky.Já bych ten soubor mohl mít jen jeden, ale pokud použiju rejstříky a indexy - další dva soubory pro urychlení parsování/hledání - tak to budou 3.
Viděl, ale je to pro mě nepřehledné a nechce se mi v tom vrtat, ale jen tak namátkou. V tom T7 co máš na stackoverflow.com vidím zhruba toto:Teď jsem opakoval T7 jen s 6 cyklama a jen ze dvou prohlížečů a přesto došlo ke 4 kolizím. Oproti tomu T8 s 10 cyklama ze čtyř firefoxů udělal jen 1 chybu ... za bez použití file_exists. Ale taky se dívám že výsledná doba čekání u toho selhání byla poměrně malá 0.864s.Tohle testování je k ničemu. Pokud nemáš správně zámky, tak pořád testuješ nezamknuté soubory a vůbec není podstatné kolik je tam chyb. Pokud paralelní php scripty pustíš přesně ve stejný okamžik, tak tam těch chyb bude teoreticky více než když je spustíš s malým časovým odstupem - časový odstup u takového testu sníží riziko překřížení mezi jednotlivými PHP procesy.
Ale ty zámky jsou přece nastaveny správně, copak si neviděl kód?
Kit, děláš mi to rozhodování čím dál těžší. Flock sice spolehlivý je, ale nezaručuje že mezi otevřením a flockem se k souboru, nedostane jiný proces. :o
Když ti více PHP procesů zároveň provede řádek "fopen $tname" a pak jeden proces přejde na řádek flock lock_ex, tak neskončí ti náhodou zbývající procesy hláškou "Couldn't get the lock!"?
Kit, děláš mi to rozhodování čím dál těžší. Flock sice spolehlivý je, ale nezaručuje že mezi otevřením a flockem se k souboru, nedostane jiný proces. :o
To vadí? Mně tedy ne.
Kit, děláš mi to rozhodování čím dál těžší. Flock sice spolehlivý je, ale nezaručuje že mezi otevřením a flockem se k souboru, nedostane jiný proces. :o
To vadí? Mně tedy ne.
Nabourává to ten script, takže není atomicitní.
Jestli myslíš tím "selhání zápisu" tento blok:Když ti více PHP procesů zároveň provede řádek "fopen $tname" a pak jeden proces přejde na řádek flock lock_ex, tak neskončí ti náhodou zbývající procesy hláškou "Couldn't get the lock!"?Všechny chyby, které nastaly jsem už popsal, jednalo se tam o selhání zápisu nic víc. Všechny hlášky mám ošetřené. flock neselhal ani jednou, vždy byl výsledek true.
$fsize = filesize($tname);
if ($original_size>$fsize)
{
echo "; <b>WRITE FAILED, restoring</b>;";
$original_fname = "$n";
$result = copy($original_fname, $tname);
if ($result == false )
die(" <b>TOTAL FAILTURE: copy failed.</b>");
else
echo " <b>RESTORED</b>;";
}
else
...
Jestli myslíš tím "selhání zápisu" tento blok:Když ti více PHP procesů zároveň provede řádek "fopen $tname" a pak jeden proces přejde na řádek flock lock_ex, tak neskončí ti náhodou zbývající procesy hláškou "Couldn't get the lock!"?Všechny chyby, které nastaly jsem už popsal, jednalo se tam o selhání zápisu nic víc. Všechny hlášky mám ošetřené. flock neselhal ani jednou, vždy byl výsledek true.Kód: [Vybrat]$fsize = filesize($tname);
if ($original_size>$fsize)
{
echo "; <b>WRITE FAILED, restoring</b>;";
$original_fname = "$n";
$result = copy($original_fname, $tname);
if ($result == false )
die(" <b>TOTAL FAILTURE: copy failed.</b>");
else
echo " <b>RESTORED</b>;";
}
else
...
tak $fsize používáš až po lock_un, takže zjišťuješ velikost souboru ve chvíli kdy do něj zapisuje jiný proces.
A jsi si jistý, že je možné správně zjistit velikost souboru, když je soubor otevřený pro zápis?
A jsi si jistý, že je možné správně zjistit velikost souboru, když je soubor otevřený pro zápis?Tím si jistý nejsem, to musíš vědět ty, je to tvůj domácí úkol :). Já jen vím, že zjišťování velikosti souboru, kdy do něj jiný proces zapisuje není správné, takže to vypadá, že nešlo o žádné skutečné chyby při zápisu, ale pouze jsi špatně srovnával velikost source a target souboru.
$success = fflush($fp);// flush output before releasing the lock
if ( $success === false )
echo "; flush FAILED; ";
$st = fstat($fp);
if ($original_size>$st['size'])
{
echo "; <b>WRITE FAILED, restoring</b>;";
OK kit, tak jsem to udělal, ale ke kolizím stále dochází:Kód: [Vybrat]$success = fflush($fp);// flush output before releasing the lock
if ( $success === false )
echo "; flush FAILED; ";
$st = fstat($fp);
if ($original_size>$st['size'])
{
echo "; <b>WRITE FAILED, restoring</b>;";
Je to tak nějak furt stejné.
Ten je o pár řádků výše, přece:
$locked = flock($fp, LOCK_EX);
Já jsem dával jen ukázku toho fstat, ne zámku
$locked = flock($fp, LOCK_EX);
if ( $locked ) { // acquire an exclusive lock
$success = fwrite($fp, $s);
if ( $success === false)
echo "; w FAILED;";
else
if ( $_DEBUG_ )
echo " $success B written; ";
$success = fflush($fp);// flush output before releasing the lock
if ( $success === false )
echo "; flush FAILED; ";
$success = flock($fp, LOCK_UN); // release the lock
if ( $success === false )
echo "; release FAILED; ";
$success = fclose($fp);
if ( $success === false )
echo "; fclose FAILED; ";
clearstatcache(); // needed for filesize and touch
$fsize = filesize($tname);
if ($original_size>$fsize)
{
echo "; <b>WRITE FAILED, restoring</b>;";
$original_fname = "$n";
$result = copy($original_fname, $tname);
if ($result == false )
die(" <b>TOTAL FAILTURE: copy failed.</b>");
else
echo " <b>RESTORED</b>;";
}
else
{
if ($fsize === 0)
echo "! THE FILE WAS NOT WRITTEN: data length: ".strlen($s)." fsize: $fsize RESOURCE: $fp<br>";
if ( $success )
touch("$tname",$fsize,$p);
}
} else echo "Couldn't get the lock!";
Mimo téma - Aneb jak to v reálu dopadne
10/2019 - Autor otázky vymyslí úžasnou funkci über cool atomickou
12/2019 - Předání zákazníkovi
01/2020 - První uživatelé začínají používat SW
02/2020 - Zákazník si začíná stěžovat na pomalost, "někdy" se stane, že vůbec nic nefunguje
03/2020 - Autor otázky dumá jak to "někdy" nasimulovat
04/2020 - Po neschopnosti nasimulovat SW přebírá jiný programátor... Se zděšením kouká co původní autor vymyslel, přepisuje s prstem v nose na file_put_contents
05/2020 - Zákazník je happy
Jiné řešení pro případ vzkazníku mě napadlo.
Odesílatel odešle zprávu do složky uživateli, ale ta se nezpracuje automaticky. Ta zpráva tam bude čekat jako samostatný soubor, dokud si uživatel nepřečte všechny zprávy (které se mu zařadí do souboru teprve až navštíví svojischránku). Tím pádem jde o stoprocentní atomicitu, protože jediný skript, který bude zapisovat data do souboru je ten jeho. Nevýhoda je že při velkém množství zpráv se může uchovávat velké množství souborů, které na linuxu mohou zabírat nevím kolik.
Flock sice spolehlivý je, ale nezaručuje že mezi otevřením a flockem se k souboru, nedostane jiný proces.To je naprosto normální, takhle se budou chovat všechny synchronizační mechanismy. Vždy je to založené na tom, že se pokusíte udělat nějakou exkluzivní akci, vyhodnotíte výsledek a zjistíte, zda se podařila, nebo zda perníček loupe i někdo jiný a musíte chvilku počkat a zkusit to znovu.
flock neselhal ani jednou, vždy byl výsledek true.Když chcete jako programátor řešit paralelní přístup k datům, tohle nemůžete nikdy napsat. To, že se vám nepodařilo nějaký souběh nasimulovat, vůbec neznamená, že nenastane hned při prvním spuštění na produkci.
A co takhle zkusit vyrobit jiný typ zámku, který by byl spolehlivější.Dám vám dobrou radu. Nepokoušejte se vymýšlet vlastní zámky, v tuto chvíli na to nemáte znalosti. Použijte nějakou běžně používanou databázi, která už má tyhle nízkoúrovňové věci vyřešené. Tam můžete studovat třeba to, jak fungují ACID transakce, jak jsou od sebe izolované – a na základě toho si začnete pomalu budovat představu o tom, co se může dít, když se stejnými daty pracuje několik programů nebo vláken souběžně.
Takže až vyřešíš problémy se zamykáním souborů, přejdi na databázi.Takhle to nebude fungovat, jedině opačně – nejprve se naučit používat prostředky databáze, které jsou jednodušší, a teprve pak se případně dostat k souborům.
Takže až vyřešíš problémy se zamykáním souborů, přejdi na databázi.Takhle to nebude fungovat, jedině opačně – nejprve se naučit používat prostředky databáze, které jsou jednodušší, a teprve pak se případně dostat k souborům.
flock neselhal ani jednou, vždy byl výsledek true.Když chcete jako programátor řešit paralelní přístup k datům, tohle nemůžete nikdy napsat. To, že se vám nepodařilo nějaký souběh nasimulovat, vůbec neznamená, že nenastane hned při prvním spuštění na produkci.
Kit: do databáze by se mi nevešlo všechno to co chci uložit. Ta databáze na freehostingu má jen 20 mB.
Jo k té databázi, styčí když k tomu použiju příkazy mysql_? Učit se za něco nového jako PDO se mi nechce.
Na jaké produkci? Já nejsem produkční studio!„Produkce“ je v IT slangové označení pro „produkční prostředí“, nebo také „ostré prostředí“ – prostředí, kde aplikace běží „na ostro“, připojují se k ní reální uživatelé, má reálná data atd. Tedy např. i ta vaše aplikace na free webhostingu. Vedle toho pak mohou existovat různá nedůležitá nebo méně důležitá prostředí – vývojová, testovací, integrační, akceptační apod.
Jak jsem psal, databázi určitě použiju, to jsem si už vyjasnil, ale rozhodně ne na ptákoviny jako je registrace a loginy, to zvládnu přes soubory […] Tady jednu kravinu abych programoval dva tři měsíce.Pokud si pro prkotiny jako registrace a loginy budete programovat vlastní databázi, opravdu vám to bude trvat dva tři měsíce, klidně i déle. Pokud se na tom budete metodou pokusu a omylu učit, jak se pracuje se soubory při konkurenčním přístupu a jak se zamykají, bude vám to trvat podstatně déle, než tři měsíce. A možná nakonec zjistíte, že když budete zamykat celé soubory, už s malým množstvím uživatelů na freehostingu narazíte na limity v počtu souběžně otevřených souborů nebo doby zpracování skriptu.
Na jaké produkci? Já nejsem produkční studio!„Produkce“ je v IT slangové označení pro „produkční prostředí“, nebo také „ostré prostředí“ – prostředí, kde aplikace běží „na ostro“, připojují se k ní reální uživatelé, má reálná data atd. Tedy např. i ta vaše aplikace na free webhostingu. Vedle toho pak mohou existovat různá nedůležitá nebo méně důležitá prostředí – vývojová, testovací, integrační, akceptační apod.
Zrovna problémy s konkurenčním přístupem se často vyskytují až od určitého množství současně pracujících uživatelů. Pokud řešíte webhosting zdarma, asi nebudete mít testovací prostředí, kde byste věrohodně simuloval souběžnou práci většího množství uživatelů. Takže na problémy se špatně napsaným konkurenčním přístupem můžete narazit až na ostrém serveru – až se vám začnou ztrácet data nebo se vám datový soubor poškodí.Jak jsem psal, databázi určitě použiju, to jsem si už vyjasnil, ale rozhodně ne na ptákoviny jako je registrace a loginy, to zvládnu přes soubory […] Tady jednu kravinu abych programoval dva tři měsíce.Pokud si pro prkotiny jako registrace a loginy budete programovat vlastní databázi, opravdu vám to bude trvat dva tři měsíce, klidně i déle. Pokud se na tom budete metodou pokusu a omylu učit, jak se pracuje se soubory při konkurenčním přístupu a jak se zamykají, bude vám to trvat podstatně déle, než tři měsíce. A možná nakonec zjistíte, že když budete zamykat celé soubory, už s malým množstvím uživatelů na freehostingu narazíte na limity v počtu souběžně otevřených souborů nebo doby zpracování skriptu.
A k tomu hostingu zdarma – slušný webhosting seženete už okolo 50 Kč za měsíc. Už jenom psaním těch podivuhodných testů jste propálil tolik času, že byste za to tu aplikaci provozoval několik let.
To je blbost, registraci si napíšu za týden.
To je blbost, registraci si napíšu za týden.Když vás baví psát týden něco, co můžete mít hotové za hodinu… Navíc už se tu dva dny snažíte přijít na to, jak se mají zamykat soubory, řešení stále nikde – a to zatím řešíte jen přidávání záznamů, ale ne aktualizaci nebo mazání nebo dokonce efektivní vyhledávání.
To je blbost, registraci si napíšu za týden.
Proč ne za hodinu?
To je blbost, registraci si napíšu za týden.Když vás baví psát týden něco, co můžete mít hotové za hodinu… Navíc už se tu dva dny snažíte přijít na to, jak se mají zamykat soubory, řešení stále nikde – a to zatím řešíte jen přidávání záznamů, ale ne aktualizaci nebo mazání nebo dokonce efektivní vyhledávání.
ne aktualizaci nebo mazání nebo dokonce efektivní vyhledávání.
A k tomu hostingu zdarma – slušný webhosting seženete už okolo 50 Kč za měsíc. Už jenom psaním těch podivuhodných testů jste propálil tolik času, že byste za to tu aplikaci provozoval několik let.
... jen 20MB. Taky jsem psal, že tu databázi použiju, ale rozhodně ne na registraci. A tento týden se databází rozhodně zabývat nebudu. To jakým tempem pracuju je moje věc, do toho vám nic není pane.
Myslím, že na Filipa útočíš neprávem. Snaží se ti slušně říct, že někdy je levnější za věci zaplatit než je mít zdarma. Až budeš starší příjdeš na to sám. Raději dát pár stovek ročně než přijít o několik víkendů kdy budeš řešit chyby v tom systému. Taky připočti častější výpadky na freehostingu ze kterého návštěvníci taky nebudou nadšeni. Existuje spousta koníčků a projektů co dělá člověk pro radost a nic na nich nevydělává.A k tomu hostingu zdarma – slušný webhosting seženete už okolo 50 Kč za měsíc. Už jenom psaním těch podivuhodných testů jste propálil tolik času, že byste za to tu aplikaci provozoval několik let.
Nedám ani korunu za web, který nevydělává, leda že by si za to návštěvníci ten hosting sami zaplatili. Ale u webu který nemá žádnou návštěvnost asi těžko. Navíc mě těmi svými blbými řečmi rozpalujete doběla. Soudíte druhé lidi podle sebe, jenže vy jste profík, můžete si dovolit strávit u počítače kolik času chcete. Vůbec jsem z těch vašich subjektivně laděných soudů znechucen. To je jak bavit se s blbým člověkem, už jsem vám říkal, že hosting placený nechci a ten neplacený má kapacitu jen 20MB. Taky jsem psal, že tu databázi použiju, ale rozhodně ne na registraci. A tento týden se databází rozhodně zabývat nebudu. To jakým tempem pracuju je moje věc, do toho vám nic není pane.
To nepotřebuju. Efektivní vyhledávání mám ale už dávno vyřešeno.Efektivní hledání v registrovaných uživatelích, které zapisujete do souboru na disk? To bych chtěl vidět…
Nedám ani korunu za web, který nevydělává, leda že by si za to návštěvníci ten hosting sami zaplatili. Ale u webu který nemá žádnou návštěvnost asi těžko. Navíc mě těmi svými blbými řečmi rozpalujete doběla. Soudíte druhé lidi podle sebe, jenže vy jste profík, můžete si dovolit strávit u počítače kolik času chcete. Vůbec jsem z těch vašich subjektivně laděných soudů znechucen. To je jak bavit se s blbým člověkem, už jsem vám říkal, že hosting placený nechci a ten neplacený má kapacitu jen 20MB. Taky jsem psal, že tu databázi použiju, ale rozhodně ne na registraci. A tento týden se databází rozhodně zabývat nebudu. To jakým tempem pracuju je moje věc, do toho vám nic není pane.Mně by to trvalo hodinu. Vám by to trvalo den, kdybyste si nechal poradit. Bude vám to trvat měsíce, když to budete dělat způsobem, jak to tady popisujete.
Raději dát pár stovek ročně než přijít o několik víkendů kdy budeš řešit chyby v tom systému. Taky připočti častější výpadky na freehostingu ze kterého návštěvníci taky nebudou nadšeni. Existuje spousta koníčků a projektů co dělá člověk pro radost a nic na nich nevydělává.
Jestli použiješ databáze vs. soubory; freehosting vs. placený; vlastní systém vs. Wordpress; to všechno záleží na tobě, ale zaplatit trochu peněz za něco co ti ušetří hodně práce je obecně správný přístup, vyjímkou snad je pokud jsi hodně mladý a i těch pár korun je pro tebe dost peněz.
Pokud nejste ochoten dát 50 Kč měsíčně, místo toho budete týdny něco programovat s nejistým výsledkem, znamená to, že váš čas nemá žádnou hodnotu.
Na druhou stranu bych ti vytkl, že jsi u nějakého freehostingu s tak mizernými parametry. Zkus hledat u konkurence, která je také zdarma a přitom má ty parametry (včetně databází) o jeden či dva řády lepší.
Na druhou stranu bych ti vytkl, že jsi u nějakého freehostingu s tak mizernými parametry. Zkus hledat u konkurence, která je také zdarma a přitom má ty parametry (včetně databází) o jeden či dva řády lepší.Nechci se znovu nachytat. Neznám je a bez doporučení se sotva mohu pouštět do experimentů. Nechci zažít druhé Moxo.
Pokud by za hosting platil 50 Kč měsíčně, měl by naprosto stejné problémy se zamykáním souborů, jaké tady řeší. Cena za hosting v tom nehraje roli.Nikoli, stejné problémy by neměl. Nebyl by omezený limitem 20 MB na databázi, takže by se nepokoušel bez jakýchkoli znalostí naprogramovat vlastní databázi, ale použil by tu, kterou nabízí webhosting.
Dík Kite za zastání. A to jsem nezmínil, že by těch projektů klidně časem mohlo být víc. Platit za něco co slouží druhým a mě ne, proč bych to měl platit? Ať si to platí sami. Anebo ať mi to zaplatí ten pán co mi tak doporučuje placený hosting, když má tolik peněz na sponzorování nekomerčních projektů.Jenže vy za to platíte svým časem, a to daleko víc, než kolik byste zaplatil za ten hosting. Navíc to zatím nevypadá, že byste se blížil k cíli – o konkurenčním přístupu k souborům toho nevíte o nic víc, než na začátku. A upřímně řečeno, nemyslím si, že byste se to mohl naučit z komentářů na diskusním fóru a generováním náhodných testů, které se s podstatou zamykání souborů míjí.
Pokud by za hosting platil 50 Kč měsíčně, měl by naprosto stejné problémy se zamykáním souborů, jaké tady řeší. Cena za hosting v tom nehraje roli.Nikoli, stejné problémy by neměl. Nebyl by omezený limitem 20 MB na databázi, takže by se nepokoušel bez jakýchkoli znalostí naprogramovat vlastní databázi, ale použil by tu, kterou nabízí webhosting.
Jenže vy za to platíte svým časem, a to daleko víc, než kolik byste ...
Kit, mám dotaz. Aktuálně mám dva oddělené bloky, jeden čte, druhý zapisuje. To by nejspíš bylo lepší sloučit do jednoho, tak co to otevřít s fopen w+? Tím se vyřeší problém té narušené atomicity scriptu ne? Akorád po načtení pomocí fread musím převinout na začátek souboru ne?Převiň na začátek téhle diskuze a přečti si ji.
Kit, mám dotaz. Aktuálně mám dva oddělené bloky, jeden čte, druhý zapisuje. To by nejspíš bylo lepší sloučit do jednoho, tak co to otevřít s fopen w+? Tím se vyřeší problém té narušené atomicity scriptu ne? Akorád po načtení pomocí fread musím převinout na začátek souboru ne?
takže r+ , ale tím jsem přepsal původní soubor, už to je úplně odlišný algoritmus.
Na začátku téhle diskuse jsem pracoval s odlišným souborem, zdroj a cíl byly odlišné soubory. Četl jsem z jednoho a zapisoval do druhého. Teď jsem ten algoritmus změnil, takže čtu z toho, do kterého jsem zapisoval. Což mimochodem znamená, že jsem musel implementovat dva adresářové locky, jeden na zazálohování souboru a druhý na jeho obnovu když dojde k selhání.
Ať si to platí sami.Ano ať si to platí, ale to jim musíš říct ty a vysvětlit jim, že se s tím nebudeš drbat 10x déle jenom, aby ušetřili pár svých stokorun. Vzpomínám si na jednu reportáž jak "sběrači" kovů týden kopali měděné kabely a dostali za to 1000 Kč, pak se na ten hluboký výkop díval majitel stavební firmy a říká: "Kdyby se ti kopáči u mě nechali zaměstnat, tak si za to kopání vydělají 5000 Kč". Ale jestli tohle vše děláš kvůli učení a zkoumání, pak to beru.
Pokud se učí a zkoumá vlastnosti souborových systémů na hostingu, který neptá peníze, tak ho nechej být.Pokud jde o zkoumání a učení se, pak proti tomu nic nemám. Ale i při učení platí efektivita, např. raději koupit učebnici za 500 Kč než brouzdat po netu a učením strávit o rok déle. Pokud mu freehosting pro jeho potřeby poskytne to samé co placený, tak ať vezme free, ale podle toho co Exkalibr napsal jsem měl pocit, že ho bude limitovat a výsledkem těch limitů bude o hodně více stráveného času. Ale jak říkám pokud zkoumá a učí se, tak nic proti.
Sqlite nemá administrátorské prostředí ne? Nebo se to změnilo od těch dob co existovalo Moxo?
Doporučíš mi nějaký hosting?
Sqlite nemá administrátorské prostředí ne?
Na endoru jsem se kdysi díval a byla omezená trafikem. Pokud se nepletu. Už jsem se před časem díval ale to bylo mnoho lez zpátky a narážel jsem na samé limity. Například limit odeslaných požadavků na server databáze.
přidávání dat do souboru pomocí fopen(filename, "a") je taky neatomicitní?
file_put_contents($filename, $data, FILE_APPEND | LOCK_EX);
přidávání dat do souboru pomocí fopen(filename, "a") je taky neatomicitní?
Zkus raději podle manuáluKód: [Vybrat]file_put_contents($filename, $data, FILE_APPEND | LOCK_EX);
Byl jsem tady Skript 2 čas 1:00:11.00
Byl jsem tady Skript 1 čas 21:00:11.002
Byl jsem tady Skript 3 čas 1:00:11.001
clearstatcache();
$_DEBUG_ = false;
/*
folder.t1 - directory lock for backup copy
folder.t2 - directory lock for restore copy
*/
echo "Lock and flush tester.".time()."<br>";
$time_constant = 1571149526;
//die; // Remove this line when you set time_constant
while ( time()<$time_constant )
{
usleep(500);
}
/*
Creates directory lock for atomicity or waits
$dirPrefix = "lock"; // dir. lock name
$lockN = 1; // first lock
$lockTimes = 7; test 7 times
*/
function AtomicFuseTestTimes($dirPrefix, $n, $lockN, $lockTimes, $printError = true){
$start = atomicFuse($dirPrefix, $n,$lockN,0);
for ($i=1; $i <= $lockTimes; $i++ )
if (!$start)
$start = atomicFuse($dirPrefix, $n,$lockN,$i);
else
break;
if (!$start) $start = atomicFuse($dirPrefix, $n, $lockN, null, false);
if ( $printError==true && !$start) echo "<br><b>Atomicity failed for lock $lockN.</b><br> ";
return $start;
}
/*
Before or after, you call AtomicityTestLockTimes,
you need to create a directory lock.
$n = file size in kb
$lockN = 1; // first lock
$lockTimes = 7; test 7 times
*/
function AtomicityTestLockTimes($dirPrefix, $n, $lockN, $lockTimes, $printError = true){
$start = TestAtomicLock($dirPrefix, $n,$lockN,0);
for ($i=1; $i <= $lockTimes; $i++ )
if (!$start)
$start = TestAtomicLock($dirPrefix, $n, $lockN,$i);
else
break;
if (!$start) $start = TestAtomicLock($dirPrefix, $n, $lockN, null);
if ( $printError==true && !$start) echo "<br><b>Atomicity failed for lock $lockN.</b><br> ";
return $start;
}
/*
This makes a test of atomic lock but does not
create it.
c is counter for optimalization
first call must have c = 0;
*/
function TestAtomicLock($dirPrefix, $n, $lockNumber, $c){
if ( $c<0 )
die("<h3>TestAtomicLock: Error - c is less than 0</h3>");
$start = true;
echo "<br>'$dirPrefix.t$lockNumber'<br>";
if ( file_exists("$dirPrefix.t$lockNumber") )
{
clearstatcache();
$st = @stat("$dirPrefix.t$lockNumber");
echo "dir lock time: ".(time()-$st['ctime']);
if ( time()-$st['ctime'] > 10 )
{
@rmdir("$dirPrefix.t$lockNumber"); // remove directory lock
echo "<h1>Old lock removed</h1>";
}
$start = false;
}
else echo " not found; ";
if ( isset($c) ){
if ( $start == false )
{
$n = $n*30;
switch($c): // Delay example increase:
case 0: break; // 0,01569 total
case 1: break; // 0,03138 total
case 2: $n = $n*2; break; // 0,06276 total
case 3: $n = $n*4; break; // 0,12552 total
// case 4: You need at least *6 or *8 to get out of problems with extrem times
case 4: $n = $n*8; break; // 0,25104 t.(upper limit)
// In case of heavy traffic:
case 5: $n = $n*8; break; // 0,36087 total extrem
case 6: $n = $n*10; break; // 0,51777 total extrem
case 7: $n = $n*20; break; // 1,03554 total extrem
default: $n = $n*8; break;
endswitch;
usleep($n);
echo "($n)<br>";
}
}
return $start;
}
/*
dirPrefix - should be equal to name of the file you're trying to lock
lockNumber for adding more locks */
function atomicFuse($dirPrefix, $n, $lockNumber, $c){
if ( $c<0 )
die("<h3>TestAtomicLock: Error - c is less than 0</h3>");
$start = false;
if ( @mkdir("$dirPrefix.t$lockNumber") )
$start = true;
if ( isset($c) ){
if ( $start == false )
{
$n = $n*30;
switch($c): // Delay example increase:
case 0: break; // 0,01569 total
case 1: break; // 0,03138 total
case 2: $n = $n*2; break; // 0,06276 total
case 3: $n = $n*4; break; // 0,12552 total
// case 4: You need at least *6 or *8 to get out of problems with extrem times
case 4: $n = $n*8; break; // 0,25104 t.(upper limit)
// In case of heavy traffic:
case 5: $n = $n*8; break; // 0,36087 total extrem
case 6: $n = $n*10; break; // 0,51777 total extrem
case 7: $n = $n*20; break; // 1,03554 total extrem
default: $n = $n*8; break;
endswitch;
usleep($n);
echo "!($n)<br>";
}
}
return $start;
}
function test($n, $p, $_DEBUG_){
// $delay_multiplier = $n*2.5;
$original_fname = "$n";
$cname = "$n.b"; // copy to restore
$working_filename = "$n.txt"; // source & target
echo "<h4>$n at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start_time = microtime(true);
clearstatcache(); // needed for filesize and touch
//////////////////////
// TEST ATOMIC LOCK //
//////////////////////
// Test 1 - "backup" lock
// MAKE BACKUP
// Test 2 - "restoring" lock
$start = AtomicityTestLockTimes($n,$n,1,7);
if ( $start )
{
$success = @mkdir("$n.t1");
if ( $success == false )
echo "<b>Failed to lock;</b><br>";
$result = copy($original_fname, $cname);
if ( $result == false )
echo "<h4>BACKUP failed.</h4>";
$result = @rmdir("$n.t1");
if ( $result == false )
echo "<h4>Directory lock was not removed</h4>";
}
// Test 2 - "restoring" lock
// $start = AtomicityTestLockTimes($n,$n,2,7);
if ( true )
{
$st = stat("$working_filename");
$original_size = $st['size'];
if ( $_DEBUG_ )
echo "; 1) prevAccess by ".$st['mtime']." fsize ".$st['size']."; ";
$fsize = filesize($working_filename);
if ( $original_size <> $fsize )
die("; fsize total FAILTURE; ");
if ($fsize === 0)
die ("! <b>The fsize is 0</b>: fstat(): $original_size <>".$st['size']." ;");
// READ OPERATION AND LOCK FOR SHARE
$fp = fopen($working_filename, "r+");
$locked = flock($fp, LOCK_SH);
if ( $locked == false)
die("failed to get LOCK_SH;<br>");
$s = fread( $fp, $fsize );
// CHANGE LOCK
$success = flock($fp, LOCK_UN);
$locked = flock($fp, LOCK_EX);
if ( $success === false )
die("; r flock release failed; ");
if ( $locked == false )
die("failed to get LOCK_EX;<br>");
clearstatcache();
$st = stat("$working_filename");
if ( $_DEBUG_ )
echo "; 2) prevAccess by ".$st['mtime']." fsize is ".$fsize."; ";
// WRITE OPERATION WITH LOCK_EX
$locked = flock($fp, LOCK_EX);
if ( $locked ) { // acquire an exclusive lock
$success = rewind($fp);
if ($success == false)
echo " rewind failture; ";
$success = fwrite($fp, $s);
if ( $success === false)
echo "; w FAILED;";
else
if ( $_DEBUG_ )
echo " $success B written; ";
$success = fflush($fp);// flush output before releasing the lock
if ( $success === false )
echo "; flush FAILED; ";
// Test 2 - "restoring" lock
// $start = AtomicityTestLockTimes($n,$n,2,7);
$success = flock($fp, LOCK_UN);
$success = fclose($fp);
if (false)//$start)
{
$original_fname = "$n";
// Create directory lock
$success = @mkdir("$n.t2");
clearstatcache(); // Check file size
$st = fstat($fp);
if ($original_size>$st['size'])
{
echo "; <b>WRITE FAILED, restoring</b>;";
if ($success) {
$success = flock($fp, LOCK_UN);
$success = fclose($fp);
$result = copy($cname, $working_filename);
if ( $result == false )
echo "<h4>Restoring failed.</h4>";
}
if ($result == false )
die(" <b>TOTAL FAILTURE: copy failed.</b>");
else
echo " <b>RESTORED</b>;";
}
else
{ // FINISH SUCCESSFUL WRITE OPERATION
if ( $success )
touch("$working_filename",$fsize,$p);
$success = flock($fp, LOCK_UN); // release the lock
if ( $success === false )
echo "; release FAILED; ";
$success = fclose($fp);
if ( $success === false )
echo "; fclose FAILED; ";
// 10 - data načtená , $p - prohlížeč
if ( $success )
{
$result = touch("$working_filename",strlen($s),$p);
if ( $_DEBUG_ )
echo "; TOUCH: $result;";
}
else
die("fclose FAIL.");
}
// RELEASE DIRECTORY LOCK: (Test 2)
/*
$result = rmdir("$n.t2");
if ( $result == false )
echo "<h4>Directory lock was not removed</h4>";
*/
} // END OF ATOMIC LOCK (mkdir) Test 2
} else echo "Couldn't get the lock!";
}
/////////////////////////
// END OF TIME MEASURE //
/////////////////////////
$time_elapsed_secs = microtime(true) - $start_time;
//usleep( $delay_multiplier + $n*rand(2,6) );
if ( $time_elapsed_secs === 0 )
echo " FAILED ";
echo "time: $time_elapsed_secs s<br>";
} // for
}
copy("523","523.txt");
copy("948","948.txt");
copy("1371","1371.txt");
copy("1913","1913.txt");
copy("2701","2701.txt");
copy("4495","4495.txt");
copy("6758","6758.txt");
test("523",$p,$_DEBUG_);
test("948",$p,$_DEBUG_);
test("1371",$p,$_DEBUG_);
test("1913",$p,$_DEBUG_);
test("2701",$p,$_DEBUG_);
test("4495",$p,$_DEBUG_);
test("6758",$p,$_DEBUG_);
function AtomicityTestLockTimes($dirPrefix, $n, $lockN, $lockTimes, $printError = true){
$start = TestAtomicLock($dirPrefix, $n,$lockN,0);
for ($i=1; $i <= $lockTimes; $i++ )
if (!$start)
$start = TestAtomicLock($dirPrefix, $n, $lockN,$i);
else
break;
...
return $start;
}
$start = AtomicityTestLockTimes($n,$n,1,7);
if ( $start )
{
$success = @mkdir("$n.t1");
if ( $success == false )
echo "<b>Failed to lock;</b><br>";
$result = copy($original_fname, $cname);
if ( $result == false )
echo "<h4>BACKUP failed.</h4>";
$result = @rmdir("$n.t1");
if ( $result == false )
echo "<h4>Directory lock was not removed</h4>";
}
přidávání dat do souboru pomocí fopen(filename, "a") je taky neatomicitní?
Zkus raději podle manuáluKód: [Vybrat]file_put_contents($filename, $data, FILE_APPEND | LOCK_EX);
To mohu použít jen v případě, že ve scriptu nejedou dva procesy paralelně, já myslel právě pro to použití dvou skriptů. Dám příklad:
Co chci zapsat do logu:
"Byl jsem tady Skript 2 čas 1:00:11.000"
"Byl jsem tady Skript 1 čas 1:00:11.002"
"Byl jsem tady Skript 3 čas 1:00:11.001"
Jestli je zapíše za sebou - jedno v jakém pořadí,
nebo se může stát, že vznikne kolize
napřKód: [Vybrat]Byl jsem tady Skript 2 čas 1:00:11.00
Byl jsem tady Skript 1 čas 21:00:11.002
Byl jsem tady Skript 3 čas 1:00:11.001
(Ubral nulu na konci prvního řádku)
Aplikace prvního zámku:Kód: [Vybrat]$start = AtomicityTestLockTimes($n,$n,1,7);
if ( $start )
{
$success = @mkdir("$n.t1");
if ( $success == false )
echo "<b>Failed to lock;</b><br>";
$result = copy($original_fname, $cname);
if ( $result == false )
echo "<h4>BACKUP failed.</h4>";
$result = @rmdir("$n.t1");
if ( $result == false )
echo "<h4>Directory lock was not removed</h4>";
}
A druhý zámek jsem neaplikoval, jak jsem už napsal.
523kB 0,848779202 0,257663012 0,257443905 0,001293182
948kB 0,001987934 1,540060997 0,002835035 1,537259817
1371kB 0,004508018 0,818147898 0,005446196 2,225590944
1913kB 1,965152025 3,108391047 0,008336067 3,122910023
2701kB 0,679250002 4,378324986 0,013814211 0,009026051
4495kB 3,45074296 3,259652853 0,037675858 0,021569967
6758kB 0,275954008 8,090615034 0,042881966 6,911487103
Návštěvníkům, kteří zde zabloudí se asi nebude chtít vše pročítat, tak mohl bys k tomu grafu stručně napsat jaké z něj plyne tvé doporučení nebo závěr pro ostatní programátory PHP? Podle názvu této diskuze bude návštěvníky hlavně zajímat, kterou funkci (zámek) použít pro čtení/zápis souborů.
Teď to čtu v manuálu, že append mode pro fopen je atomický.
"If handle was fopen()ed in append mode, fwrite()s are atomic (unless the size of string exceeds the filesystem's block size, on some platforms, and as long as the file is on a local filesystem). That is, there is no need to flock() a resource before calling fwrite(); all of the data will be written without interruption."
fwrite($f, "Hello, ");
fwrite($f, "World");
tak musíš počítat s tím, že se ti mezi ta dvě slova může vecpat něco jiného. Na to je však snadný recept: Naskládáš si vše do jednoho stringu a ten atomicky zapíšeš jedním vrzem. Je to i rychlejší.
V praxi přece nikdo nechce jen načíst data. Musíš to udělat tak, že načteš data, pak provedeš operace a pak je uložíš. Což znamená znovu zkontrolovat velikost souboru, porovnat jestli velikost sedí nebo případně načíst celý soubor v modu r+, porovnat data, dát rewind a zapsat. Jen tak si člověk může ověřit že mezi zpracováváním dat nedošlo ke změně.
@Exkalibr: Pokud k tomu grafu nemáš žádné vyhodnocení, tak proč si nám ho sem dal? K čemu nám je užitečný?
Ano, může si ho každý z nás zhodnotit tak, že bude 2 dny zkoumat zdrojáky a zjišťovat co v tom grafu vlastně je. Proč by tím měl trávit čas každý z nás když to může pár větami shrnout Exkalibr, který tomu ty 2 dny už věnoval.@Exkalibr: Pokud k tomu grafu nemáš žádné vyhodnocení, tak proč si nám ho sem dal? K čemu nám je užitečný?Proč by měl řešit, zda je nám ten graf k užitku? Zhodnotit si ho může každý, stejně jako ho každý může ignorovat dle své volby.
@Exkalibr: Pokud k tomu grafu nemáš žádné vyhodnocení, tak proč si nám ho sem dal? K čemu nám je užitečný?
Jak vidíte, zkopírování 2MB souboru + čtení a zápis v originále už začíná být znát. Nejvyšší čas (v poměru k velikosti souboru) je 2.7 MB.
Ano, může si ho každý z nás zhodnotit tak, že bude 2 dny zkoumat zdrojáky a zjišťovat co v tom grafu vlastně je. Proč by tím měl trávit čas každý z nás když to může pár větami shrnout Exkalibr, který tomu ty 2 dny už věnoval.@Exkalibr: Pokud k tomu grafu nemáš žádné vyhodnocení, tak proč si nám ho sem dal? K čemu nám je užitečný?Proč by měl řešit, zda je nám ten graf k užitku? Zhodnotit si ho může každý, stejně jako ho každý může ignorovat dle své volby.
Ty si přece u toho byl a sám si navrhl T8 @mkdir jako tu pojistku proti přepisům, vlastně si mi taky poradil jak odstranit tu chybu, že kontrola filesize je zbytečná a nespolehlivá.No právě, byl jsem u toho a ani já se v tom nevyznám. Těch úprav, kódu, grafů a popisů chyb bylo tolik. Každého asi první budou zajímat ty nejrychlejší časy T3-T4 u kterých ses obával nespolehlivosti kvůli bufferování, tak jsem myslel, že to nějak okomentuješ.
Hlavní úspěch je především v tom, že se mi povedlo vyloučit ty selhání zápisu a selhání atomicity, takže T10 je první test s validními výsledky.Jo i to, že všechny ostatní způsoby kromě T10 jsou špatné jsou výsledek. Pak ale nechápu k čemu jsou ty křivky T2-T8b v grafu když u nich dochází k selhání. K čemu je důležité znát rychlost v sekundách když při tom dochází k selhání?
Graf pak slouží hlavně pro orientaci v tom, že vidíš jaké jsou zdržení při zápisu na disk když běží 4 procesy ve smyčce bez prodlevy ... a potom jak se ten čas mění, když tam uměle strčíš prodlevu kvůli čekání na uvolnění directory lock.A u kterých T je strčená ta prodleva? Možná jsi to psal na stackoverflow.com a možná je to někde na těch 10 stránách této diskuze. Mám dojem, že u T7 jsi psal o 50 microsekundové prodlevě o které jsi prohlásil, že nemá na měření vliv, ale teď myslíš asi jinou prodlevu.
Pak ale nechápu k čemu jsou ty křivky T2-T8b v grafu když u nich dochází k selhání. K čemu je důležité znát rychlost v sekundách když při tom dochází k selhání?
T3 a T4 - bufferování file_get_contents() a file_put_contents()No tohle je třeba jedna z věcí co nechápu. file_put_contents má parametr LOCK_EX, takže pokud to budeš mít dobře nastavené, tak se daný soubor zamkne a nic neselže. To, že se to bufferuje je právě výhoda, protože to je nejrychlejší a jak ti Kid hned na začátku diskuze vysvětlil, tak to buferování si hlídá filesystém a nevídím důvod proč bys tuto funkci neměl používat. Nebo místo parametru LOCK_EX můžeš použít mkdir.
Ty testy jsem začal dělat proto, že jsem se chtěl bufferování vyhnout. Chtěl jsem najít způsob jak přečíst a zapsat data bezpečně do souboru, aniž bych se musel bát, že když je pozměním, změny nebudou uloženy. Proto mě ty funkce file_get(put)_contents nezajímají, jsou pro mě nepoužítelné.
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.Přesně tak. Já jsem myslel, že teď když si Exkalibr ten test doladil, že ho spustil celý znovu a všechny výsledky v grafu jsou SPOLEHLIVÉ zápisy dat, ale vypadá to, že se pořád plácáme v dolaďování testovacího scriptu. Jakýkoliv graf v tuhle chvíli ztrácí smysl. Jediná správná věc je všechno zahodit, napsat znovu test pečlivě (slovy pečlivě) a odprezentovat jediný graf s jasným sdělením. Takhle to vypadá, že cílem bylo pochlubit se uměním vytvářet grafy a testovací script posloužil jen jako generátor náhodných dat.
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.Přesně tak. Já jsem myslel, že teď když si Exkalibr ten test doladil, že ho spustil celý znovu a všechny výsledky v grafu jsou SPOLEHLIVÉ zápisy dat, ale vypadá to, že se pořád plácáme v dolaďování testovacího scriptu. Jakýkoliv graf v tuhle chvíli ztrácí smysl. Jediná správná věc je všechno zahodit, napsat znovu test pečlivě (slovy pečlivě) a odprezentovat jediný graf s jasným sdělením. Takhle to vypadá, že cílem bylo pochlubit se uměním vytvářet grafy a testovací script posloužil jen jako generátor náhodných dat.
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.
To, že bych se v tom plácal já není nic překvapivého, tenhle test byl jeden velký chaos, jsi hodně zbrklý. Bohužel se v tom plácáš hlavně ty. Jestliže jsi napsal:Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.Přesně tak. Já jsem myslel, že teď když si Exkalibr ten test doladil, že ho spustil celý znovu a všechny výsledky v grafu jsou SPOLEHLIVÉ zápisy dat, ale vypadá to, že se pořád plácáme v dolaďování testovacího scriptu. Jakýkoliv graf v tuhle chvíli ztrácí smysl. Jediná správná věc je všechno zahodit, napsat znovu test pečlivě (slovy pečlivě) a odprezentovat jediný graf s jasným sdělením. Takhle to vypadá, že cílem bylo pochlubit se uměním vytvářet grafy a testovací script posloužil jen jako generátor náhodných dat.
Blbost. Tady už není co dolaďovat napsal jsem snad jasně, že T10 je dokončený a bez chyb. Není co dolaďovat. K ostatním testům se vracet nebudu, nelze je opravit, když obsahují chyby. Jediné v čem se plácáme dokonala je tvá nechápavost. Psal jsem to už několikrát a nebaví mě to opakovat, že ten graf odráží rychlosti čtení a zápisu a chyby v tom nehrají roli. Když došlo k údajnému selhání fwrite, soubor byl přece načten a zkopírován pomocí copy(). Takže ty časy jsou spolehlivé a věruhodné. Nechápu co to tu furt plácáš.
Ty testy jsem začal dělat proto, že jsem se chtěl bufferování vyhnout. Chtěl jsem najít způsob jak přečíst a zapsat data bezpečně do souboru, aniž bych se musel bát, že když je pozměním, změny nebudou uloženy. Proto mě ty funkce file_get(put)_contents nezajímají, jsou pro mě nepoužítelné.tak to znamená, že jsi došel ke zcela mylnému závěru. Funkce file_get(put)_contents je spolehlivá a použitelná.
Jenom bych upřesnil, že neustále píšete, že selhávají funkce flock() a file_put_contents() atd., ale ve skutečnosti selhává váš kód. Ty funkce fungují správně, chyby jsou ve vašem kódu.Nic jiného netvrdím. Záleží přece na tom jakým způsobem ty funkce použijete a to jsem psal, že já hledám funkci, která umožňuje přístup k souboru více uživateli, načíst soubor, změnit soubor, zapsat soubor. V mých testech není ta změna.
Nic jiného netvrdím. Záleží přece na tom jakým způsobem ty funkce použijete a to jsem psal, že já hledám funkci, která umožňuje přístup k souboru více uživateli, načíst soubor, změnit soubor, zapsat soubor. V mých testech není ta změna.To ale umožňují všechny funkce, o kterých tady byla řeč. Akorát se (kterákoli z nich) musí správně používat. Navíc ty vaše testy mohou ale nemusí případné chyby odhalit. Konkurenční programování je založené na tom, že pochopíte problém a nastudujete si dokumentaci použitých funkcí. Nelze to založit na testech, protože variant je příliš mnoho, takže je nedokážete otestovat všechny. A do třetice, výsledkem testu, který ověřuje, zda by váš kód mohl být správně, je výstup ano (možná je správně) nebo ne (není správně) – ne žádné grafy. Pokud vám z testu vyjde, že ten kód je špatně, nemá smysl z toho malovat nějaký graf, ale opravit ten kód.
... nejoptimálnější...?
... nejoptimálnější...?
@Kit: Po jak velkých blocích je nejoptimálnější načítat data ze souboru? Dejmetomu, že mám texťák s emaily a id-éčkama uživatelů, na začátku je hlavička s rejstříkama cca 2KB. Je nějaký rozdíl v rychlosti či odezvě v tom jestli napoprvé načtu 2kB, 4kB nebo 8kB? Opakuji, že jde jen o první načtení hlavičky, z toho zjistím přesné umístění bloku, ve kterém hledat email po přihlášení; Takový blok by pak měl mít prakticky mezi 50-250 znaky. Takže i kdyby měl soubor 4MB, během přihlašování načtu jen hlavičku a pak ten hledaný blok.
@Kit: Po jak velkých blocích je nejoptimálnější načítat data ze souboru? Dejmetomu, že mám texťák s emaily a id-éčkama uživatelů, na začátku je hlavička s rejstříkama cca 2KB. Je nějaký rozdíl v rychlosti či odezvě v tom jestli napoprvé načtu 2kB, 4kB nebo 8kB? Opakuji, že jde jen o první načtení hlavičky, z toho zjistím přesné umístění bloku, ve kterém hledat email po přihlášení; Takový blok by pak měl mít prakticky mezi 50-250 znaky. Takže i kdyby měl soubor 4MB, během přihlašování načtu jen hlavičku a pak ten hledaný blok.
Optimální by mělo být 8 KiB, protože to je obvyklá velikost bufferu.
/* default bucket buffer size - 8KB minus room for memory allocator headers */
#define APR_BUCKET_BUFF_SIZE 8000
Což osobně čtu tak, že user-space alokátor Apache si přidělenou virtuální paměť (přidělena kernelem po 4 kB) parceluje pro potřeby file IO po 8kB (8192 B), ale payloadu Vaší PHP aplikace z toho dává jenom 8 kiB (8000 B).Po jak velkých blocích je nejoptimálnější načítat data ze souboru?Optimální je načítat data po stejných blocích, po jakých je načítá knihovní funkce do bufferu, po jakých s nimi pracuje souborový systém a po jakých s nimi pracuje disk. Přičemž v každé té vrstvě může být blok jinak velký, v lepším případě jsou to alespoň násobky. A v každé té vrstvě to může být v různých případech jinak. Takže nemá smysl to experimentálně zjišťovat, protože tím zjistíte pouze parametry pro ten případ, kde to testujete – a tam je lepší se podívat do konfigurace, jak máte nastavený souborový systém a jaký tam máte disk.
Což osobně čtu tak, že user-space alokátor Apache si přidělenou virtuální paměť (přidělena kernelem po 4 kB) parceluje pro potřeby file IO po 8kB (8192 B), ale payloadu Vaší PHP aplikace z toho dává jenom 8 kiB (8000 B).
Pro mě není slovo optimální dostačující. Je optimální a ještě víc optimální. Optimální může být pro vysokoúrovňového programátora, tzn. dostačující, ale pro perfekcionistu nízkoúrovňového programátora je nutné použít superlativum nejoptimálnější, protože to znamená dokonalý stav, kterého každý pedant touží dosáhnout.Optimální ale neznamená dostačující, znamená to nejlepší možný, dokonalý. Jak může být něco nejlepší, když existuje něco ještě lepšího?
S tím se váže otázka na používání funkcí chr a ord. Když bych do souboru chtěl zapsat uživatelská idečka a je třeba to udělat binárně a bezpečně tj. zkopírovat dva bajty s daným id, jak to správně udělat? Já znám jen ty dvě funkce chr a ord mám obavy o to, že tyhle věci budou náročné na výkon. A neměl bych taky řešit endianness (česky endianita?) správnost přečtení z binárního souboru?
Popravdě mi teprve teď došlo, že nemáte k dispozici Céčkový typový systém, pointerovou aritmetiku apod. Prostě všechen ten bordel, který umožňuje koukat na data střídavě jako na buffer binárních bajtů, nulou zakončený řetězec znaků, integer o potřebné délce na nějaké adrese apod. Takže nevím, jak s tím bufferingem. Má PHP aspoň něco jako perlový "binmode" režim souborů? Datový typ "buffer binárních bajtů", nebo třeba jenom stringy co nesmí obsahovat nulové bajty?
Ohledně endianity... procesor při aritmetických operacích očekává data uložená v RAMce v souladu s endianitou Vaší instrukční sady. Formát uložení binárních dat v souboru (nebo na síti) může mít nějaký standard, který endianitu jasně stanoví = může být potřeba, konvertovat indiány mezi instrukční sadou a diskovým formátem.
Koukám, že PHP má jenom jeden integer podle architektury, a to se znaménkem... Tzn. 16bit unsigned hodnota se Vám do něj nejspíš vejde bez problému. Jak k tomu přistupovat po bajtech... jakožto PHP analfabet, bez pointerové aritmetiky, bych se to asi pokusil ohnout pomocí bitwise operátorů (https://www.php.net/manual/en/language.operators.bitwise.php), ty jsou zřejmě k dispozici. Levý a pravý shift, stejně jako masky používané s operací "AND" fungují na úrovni zdrojového textu všude stejně, nezávisle na indiánech v instrukční sadě = tyto operace použité ve zdrojáku jsou multiplatformní. A funkce ord() a chr() jsou myslím použitelné jenom na zobrazitelné ASCII znaky. Pokud potřebujete 16bit čísla ukládat buď jako dva bajty v binárním souboru nebo jako číslo v ASCII textu, podle mého budete potřebovat spíš sprintf()/sscanf() nebo něco na ten způsob (pro konverzi do/z ASCII formátu).
Ano tohle všechno v PHP funguje, ale je zde zásadní otázka: Proč dělat tyhle binární opičky, když je to už hotové, v knihovnách, napsáno v C/C++, takže je to i rychlé?
o jakých knihovnách je řeč?
$keys .= $sub.pack('S', $size);
https://stackoverflow.com/questions/6453061/how-to-convert-integer-to-8bit-binary-data-by-using-phpS unsigned short (always 16 bit, machine byte order)
'size'=>array(
'size'=>$ss['size'], //Size of file, in bytes.
'blocks'=>$ss['blocks'], //Number 512-byte blocks allocated
'block_size'=> $ss['blksize'] //Optimal block size for I/O.
),