Avatar billede wisemind Nybegynder
06. juli 2009 - 11:29 Der er 11 kommentarer

Handling af store php loops

Hej Eksperter,

Hvis man eksempelvis har et loop som udfoerer en handling 1000 gange foer den er faaerdig, hvordan kan man saa:

1. Sikre at det ikke timer ud.

2. Endnu bedre, vise en opdatering paa selve siden der siger noget ala "1 ud af 1000 handlinger completed" , "2 ud af 1000 handlinger completed" osv.

Haaber der er nogen der ved hvilken vej man skal kigge for at loese denne udfordring.

Paa forhaand tak
Avatar billede repox Seniormester
06. juli 2009 - 11:35 #1
1.:
set_time_limit(0);
Det virker, men det er noget gris og det sikrer dig ikke at klienten ikke timer ud.

2.:
Kig på http://php.net/flush

Det er svært at give dig et godt råd, når du ikke har en kodestump man kan kommentere på; måske er det i en anden retning man skal kigge.
Avatar billede majbom Novice
06. juli 2009 - 11:52 #2
du kan også køre f.eks. 10 loops for derefter at loade siden igen og fortsætte hvor den slap, ved at tage et parameter med i din querystreng - ved self ikke om det kan lade sig gøre i din situation, der du ikke har givet så meget info, som repox også nævner...
Avatar billede mrgumble Nybegynder
06. juli 2009 - 11:58 #3
Til nr. 1:
Du kan ikke garantere, at dit script ikke får en timeout. Men kig på http://us3.php.net/manual/en/function.set-time-limit.php og især bruger-kommentarerne, da de kommer med en masse hints, alt efter hvilken server du kører på. Så har du da mulighed for at forlænge dit scripts levetid.
Hvis du har bruger for at lave nogle beregninger der tager meget lang tid, skal du overveje at dele beregningerne op i del-problemer og lave en form for job-kø, f.eks. med en database og en side der bliver ved med at kalde dit script. Men serverens ejer bliver måske lidt sur på dig, hvis du suger for meget kraft til dine beregninger.

Til nr. 2:
Eftersom nogle browsere og servere ikke sender outputtet før det hele er færdig, kan du ikke løbende outputte, som f.eks. (pseudokode):
for i = 1 to 1000 {
  print i, " ud af 1000";
  sleep(1 sec);
}
I stedet kan du muligvis dele tingene op, så du har et par filer som f.eks.:
A. Hoved-siden som (1) kalder et eksternt script der laver beregninger og (2) kan vise løbende status.
B. Det eksterne script kan løbende udskrive status til en midlertidig log-fil. Dette kan du selv helt præcist styre. Evt. også en session, men jeg ved ikke hvordan det synkroniseres.
C. For at vise den løbende status, skal du bare have et simpelt script, der indlæser log-filen og som samtidig har en REFRESH meta-tag, så den selv bliver genindlæst løbende.

I hovedsiden kan (1) og (2) laves i iframes.

Jeg har ikke nogen konkrete eksempler på dette, da det er noget jeg lavede for meget lang tid siden. Men det gav nogle okay resultater.
Avatar billede wisemind Nybegynder
06. juli 2009 - 12:33 #4
Hej alle og mange tak for de informative svar!

Jeg har ikke lavet det endelig loop endnu, da jeg stadig arbejder paa del-processerne i loopet. Vil blot hoere nogle eksperters mening om hvordan man kan goere det mest fornuftigt ig brugervenligt fra starten.

Proevede lige et flush eksempel fra php.net , men siden "loadede" som om den ventede paa svar, og viste saa foerst loading status, da loopet var faerdigt.

Kodestumpen jeg testede var denne her:

<html>
<head>
<style type="text/css"><!--
.pbar {
    background: #EEE;
    border: 1px solid #CCC;
    margin: 1px;
    height: 10px;
    width: 10px;
}--></style>
</head>
<body>

<?php
// If the buffer is not set to 0, there's no need to call
// ob_start(), because the buffer is started already.
// You can test that by a call to ob_get_level();. Calling it
// again will cause a second level of buffering to start and
// the script won't work.

if (ob_get_level() == 0) {
    ob_start();
}
echo str_pad('Loading... ',4096)."<br />\n";
for ($i = 0; $i < 250; $i++) {
    echo '<span class="pbar">&nbsp;</span>';
    ob_flush();
    usleep(700000);
}
ob_end_flush();

// Close it out...
?>
</body>
</html>
Avatar billede mrgumble Nybegynder
06. juli 2009 - 13:01 #5
Det er et smukt eksempel, der desværre netop viser ulempen ved flush() og problemerne mellem server og klient.

Hvis du vil gøre tingene hipt, kan du anvende AJAX; dvs. lade JavaScript opdatere siden med info hentet fra serveren.

Hvad er det egentligt du beregner, der tager så meget tid?
Avatar billede coderdk Praktikant
06. juli 2009 - 20:31 #6
Jeg er enig mht ajax osv, men af ren interesse, så nævn mig en browser (som folk bruger) hvor dette ikke virker:

<?php

for ( $i = 0; $i < 60; $i++ )
{
  print str_repeat( " ", 1024 ) . "Nummer $i<br />\n";
  flush();
  sleep( 1 );
}

?>

Det kræver naturligvis, at output compression etc er slået fra.
Avatar billede majbom Novice
07. juli 2009 - 08:23 #7
-> #6 - det virker fint her i ie8, men jeg forstår ikke hvorfor der skal bruges str_repeat (jeg har prøvet at fjerne den, og så kommer der først output når den er færdig med løkken, hvorfor det?)
Avatar billede mrgumble Nybegynder
07. juli 2009 - 09:06 #8
-> #6 - delvist i Firefox 3.5 samt IE8 fra mit webhotel på http://www.iysik.com/test.php
Siden opdateres efter en 5-6 iterationer af for-løkken.
Avatar billede coderdk Praktikant
07. juli 2009 - 09:49 #9
Grunden til at str_repeat er der, er for at fylde nogen browseres interne buffer - så spytter den indhold ud hurtigere... Det lyder som IE8 måske skal have lidt flere tegn, før den spytter noget ud :P hehe

Løsningen virker fint i min FF 3.5, IE8, Safari 4 og Opera 9.6 :) Safari virker som om den har en anelse større buffer - Nogle gange kommer der to ad gangen...
Avatar billede majbom Novice
07. juli 2009 - 09:54 #10
okay, på den måde :)

hos mig spytter den 4 ud ad gangen i både ie8, ff3.5 og chrome2
Avatar billede majbom Novice
04. november 2010 - 12:50 #11
lukketid?
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester