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

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


Kit

  • *****
  • 704
    • Zobrazit profil
    • E-mail
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

Nejsem Alf :D

Ty dvě funkce jsou nejužitečnějsí ze všech funkcí, které pracují se soubory. Nemohou za to, že je používáš špatně pro naprosto nevhodný účel.

Dej příklad jak by se dali použít. Chci si rozšířit obzory.

Tak jedno použití mě napadlo. Možná na stáhnutí vzdáleného souboru?

Kit

  • *****
  • 704
    • Zobrazit profil
    • E-mail
Například načtení konfigurace, šablony, slovníku nebo číselníku; uložení vygenerovaného obrázku, sitemapy, PDF, konfigurace a kdovíčeho ještě. Když ukládáš pod unikátními názvy, tak kolize nehrozí.

@exkalibr: Mám dojem, že se zabýváš složitým testem, ze kterého něco dedukuješ, ale přitom to co potřebuješ je zamknout soubor. Pokud to hodíš do googlu, tak najdeš spoustu řešení. Namátkou https://php.vrana.cz/atomicita-operaci.php , http://cubosoft.sweb.cz/Php/php/azphp510.htm , https://locallost.net/?p=1091 . Jak vidíš jsou to hodně letité odkazy, takže není pravda, že by se o tom nevědělo.


Dík za článek. A proč prostě soubor nepřejmenovat?

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

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.

Dal by se do toho zakomponovat i test if jirka.2 exists do:
« Poslední změna: 12. 10. 2019, 22:08:12 od exkalibr »

Kit

  • *****
  • 704
    • Zobrazit profil
    • E-mail
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ď?

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ď?

Díky za potvrzení :) Jsem perfekcionista, počítal jsem s tím přece. Viz

Citace
Dal by se do toho zakomponovat i test if jirka.2 exists do:

Dík za článek. A proč prostě soubor nepřejmenovat?
Kód: [Vybrat]
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;
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.
Dal by se do toho zakomponovat i test if jirka.2 exists do:
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.

Dík za článek. A proč prostě soubor nepřejmenovat?
Kód: [Vybrat]
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;
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.
Dal by se do toho zakomponovat i test if jirka.2 exists do:
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.

Máš pravdu, to rename musí následovat hned za if, pak už je pozdě. Copy provést až po přejmenování. Mě připadá že vytváření adresáře je složitější proces než přejmenování. FS si musí kvůli tomu vytvořit nový záznam, kdežto při rename souboru nemusí vytvářet nic... Ale mohu otestovat ten rename a říct ti jestli je to spolehlivější než T7.

1. Minimálně musíte zkontrolovat výsledek rename. K rename může dojít více procesů, jen jeden z nich ale projde.
2. Nerozumím Vašemu řešení, jak ošetříte situaci, kdy aplikace spadne. Ta situace přece vypadá úplně stejně, jako kdyby druhý proces byl aktivní. A když už to detekujete, otázka je, co s tím uděláte…
3. Tomu cyklu na konci asi nerozumím, nicméně  vypadá to jako busy waiting. To zrovna dvakrát elegantní není. Žere to CPU, ačkoli by proces mohl pokojně spát a čekat na I/O.
4. Opravdu nechcete použít databázi, kde za Vás někdo podobné problémy již vyřešil?

Tak to nefunguje. Povedlo se otestovat jen dva bloky, ale mají příliš vysoký čas. Možná kvůli té testovací smyčce (i když file_exists asi hledá v bufferu, že?).

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.
« Poslední změna: 12. 10. 2019, 23:37:08 od LarryLin »

Dneska vyzkouším ten mkdir.

Zatím se mi to nedaří rozjet. Kontrola kódu:

function atomicFuse($n){
  $start = false;
  if ( !file_exists("$n.t") )
   $start = mkdir("$n.t");
  if ( $start == false )
   usleep($n*16);
  return $start;
}

  for ($i = 0; $i<2; $i++ ){
    $start_time = microtime(true);
      {
      $start = atomicFuse($n);
      // If n*16 used then 6 time repeat:
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) $start = atomicFuse($n);
      if (!$start) echo "Atomicity failed. ";
      if ( $start )
         {
         .... do této větve se nedostane
         }
     }
     $time_elapsed_secs = microtime(true) - $start_time;
     if ( $time_elapsed_secs === 0 )
       echo " FAILED ";
   }

Pro srozuměnou: n je velikost souboru v kb.
Pro n= 948 tak vychází prodleva 16116 čili 0,016116 mikrosekund.

Výstup:

523 at 1570949057
Atomicity failed. skippedtime: 0.050755023956299 s
Atomicity failed. skippedtime: 0.050696134567261 s
948 at 1570949057
Atomicity failed. skippedtime: 0.091481924057007 s
Atomicity failed. skippedtime: 0.091547012329102 s
1371 at 1570949057
Atomicity failed. skippedtime: 0.13213992118835 s
Atomicity failed. skippedtime: 0.13215684890747 s
1913 at 1570949057
Atomicity failed. skippedtime: 0.18418097496033 s
Atomicity failed. skippedtime: 0.1841561794281 s
« Poslední změna: 13. 10. 2019, 09:00:42 od exkalibr »