Yii Framework Forum: Flush immediato... - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Flush immediato... Rate Topic: -----

#1 User is offline   Customsoft 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 36
  • Joined: 18-May 11
  • Location:Arzignano

  Posted 22 June 2011 - 08:43 AM

Mi sto perdendo in un bicchier d'acqua. :-)

Ho un piccolo script che recupera da un server remoto dei dati e li elabora sul mio server web inserendoli in un db
La procedura completa impiega dai 20 ai 90 secondi.

All'interno della procedura ho inserito vari echo per monitorare gli step della stessa. Ho pensato di aggiungere flush(); per veder apparire subito i dati sul client, ma questi vengono mostrati solo al termine di tutta la procedura.

Quindi mi sto domandando se su YII ci sia un altro modo per inviare direttamente i dati al browser durante l'elaborazione. Ho provato a cercare, ma non ho trovato soluzioni di sorta. Dove sta quindi l'inghippo?

Grazie a chi mi indirizza sulla giusta via :-)

Marco
Saluti
Marco (SE&O)
0

#2 User is offline   sensorario 

  • Elite Member
  • Yii
  • Group: Moderators
  • Posts: 1,986
  • Joined: 07-September 10
  • Location:Cesena (Italy)

Posted 22 June 2011 - 11:46 AM

Da quello che dici, a me sembra che l'inghippo sia in questo server remoto. Voglio dire... se la pagina ci mette tanto ad arrivare il problema sta li. Secondo me, senza il bisogno di echo, potresti fare girare questa pagina in background, magari con una chiamata ajax. ... ed aspettare che carichi.
0

#3 User is offline   Customsoft 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 36
  • Joined: 18-May 11
  • Location:Arzignano

Posted 22 June 2011 - 04:13 PM

View Postsensorario, on 22 June 2011 - 11:46 AM, said:

Da quello che dici, a me sembra che l'inghippo sia in questo server remoto. Voglio dire... se la pagina ci mette tanto ad arrivare il problema sta li. Secondo me, senza il bisogno di echo, potresti fare girare questa pagina in background, magari con una chiamata ajax. ... ed aspettare che carichi.

Intanto grazie per la risposta
Metto il codice cosi magari si capisce meglio :-D
public function actionImportaCategorie()
  {
    $y = 0;
    $x = 0;
    $nTempo = GetMicroTime();
    echo "<b>Recupero dati categorie</b> ... (".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />";flush();

    $sSql .= file_get_contents('http : / / www. SITO_REMOTO. com/crea_sql.asp?tab=categorie');

    echo "Vettorializzazione dati categorie ... (".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />";flush();

    $aSql = explode("\n",$sSql);
    echo "Inizio inserimento/aggiornamento DB ... (".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />";flush();

    $connection=Yii::app()->db;
    $command=$connection->createCommand("SET foreign_key_checks = 0;");
    $rowCount=$command->execute();
    #$command=$connection->createCommand("TRUNCATE categorie;");
    #$rowCount=$command->execute();

    echo count($aSql)." aggiornamenti da effettuare... (".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />";flush();

    foreach ($aSql as $key=>$value) {
      if (trim($value)!='') {
        $command=$connection->createCommand($value);
        $rowCount=$command->execute();
      }
      $y++;
      $x+=$rowCount;
      if ( ( $y % 500)==0 ) {
      	echo " - Aggiornate ".$y." righe con ".$y." query.(".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />";flush();
      }
    }
    $command=$connection->createCommand("SET foreign_key_checks = 0;");
    $rowCount=$command->execute();
  	echo " - Aggiornate ".$y." righe con ".$y." query.(".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />
      Importazione categorie completata.<br /><br />";
	}

Il ciclo FOREACH dovrebbe restituirmi un ECHO ogni 500 righe, ma tutti gli ECHO (anche quelli iniziali) mi vengono visualizzati solo al completamento di tutta la funzione.
L'altro server risponde in 1 secondo. Il tempo dello script è tutto nel ciclo FOREACH.

Cosa sbaglio?

Per completezza ecco le righe dell'output:

Quote

Recupero dati categorie ... (9.81 sec.)
Vettorializzazione dati categorie ... (16.61 sec.)
Inizio inserimento/aggiornamento DB ... (16.61 sec.)
2229 aggiornamenti da effettuare... (16.62 sec.)
- Aggiornate 500 righe con 500 query.(20.97 sec.)
- Aggiornate 1000 righe con 1000 query.(21.32 sec.)
- Aggiornate 1500 righe con 1500 query.(22.72 sec.)
- Aggiornate 2000 righe con 2000 query.(23.23 sec.)
- Aggiornate 2229 righe con 2229 query.(24.31 sec.)
Importazione categorie completata.

Ecco queste righe appaiono solo una volta completato il processo e non durante l'esecuzione.
Saluti
Marco (SE&O)
0

#4 User is offline   sensorario 

  • Elite Member
  • Yii
  • Group: Moderators
  • Posts: 1,986
  • Joined: 07-September 10
  • Location:Cesena (Italy)

Posted 23 June 2011 - 04:12 AM

Lo sbaglio è il sito di origine che è in asp. No dai scherzo. Guarda, ragionando ad oggetti ho imparato che il codice deve fare una cosa alla volta. Quindi, per farla breve, secondo me devi togliere le echo da questa pagina, ed usarne un'altra che restituisce la stringa "aggiornate ... ... ...". Quello che ci hai mostrato io lo lancerei in background senza controllare nulla.

tornando all'inizio di questo intervento... actionImportaCategorie servirà appunto per importare le categorie mentre un'ipotetica actionVerificaAggiornamenti farebbe un "count di la" ... e ti restituirebbe il lavoro fatto.

Questo avrebbe anche lo scopo di isolare i contesti ed avere un codice più pulito. Però è un po' diverso da quello che mi hai chiesto. Funziona! Io, per esempio, nelle mie GUI cerco sempre di strutturare delle chiamate ajax del tipo Controller::action() che restituiscono dei json. la GUI richiede l'informazione, e con jquery animo la pagina. Ciascun comportamento ha un suo piccolo javascript ed un suo piccolo php.

Anche se non ho trovato la TUA soluzione, spero di averti dato degli spunti per trovarne di NUOVE.
0

#5 User is offline   Customsoft 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 36
  • Joined: 18-May 11
  • Location:Arzignano

Posted 23 June 2011 - 04:55 AM

View Postsensorario, on 23 June 2011 - 04:12 AM, said:

Questo avrebbe anche lo scopo di isolare i contesti ed avere un codice più pulito.


L'ho detto che mi stavo perdendo in un bicchier d'acqua ... appena riesco provo e ti faccio sapere com'è andata :-) intanto grazie.
Saluti
Marco (SE&O)
0

#6 User is offline   zaccaria 

  • Elite Member
  • PipPipPipPipPip
  • Yii
  • Group: Members
  • Posts: 2,232
  • Joined: 04-October 09
  • Location:Moscow

Posted 24 June 2011 - 01:23 AM

Anche io ho avuto esperienze di questo tipo, e il flush funziona in una maniera un po' strana.

In teoria funziona, ma in pratica sulla mia macchina di sviluppo e sul server c'erano evidenti differenze di tempo.

Secondo me se ci fosse piu' output funzionerebbe meglio.

Ovviamente il consiglio di sensorario e' ottimo, io non ho mai fatto cosi' perche' sono troppo pigro, ma la strada corretta e' quella che dice lui.
1

#7 User is offline   Customsoft 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 36
  • Joined: 18-May 11
  • Location:Arzignano

Posted 25 June 2011 - 03:41 PM

Rieccomi come promesso ho trovato il tempo di riscrivere la procedura ... e sto godendo come un riccio ... a dire il vero ho goduto di più per il 57% al referendum 2011, ma quello è un altro discorso.

Veniamo a noi.

Per fare quanto proposto da sensoriano non ho potuto usare le sessione in quanto vengono salvate alla fine del processo in background.

Mi son rigirato quindi su una tabella.
Inspiegabilmente (anzi se mi illuminate son contento!) il seguente codice non va:
      $objAvanzamento = new T2Avanzamento;
      $objAvanzamento->Azione = $sTab;
      $objAvanzamento->Valore = "11111222223333";
      $objAvanzamento->StatoAvanzamento = 1;
      $objAvanzamento->save();

in quanto non inserisce nessun record, ma con createCommand ho risolto la situazione
PS: la cosa triste è che il codice sopracitato in altri punti funziona :-S

Ma veniamo ai vari pezzi in modo ordinato cosi i posteri italiani potranno trovare la via aperta per gestire la situazione.

Prima facciamo la tabellina dove salvare le varie azioni:
CREATE TABLE `t2_avanzamento` (
  `Azione` char(50) NOT NULL,
  `Valore` text NOT NULL,
  `StatoAvanzamento` tinyint(3) unsigned NOT NULL default '0' COMMENT '0=finito; 1=in avanzamento;',
  PRIMARY KEY  (`Azione`)
);

Ho usato un tinyint per lo Stato ... si sa mai che in futuro invece di gestire solo 2 stati ne possano esser gestiti di più ...

Poi passiamo ad scrivere 2 righette di JS per richiamare il processo di background e impostare il controllo periodico dell'avanzamento.
      <script type="text/javascript">

        var sTab; 

        function aggiornaOutput() {
          $("#outputComando").load("/a/categorieImportaAvanzamento/"+sTab);
        } 

        $(".comando a").click(function() {
          var interval = setInterval("aggiornaOutput()", 1000);
          sTab = $(this).attr("title");
          $("#outputComando").load($(this).attr("href"), function(response, status, xhr) {
            clearInterval ( interval );
            aggiornaOutput();
          });
          return false;
        });

      </script>

Il JS ha una funzione aggiornaOutput che viene richiamata ogni secondo per ricevere l'avanzamento del lavoro lanciato con click sul link. Completato il caricamento della pagina viene cancellato il ciclo di aggiornamento e richiamato un'ultima volta la funzione per esser sicuro di avere il risultato finale dell'avanzamento.

Passiamo ora a gestire le action inserendo 3 funzioncine:
public function aggiornaAvanzamento( $objConn, $sTab, $sAvanzamento, $bFinito ){
    $objComm  = $objConn->createCommand( "REPLACE INTO t2_avanzamento
      (Azione, Valore, StatoAvanzamento) VALUES
      ('".$sTab."','".$sAvanzamento."',".$bFinito.");");
    $rowCount = $objComm->execute();
}

Questa funzioncina facile facile è solo per tenere più pulito il codice e si incarica di aggiornare la tabella. Avrei preferito usare il primo codice citato, ma non capisco come mai non salvi un picchio :-(. Se vedete qualche errore che mi sfugge fatemi sapere :-)

Procediamo con la procedura che deve girare in background al click sul link:
public function actionCategorieImporta()
  {
    $objConn  = Yii::app()->db;
    $sTab = $_GET['tab'];
    $sAvanzamento = '';
    $y = 0;
    $x = 0;
    $sSql = '';

    $objAvanzamento = new T2Avanzamento;
    $objRecord = $objAvanzamento->findByPk($sTab);

    if ( is_null($objRecord) || $objAvanzamento->StatoAvanzamento==0 ) {
      $nTempo = GetMicroTime();
      $sAvanzamento = "<b>Inizio recupero dati per ".$sTab."</b> ... (".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />";
      self::aggiornaAvanzamento($objConn,$sTab,$sAvanzamento,1);

      $sSql .= file_get_contents(URL_REMOTO.'/crea_sql.asp?tab='.$sTab);

      $sAvanzamento .= "Vettorializzazione dati ... (".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />";
      self::aggiornaAvanzamento($objConn,$sTab,$sAvanzamento,1);
      $aSql = explode("\n",$sSql);

      $sAvanzamento .= "Inizio inserimento/aggiornamento DB ... ".count($aSql)." aggiornamenti da effettuare... (".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />";
      self::aggiornaAvanzamento($objConn,$sTab,$sAvanzamento,1);

      $objComm  = $objConn->createCommand("SET foreign_key_checks = 0;");
      $rowCount = $objComm->execute();

      foreach ($aSql as $sSql) {
        if (trim($sSql)!='') {
          $objComm  = $objConn->createCommand($sSql);
          $rowCount = $objComm->execute();
        }
        $y++;
        $x += $rowCount;
        if ( ( $y % 1000)==0 ) {
          $sAvanzamento .= " - Aggiornate ".$y." righe con ".$y." query.(".number_format(GetMicroTime()-$nTempo,2)." sec.)<br />";
          self::aggiornaAvanzamento($objConn,$sTab,$sAvanzamento,1);
        }
      }
      $objComm  = $objConn->createCommand("SET foreign_key_checks = 1;");
      $rowCount = $objComm->execute();
      $sAvanzamento .= " - Aggiornate ".$y." righe con ".$y." query.(".number_format(GetMicroTime()-$nTempo,2)." sec.)<br /><br /><b>IMPORTAZIONE COMPLETATA!</b><br /><br />";

      self::aggiornaAvanzamento($objConn,$sTab,$sAvanzamento,0);
    }
  }

Controllo che non sia già in esecuzione la stessa operazione e poi salvo nel DB tutti i passaggi.

Non rimane quindi che la risposta alle richieste sull'avanzamento fatte ogni secondo(tempo medio di spazientimento dell'utente):
public function actionCategorieImportaAvanzamento()
  {
    $sTab = $_GET['tab'];
    $objAvanzamento = new T2Avanzamento;
    $objRecord = $objAvanzamento->findByPk($sTab);
    echo $objRecord->Valore;
  }


RISULTATO FINALE:

Quote

