2013-02-26 9 views
5

Utilizzando Django (ospitato da Webfaction), ho il seguente codiceDjango, sleep() mette in pausa tutti i processi, ma solo se nessun parametro GET?

import time 
def my_function(request): 
    time.sleep(10) 
    return HttpResponse("Done") 

Questo viene eseguito attraverso Django quando vado al mio url, www.mysite.com

ho inserire l'URL due volte, subito uno dopo l'altro. Per come la vedo io, entrambi dovrebbero finire dopo 10 secondi. Tuttavia, la seconda chiamata attende il primo e termina dopo 20 secondi.

Se, tuttavia, io entro alcuni parametri GET fittizio, www.mysite.com?dummy=1 e www.mysite.com?dummy=2 poi entrambi finitura dopo 10 secondi. Quindi è possibile che entrambi funzionino contemporaneamente.

È come se l'ambito di sleep() sia in qualche modo globale ?? Forse inserire un parametro li fa correre come processi diversi invece degli stessi ???

È ospitato da Webfaction. httpd.conf ha:

KeepAlive Off 
Listen 30961 
MaxSpareThreads 3 
MinSpareThreads 1 
ServerLimit 1 
SetEnvIf X-Forwarded-SSL on HTTPS=1 
ThreadsPerChild 5 

ho bisogno di essere in grado di usare sleep() e la fiducia che non si ferma tutto. Allora, come va e come risolverlo?

Modifica: Webfaction esegue questo utilizzando Apache.

+0

Qual è il caso d'uso per l'uso di "sonno"? Sembra che tu stia facendo qualcosa di molto strano se vuoi usarlo in un ciclo di richiesta/risposta. Forse potresti spiegare cosa stai cercando di fare e possiamo suggerire alternative. –

risposta

8

Come sottolineato da Gjord, il sonno interromperà il thread corrente. Ho visto Webfaction e sembra che stiano usando WSGI per l'esecuzione dell'istanza di Django. Ciò significa che, ogni volta che una richiesta arriva, Apache analizzerà quanti processi di lavoro (ovvero processi che eseguono ciascuna un'istanza di Django) sono attualmente in esecuzione. Se non ce ne sono/per vederlo genererà additivamente lavoratori e passerà loro le richieste.

Ecco quello che penso sta accadendo in te situazione:.

  • prima richiesta GET per la risorsa A è disponibile in Apache utilizza un lavoratore in esecuzione (o inizia uno nuovo)
  • il lavoratore può ospitare 10 secondi
  • durante questo, una nuova richiesta per la risorsa A entra. Apache vede che sta richiedendo la stessa risorsa e lo invia allo stesso lavoratore come per la richiesta A. Immagino che qui si assuma che un lavoratore che elabora di recente una richiesta di una risorsa specifica è più probabile che il lavoratore abbia alcune informazioni memorizzate nella cache/preprocessate/qualsiasi altra cosa in modo che possa avere ndle questa richiesta più veloce
  • questo si traduce in un secondo blocco 20 in quanto c'è solo il lavoratore che attende 2 volte 10 secondi

Questo comportamento ha un senso del tutto il 99% del tempo quindi è logico fare questo su di default .

Tuttavia, se si modifica la risorsa richiesta per la seconda richiesta (aggiungendo il parametro GET) Apache assumerà che questa è una risorsa diversa e avvierà un altro worker (poiché il primo è già "occupato" (Apache non può sappi che non stai facendo alcun lavoro duro.) Dato che ora ci sono due operatori, entrambi in attesa di 10 secondi, il tempo totale scende a 10 secondi.


Inoltre, suppongo che qualcosa sia errato con il tuo disegno. Non ci sono quasi casi in cui posso pensare a dove sarebbe ragionevole non rispondere a una richiesta HTTP il più velocemente possibile. Dopotutto, vuoi servire quante più richieste possibili nel più breve tempo possibile, quindi dormire 10 secondi è la cosa più controproducente che puoi fare. Ti consiglierei di creare una nuova domanda e di indicare quale obiettivo reale stai cercando di raggiungere. Sono abbastanza sicuro che ci sia una soluzione più ragionevole a questo!

+0

Grazie per l'analisi. Anche senza dormire, ci sono molti motivi per cui NON vorrei che le chiamate si svolgessero nello stesso thread. Ad esempio, se una chiamata sta cercando informazioni da un altro sito web. urlopen() può essere lento in attesa di una risposta e mi dispiacerebbe che ogni chiamata fosse in attesa in fila per il completamento delle altre chiamate. O una lenta query del database. Farò un'altra domanda su come avviare ogni chiamata in una nuova discussione. – user984003

+0

Django è single-threaded, quindi sarà sempre un problema. Se hai bisogno di cose asincrone e non bloccanti, probabilmente vorrai dare un'occhiata a qualcosa come Tornado. –

3

Supponendo di eseguire il server Django solo con run(), per impostazione predefinita questo rende un server a thread singolo. Se si utilizza lo stato di sospensione su un singolo processo con thread, l'intera applicazione si blocca per tale tempo di sospensione.

+0

Quindi non posso usare sleep() perché questo influenzerà ogni chiamata ?? È solo un problema di Django? Ho bisogno di un modo per mettere in pausa le mie funzioni senza che ogni chiamata venga messa in pausa. – user984003

+0

BTW, non sono sicuro che l'uso di Django significhi automaticamente che sto utilizzando il server Django. Webfaction utilizza Apache. – user984003

+0

Buon punto, l'effetto sembra ancora lo stesso. Solo un thread gestisce entrambe le richieste, se entrambe si appendono a – Gjordis

1

Può essere semplicemente che il browser stia accodando la seconda richiesta da eseguire solo dopo il completamento della prima. Se apri i tuoi URL nello stesso browser, prova a utilizzarne due diversi (ad esempio Firefox e Chrome) oppure prova ad eseguire richieste dalla riga di comando utilizzando wget o curl.