PHP: Výsledky srovnání funkcí file_(get)put_contents & f(read/write/flush)

Při T5-T7 je problém při zápisu do souboru fwrite, fflush. To jsem už psal.

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);

Ale teď se dívám, že jsem tam mohl dát LOCK_EX místo LOCK_SH, to LOCK_SH tam nedává smysl. Ale má to vliv?

Kód: [Vybrat]
$locked = flock($fp, LOCK_SH)
OK, tak jsem to testnul a řekněte mi jestli ten kód je dobře:

Kód: [Vybrat]
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.

Výsledek:
FF1 - failed 0x
Chrome - failed 0x
FF2 - failed 2x
Opera - failed 5x
Celkem atomicity failed 7x - což ale nutně neznamená, že je to lepší. Někdy může být selhání více, někdy méně, jak tu bylo řečeno, tohle závisí na OS, který proces si zrovna upřednostní. Závěr ale je, že k porušení atomicity došlo.
« Poslední změna: 13. 10. 2019, 21:42:21 od exkalibr »


Kit

  • *****
  • 661
    • Zobrazit profil
    • E-mail
LOCK_EX se dává v případě, že chceš do souboru zapisovat.

Původně mi šlo o testování rychlosti během čtení/zápisu na server při spuštěných 4 procesech současně. T7 se povedlo otestovat s malým množstvím chyb, ale nyní těch chyb je kopa, to nemá cenu počítat. Nevím co se změnilo. Tak by T8 možná mohl vyjít spolehlivěji, ale ve výsledku ani jedna operace není dokonale spolehlivá.

Kit

  • *****
  • 661
    • Zobrazit profil
    • E-mail
Stačí jediná chyba a můžeš tu metodu zahodit.

Čím si vysvětluješ, že ani flock nepomůže k zajištění atomicity?


Kit

  • *****
  • 661
    • Zobrazit profil
    • E-mail
Nezkoumal jsem to tak podrobně, jen vidím, že proměnná $start je zcela zbytečná a může ty problémy způsobovat.

Kit

  • *****
  • 661
    • Zobrazit profil
    • E-mail
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);

Zamknuté to není, protože to v polovině odemykáš a zase zamykáš. V tu chvíli si ten soubor zamkne jiný proces a máš kolizi.

Kit

  • *****
  • 661
    • Zobrazit profil
    • E-mail
Zkus tuto jednoduchou úpravu, jak bude reagovat na souběhy:
Kód: [Vybrat]
$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 ;)

Kit

  • *****
  • 661
    • Zobrazit profil
    • E-mail
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 ;)

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().

Zamykání přes mkdir() má nevýhodu v tom, že když ten proces spadne, kdo to po něm uklidí?

Čí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.


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.

Kit

  • *****
  • 661
    • Zobrazit profil
    • E-mail
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í.