Inizio recupero dati per xxxxxxxxx ... (0.00 sec.)
Vettorializzazione dati ... (16.69 sec.)
Inizio inserimento/aggiornamento DB ... 22270 aggiornamenti da effettuare... (16.72 sec.)
- Aggiornate 1000 righe con 1000 query.(18.15 sec.)
- Aggiornate 2000 righe con 2000 query.(19.15 sec.)
- Aggiornate 3000 righe con 3000 query.(20.19 sec.)
- Aggiornate 4000 righe con 4000 query.(21.21 sec.)
- Aggiornate 5000 righe con 5000 query.(22.97 sec.)
- Aggiornate 6000 righe con 6000 query.(23.92 sec.)
- Aggiornate 7000 righe con 7000 query.(24.87 sec.)
- Aggiornate 8000 righe con 8000 query.(25.87 sec.)
- Aggiornate 9000 righe con 9000 query.(26.72 sec.)
- Aggiornate 10000 righe con 10000 query.(28.18 sec.)
- Aggiornate 11000 righe con 11000 query.(29.03 sec.)
- Aggiornate 12000 righe con 12000 query.(29.92 sec.)
- Aggiornate 13000 righe con 13000 query.(31.11 sec.)
- Aggiornate 14000 righe con 14000 query.(32.08 sec.)
- Aggiornate 15000 righe con 15000 query.(33.42 sec.)
- Aggiornate 16000 righe con 16000 query.(34.34 sec.)
- Aggiornate 17000 righe con 17000 query.(35.27 sec.)
- Aggiornate 18000 righe con 18000 query.(36.34 sec.)
- Aggiornate 19000 righe con 19000 query.(37.29 sec.)
- Aggiornate 20000 righe con 20000 query.(38.26 sec.)
- Aggiornate 21000 righe con 21000 query.(39.18 sec.)
- Aggiornate 22000 righe con 22000 query.(40.20 sec.)
- Aggiornate 22270 righe con 22270 query.(40.43 sec.)

IMPORTAZIONE COMPLETATA!

Ora voi lo vedete tutto assieme ... io mi son goduto l'apparir delle singole righe ogni secondo :-P

Che dite? Potevo fare diversamente in qualche punto? Qualcosa di migliorabile? Ogni suggerimento è ben accetto :-)

Saluti
Marco (SE&O)
Saluti
Marco (SE&O)
0

#8 User is offline   Customsoft 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 36
  • Joined: 18-May 11
  • Location:Arzignano

Posted 25 June 2011 - 03:45 PM

View Postsensorario, on 23 June 2011 - 04:12 AM, said:

Lo sbaglio è il sito di origine che è in asp.


Mi avevano detto funzionava il php ... e non funzionava.
Alla fine ho dovuto pure imparare i comandi MsSql :-)

Vabbè devo solo copiare dei dati per qualche settimana, poi si passa sui nuovi server Linux con PHP e Mysql ;-)

Saluti
Marco (SE&O)
Saluti
Marco (SE&O)
0

#9 User is offline   sensorario 

  • Elite Member
  • Yii
  • Group: Moderators
  • Posts: 1,986
  • Joined: 07-September 10
  • Location:Cesena (Italy)

Posted 27 June 2011 - 02:57 AM

La parte migliorabile è senz'altro nell'astrazione del codice. E' un concetto un po' strano: detto in un italiano migliore: secondo me ora dovresti cercare di scrivere codice più integrato in Yii. Non farlo non è grave. Mettiti nei panni di un'altra persona che conosce Yii ma non conosce te e non può parlare con te. Se deve mettere mano sul tuo codice non sa che pattern hai usato.

L'uni consiglio chiaro che posso darti è questo:
    $.getJSON('index.php?json=json/buildable',function(data){
        alert(data.campo);
    });


Colgo anche l'occasione per mostrarvi un browser game dove faccio un uso pesante (troppo pesante ed al momento anche mal gestito) di questa architettura:

https://github.com/s...ascript/yago.js

Il front-end fa delle chiamate che restituiscono un json. Ciascuna chiamata mi da json differenti. Lo stesso front-end, javascript, modifica la pagina. Anzi ... visto che un paio di giorni fa ho deciso di rendere open source il mio browser game =) se vi va di forkare, sviluppare con me a me farebbe piacere. Non è basato su yii ma mi sono lasciato ispirare da alcuni concetti.
0

#10 User is offline   Customsoft 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 36
  • Joined: 18-May 11
  • Location:Arzignano

Posted 30 June 2011 - 08:34 AM

View Postsensorario, on 27 June 2011 - 02:57 AM, said:

Mettiti nei panni di un'altra persona che conosce Yii ma non conosce te e non può parlare con te. Se deve mettere mano sul tuo codice non sa che pattern hai usato.


Uno dei motivo per cui ho cominciato ad usare YII è proprio quello di avere una base comune su cui lavorare in gruppo su alcuni progetti opensouce che sto pensando di fare...però non ho capito, seppur sia il mio intento, quello che intendi. Ossia da un punto di vista pratico puoi illuminarmi più chiaramente sulle migliorie di cui parli?

Ovviamente chiunque si voglia cimentare in esempi esplicativi e migliorie è ben accetto ... tanto per cominciare a parlar la stessa lingua :-D
Saluti
Marco (SE&O)
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users