2015-06-19 24 views
9

La mia applicazione può eseguire fino a 180 processi AJAX ad alto utilizzo di IO sul lato server (lunghe interrogazioni SELECT).Richieste AJAX parallele in jQuery

Vorrei ottimizzare il carico dei più core CPU che ho a disposizione, passando da un progetto in cui ogni chiamata AJAX viene eseguita in sequenza a un progetto in cui queste richieste vengono eseguite con un massimo di, ad esempio, 4 in parallelo.

Una possibile soluzione, ma brutto potrebbe essere emette tutti i 180 richieste al tempo stesso sul client e hanno utilizzare il server un Semaphore conservato a Session o Application livello. Discuterò in seguito sui carichi di lavoro dell'applicazione.

Mi piacerebbe trovare una soluzione migliore in cui le chiamate siano tutte avviate in ordine (ogni riga di una tabella è una query di controllo diversa) ma quando qualcuno termina, viene avviato il successivo e c'è un numero (in particolare 4) di richieste AJAX simultanee con i rispettivi indicatori del caricatore.

Ho provato ad utilizzare Threadpool-js ma ho trovato me stesso che non posso usare jQuery dai lavoratori

Il mio codice attuale è la seguente

function GlobalCheck() { //entry point 
     if (ValidateDate()) { 
      //Below are global variables 
      list = $(".chkClass:checked"); //Only checked rows deal to AJAX request 
      num = $(".chkClass:checked").length; //Total number of ajax calls 
      done = 0; //Count of complete calls. When it reaches num we are done! 

      if (list.length == 0) { 
       alert('...'); 
       return; 
      } 

      $(".pMessage").fadeOut(); 
      $(".tbStatus").html(''); 
      $(".submit").hide(); 
      $(".exportFunctions").fadeOut(); 
      $(".loader").show(); 
      $(":checkbox").attr('disabled', true); 

      SingleCheck(0); //simplification, I do other non interesting things here 
     } 
    } 


function SingleCheck(index) { 
     aValue = $($(list).get(index)).val(); 

     var splitted = aValue.split('_'); 
     $('#loader_' + aValue).show(); 
     $('#green_' + aValue).hide(); 
     $('#yellow_' + aValue).hide(); 
     $('#red_' + aValue).hide(); 
     $('#print_' + aValue).hide(); 
     $('#xls_' + aValue).hide(); 
     $('#summ_' + aValue).hide(); 

     $.ajax({ 
      type: 'GET', 
      url: '@Url.Action("Single", "Check")', 
      data: { 
       pType: splitted[0], 
       pIdQuery: splitted[1], 
       pDateBegin: $('#date_begin').attr('value'), 
       pDateEnd: $('#date_end').attr('value'), 
       pNow: Math.floor(Math.random() * 1000000) 
      }, 
      success: function (data) { 
       if (!CheckSessionExpired(data)) { 
        //alert(data); 

        $("#tdStatus_" + aValue).html(data); 
        $("#loader_" + aValue).hide(); 
        done++; //Done 1 more query 
        $(".progress").each(function (i, cRow) { $(this).html([update status]); }); 

        if (done == num) { // Finish? 
         FinishCheck(); 
        } 
        else { 
         SingleCheck(done); //Go to the next 
        } 
       } 
      }, 
      error: function (XMLHttpRequest, textStatus, errorThrown) { 
       alert(errorThrown); 
       RedirectToError(); 
      } 
     }); 
    } 

risultato è il seguente:

Auitool

La domanda è: quale approccio posso seguire per creare richieste AJAX simultanee nel mio scenario?

[modifica] dimenticato di discutere le richieste delle applicazioni: questa applicazione è in esecuzione dal vivo ma non serve una vasta base di utenti. Quando un utente invia i dati da controllare, l'applicazione eseguirà operazioni intensive, rimanendo inattiva per lunghi periodi di tempo.

risposta

2

$.ajax() è una funzione asincrona che avvia una richiesta e quindi restituisce immediatamente. Quindi, se lo chiami più volte di seguito, creerà richieste simultanee.

Il codice viene eseguito ancora su un singolo thread, ma le richieste HTTP si verificano in parallelo in background e jQuery richiama i callback mentre restituiscono i dati. Quindi ottieni il parallelismo senza dover affrontare direttamente i thread.

Nel vostro GlobalCheck():

var CONCURRENT_REQUESTS = 4; 

while (done < CONCURRENT_REQUESTS) { 
    SingleCheck(done++); 
} 

inizierà quattro richieste parallele, e il codice esistente attiveranno una nuova richiesta ogni volta che uno finiture, in modo da avere sempre 4 richieste parallele in esecuzione. E poiché il codice funziona solo su un singolo thread, non c'è bisogno di preoccuparsi di problemi di concorrenza con il done variabile ecc

Per richieste più simultanee, basta aumentare il valore di CONCURRENT_REQUESTS, ma nota che molto rapidamente colpirai il limite di richieste simultanee del browser a un singolo dominio: varia a seconda del browser ma è sempre un numero piuttosto ridotto. See this answer for specifics.

1

Quando, ad esempio, si ha una chiamata ajax in una funzione "doCall", avviare questa funzione per un'adeguata quantità di x sui "thread" desiderati.

Ora avete 3 fili. Per continuare, "riavvia" la funzione nella funzione. Quindi nella funzione doCall hai un altro doCall (x) per "mantenere il thread vivo".

Si avrà una sorta di "loop" e le richieste continueranno a essere attivate in modo asincrono.

0

A mio parere è necessario un array "nbRequest" per sapere quante richieste si sta lavorando. (4 max)

Quindi utilizzare setInterval.

Avviare l'intervallo, memorizzare il "num" all'interno di "nbRequest". Al termine della richiesta Ajax, rimuovere il "num" da "nbRequest".

Nel frattempo, l'intervallo controllerà se la lunghezza di "nbRequest" è uguale a 4. In caso contrario, si avvia una nuova richiesta.

Se "done == num", interrompere l'intervallo.

0

Nota: il numero di richieste concorrenti che i browser possono eseguire su un determinato dominio è limitato. Quindi potresti sparare tutte le tue richieste contemporaneamente, il browser si occuperà di metterle in coda e di eseguire solo da 6 a 8 contemporaneamente.

Fonte

: Max parallel http connections in a browser?

Tuttavia, se si desidera un controllo più preciso, si potrebbe implementare qualcosa di simile:

//define your list of URLs and what to do with the data 
var sources = [ 
    { 
     url : "http://...", 
     callback : function(data){ /* do something */} 
    }, 
    { 
     url : "http://...", 
     callback : function(data){ /* do something */} 
    } 
]; 

//state 
var maxConcurrentRequests = 4; 
var concurrentRequests = 0; 
var currentSourceIndex = -1; 

//this function wil ensure that as long as there are sources left, there are 4 requests running 
function startRequestIfNeeded(){ 

    while(currentSourceIndex < sources.length-1 && concurrentRequests < maxConcurrentRequests){ 
     currentSourceIndex++; 
     concurrentRequests++; 
     var source = sources[sourceIndex]; 
     doRequest(source); 
    } 
} 

//this fires the request and executes the callback 
function doRequest(source){ 

    $.getJSON(source.url, function(data){ 
     source.callback(data); 
     concurrentRequests--; 
     startRequestIfNeeded(); 
    }); 
} 

startRequestIfNeeded(); 

Lascio la gestione a voi errore.

E se sarà necessario aggiungere logica se si desidera rilevare quando tutte le richieste sono state fatte. Forse guarda alle promesse.

+0

Grazie, ho aggiornato la mia risposta di conseguenza e collegato alla domanda più aggiornata. –

Problemi correlati