Qual è la differenza tra chiamate asincrone e non bloccanti? Anche tra blocco e chiamate sincrone (con esempi per favore)?
Qual è la differenza tra chiamate asincrone e non bloccanti? Anche tra blocco e chiamate sincrone (con esempi per favore)?
Risposte:
In molte circostanze sono nomi diversi per la stessa cosa, ma in alcuni contesti sono abbastanza diversi. Quindi dipende. La terminologia non viene applicata in modo totalmente coerente in tutto il settore del software.
Ad esempio, nella classica API socket, un socket non bloccante è un socket che ritorna immediatamente immediatamente con uno speciale messaggio di errore "bloccherebbe", mentre un socket bloccante avrebbe bloccato. Devi usare una funzione separata come select
o poll
per scoprire quando è il momento giusto per riprovare.
Ma i socket asincroni (come supportati dai socket di Windows) o il modello IO asincrono utilizzato in .NET sono più convenienti. Si chiama un metodo per avviare un'operazione e il framework ti richiama al termine. Anche qui, ci sono differenze fondamentali. I socket asincroni Win32 "eseguono il marshalling dei risultati su uno specifico thread della GUI passando messaggi di Windows, mentre IO asincrono .NET è a thread libero (non sai su quale thread verrà chiamato il callback).
Quindi non significano sempre la stessa cosa. Per distillare l'esempio del socket, potremmo dire:
sincrono / asincrono è descrivere la relazione tra due moduli.
blocco / non blocco è descrivere la situazione di un modulo.
Un esempio:
Modulo X: "I".
Modulo Y: "libreria".
X chiede Y: hai un libro chiamato "c ++ primer"?
1) blocco: prima che Y risponda X, X continua ad aspettare lì per la risposta. Ora X (un modulo) sta bloccando. X e Y sono due thread o due processi o un thread o un processo? non lo sappiamo.
2) non bloccante: prima che Y risponda X, X lascia semplicemente lì e fa altre cose. X può tornare ogni due minuti per verificare se Y ha terminato il suo lavoro? O X non tornerà finché Y non lo chiamerà? Non lo sappiamo. Sappiamo solo che X può fare altre cose prima che Y finisca il suo lavoro. Qui X (un modulo) non è bloccante. X e Y sono due thread o due processi o un processo? non lo sappiamo. MA siamo sicuri che X e Y non possano essere un thread.
3) sincrono: prima che Y risponda X, X continua ad aspettare lì per la risposta. Significa che X non può continuare fino a quando Y non termina il suo lavoro. Ora diciamo: X e Y (due moduli) sono sincroni. X e Y sono due thread o due processi o un thread o un processo? non lo sappiamo.
4) asincrono: prima che Y risponda X, X lascia lì e X può fare altri lavori. X non tornerà finché Y non lo chiamerà. Ora diciamo: X e Y (due moduli) sono asincroni. X e Y sono due thread o due processi o un processo? non lo sappiamo. MA siamo sicuri che X e Y non possano essere un thread.
Si prega di prestare attenzione alle due frasi in grassetto sopra. Perché la frase in grassetto nel 2) contiene due casi mentre la frase in grassetto nel 4) contiene solo un caso? Questa è una chiave della differenza tra non bloccante e asincrona.
Ecco un tipico esempio di non blocco e sincrono:
// thread X
while (true)
{
msg = recv(Y, NON_BLOCKING_FLAG);
if (msg is not empty)
{
break;
}
sleep(2000); // 2 sec
}
// thread Y
// prepare the book for X
send(X, book);
Puoi vedere che questo design non è bloccante (puoi dire che la maggior parte delle volte questo loop fa qualcosa di insensato ma agli occhi della CPU, X è in esecuzione, il che significa che X è non bloccante) mentre X e Y sono sincroni perché X può continuerai a fare qualsiasi altra cosa (X non può saltare fuori dal ciclo) fino a quando non ottiene il libro da Y.
Normalmente in questo caso, rendere il blocco X è molto meglio perché il non-blocco spende molte risorse per un ciclo stupido. Ma questo esempio è utile per aiutarti a capire il fatto: non bloccare non significa asincrono.
Le quattro parole ci rendono facilmente confusi, ciò che dovremmo ricordare è che le quattro parole servono per la progettazione dell'architettura. Imparare a progettare una buona architettura è l'unico modo per distinguerli.
Ad esempio, possiamo progettare un tale tipo di architettura:
// Module X = Module X1 + Module X2
// Module X1
while (true)
{
msg = recv(many_other_modules, NON_BLOCKING_FLAG);
if (msg is not null)
{
if (msg == "done")
{
break;
}
// create a thread to process msg
}
sleep(2000); // 2 sec
}
// Module X2
broadcast("I got the book from Y");
// Module Y
// prepare the book for X
send(X, book);
Nell'esempio qui, possiamo dirlo
Se necessario, puoi anche descrivere quei thread creati in X1 con le quattro parole.
Le cose più importanti sono: quando utilizziamo sincrono anziché asincrono? quando utilizziamo il blocco anziché il non blocco?
Perché Nginx non è bloccante? Perché il blocco di Apache?
Per fare una buona scelta, devi analizzare le tue necessità e testare le prestazioni di diverse architetture. Non esiste un'architettura simile adatta a varie esigenze.
Mettendo questa domanda nel contesto di NIO e NIO.2 in java 7, l'IO asincrono è un passo più avanzato rispetto al non blocco. Con le chiamate non bloccanti NIO Java, si impostano tutti i canali (SocketChannel, ServerSocketChannel, FileChannel, ecc.) Come tali chiamando AbstractSelectableChannel.configureBlocking(false)
. Dopo il ritorno di quelle chiamate IO, tuttavia, sarà probabilmente necessario controllare i controlli come se e quando rileggere / scrivere, ecc.
Ad esempio,
while (!isDataEnough()) {
socketchannel.read(inputBuffer);
// do something else and then read again
}
Con l'API asincrono di Java 7, questi controlli possono essere realizzati in modi più versatili. Uno dei 2 modi è usare CompletionHandler
. Si noti che entrambe le read
chiamate non sono bloccanti.
asyncsocket.read(inputBuffer, 60, TimeUnit.SECONDS /* 60 secs for timeout */,
new CompletionHandler<Integer, Object>() {
public void completed(Integer result, Object attachment) {...}
public void failed(Throwable e, Object attachment) {...}
}
}
FileChannel
non è selezionabile e non può essere configurato per non bloccare.
Come probabilmente puoi vedere dalla moltitudine di risposte diverse (e spesso reciprocamente esclusive), dipende da chi chiedi. In alcune arene, i termini sono sinonimi. Oppure potrebbero riferirsi a due concetti simili:
In entrambi i casi, l'intenzione è quella di non bloccare il programma in attesa del completamento di un processo lento: l'unica vera differenza è la risposta del programma. Quale termine si riferisce a quale cambia anche da programmatore a programmatore, da lingua a lingua o da piattaforma a piattaforma. Oppure i termini possono riferirsi a concetti completamente diversi (come l'uso di sincrono / asincrono in relazione alla programmazione di thread).
Ci dispiace, ma non credo che ci sia una sola risposta giusta che sia globalmente vera.
Una chiamata non bloccante ritorna immediatamente con tutti i dati disponibili: il numero completo di byte richiesti, meno o nessuno.
Una chiamata asincrona richiede un trasferimento che verrà eseguito nella sua interezza (totalità) ma verrà completato in futuro.
Non bloccante: questa funzione non attende mentre si trova nello stack.
Asincrono: il lavoro può continuare per conto della chiamata di funzione dopo che quella chiamata ha lasciato lo stack
Sincrono è definito come accadendo contemporaneamente.
L'asincrono viene definito come non accada contemporaneamente.
Questo è ciò che provoca la prima confusione. Sincrono è in realtà ciò che è noto come parallelo. Mentre asincrono è sequenziale, farlo, quindi farlo.
Ora l'intero problema riguarda la modellazione di un comportamento asincrono, perché hai alcune operazioni che richiedono la risposta di un'altra prima che possa iniziare. Quindi è un problema di coordinamento, come farai a sapere che ora puoi iniziare quell'operazione?
La soluzione più semplice è nota come blocco.
Il blocco si verifica quando si sceglie semplicemente di attendere che venga eseguita l'altra cosa e si restituisca una risposta prima di passare all'operazione che ne aveva bisogno.
Quindi, se hai bisogno di mettere il burro su pane tostato, e quindi devi prima tostare l'allevamento. Il modo in cui li coordineresti è che prima brindavi all'allevamento, poi fissavi all'infinito il tostapane fino a quando non fa scoppiare il toast, e poi procedi a metterli sopra il burro.
È la soluzione più semplice e funziona molto bene. Non c'è alcun motivo reale per non usarlo, a meno che tu non abbia anche altre cose che devi fare che non richiedono il coordinamento con le operazioni. Ad esempio, facendo alcuni piatti. Perché aspettare fissando costantemente il tostapane per far scoppiare il toast, quando sai che ci vorrà un po 'di tempo e potresti lavare un intero piatto mentre finisce?
È qui che entrano in gioco altre due soluzioni note rispettivamente come non bloccanti e asincrone.
Il blocco non è quando si sceglie di fare altre cose non correlate mentre si attende che l'operazione venga eseguita. Verifica la disponibilità della risposta come ritieni opportuno.
Quindi, invece di guardare il tostapane per farlo scoppiare. Vai a lavare un piatto intero. E poi dai un'occhiata al tostapane per vedere se sono spuntati i toast. Se non l'hanno fatto, vai a lavare un altro piatto, controllando il tostapane tra ogni piatto. Quando vedi che i toast sono scoppiati, smetti di lavare i piatti e invece prendi il toast e vai a metterli sopra il burro.
Dover controllare costantemente i toast può essere fastidioso, immagina che il tostapane sia in un'altra stanza. Tra un piatto e l'altro perdi il tuo tempo andando in quell'altra stanza per controllare il toast.
Ecco che arriva asincrono.
Asincrono è quando si sceglie di fare altre cose non correlate mentre si attende che l'operazione venga eseguita. Invece di controllarlo, però, deleghi il lavoro di verifica a qualcos'altro, potrebbe essere l'operazione stessa o un osservatore, e hai quella cosa avvisare e possibilmente interrompere te quando la risposta è disponibile in modo da poter procedere con l'altra operazione che ne avevo bisogno.
È una strana terminologia. Non ha molto senso, dal momento che tutte queste soluzioni sono modi per creare un coordinamento asincrono di attività dipendenti. Ecco perché preferisco chiamarlo evented.
Quindi, per questo, decidi di aggiornare il tuo tostapane in modo che emetta un segnale acustico al termine dei toast. Ti capita di ascoltare costantemente, anche mentre fai i piatti. Ascoltando il segnale acustico, ti metti in coda in memoria che non appena avrai finito di lavare il tuo attuale piatto, ti fermerai e andrai a mettere il burro sul toast. Oppure potresti scegliere di interrompere il lavaggio del piatto attuale e occuparti subito del brindisi.
Se hai problemi ad ascoltare il segnale acustico, puoi chiedere al tuo partner di guardare il tostapane e venire a dirti quando il brindisi è pronto. Il tuo partner può scegliere una delle tre strategie precedenti per coordinare il suo compito di guardare il tostapane e dirti quando sono pronti.
In ultima analisi, è bene capire che mentre non-blocking e async (o quello che preferisco chiamare evented) ti permettono di fare altre cose mentre aspetti, non ce l'hai anche. Puoi scegliere di eseguire un ciclo continuo per controllare lo stato di una chiamata non bloccante, senza fare altro. Tuttavia, spesso è peggio del blocco (come guardare il tostapane, quindi allontanarlo, quindi riprovare fino al suo completamento), quindi molte API non bloccanti ti consentono di passare a una modalità di blocco da esso. Per quanto riguarda gli eventi, puoi semplicemente attendere inattivo fino a quando non ricevi una notifica. L'aspetto negativo in quel caso è che l'aggiunta della notifica è stata complessa e potenzialmente costosa all'inizio. Dovevi comprare un nuovo tostapane con la funzione bip o convincere il tuo partner a guardarlo per te.
E un'altra cosa, è necessario rendersi conto dei compromessi forniti da tutti e tre. Uno non è ovviamente migliore degli altri. Pensa al mio esempio. Se il tuo tostapane è così veloce, non avrai il tempo di lavare un piatto, nemmeno iniziare a lavarlo, ecco quanto è veloce il tuo tostapane. Iniziare a fare qualcos'altro in quel caso è solo una perdita di tempo e fatica. Il blocco lo farà. Allo stesso modo, se lavare un piatto impiegherà 10 volte di più della tostatura. Devi chiederti cosa c'è di più importante da fare? Il brindisi potrebbe diventare freddo e duro a quel punto, non ne vale la pena, anche il blocco farà. Oppure dovresti scegliere cose più veloci da fare mentre aspetti. C'è di più ovviamente, ma la mia risposta è già piuttosto lunga, il mio punto è che devi pensare a tutto ciò e alle complessità dell'implementazione di ciascuno per decidere se ne valga la pena e se '
Modificare:
Anche se questo è già lungo, voglio anche che sia completo, quindi aggiungerò altri due punti.
1) Esiste anche comunemente un quarto modello noto come multiplexato . Questo è quando mentre aspetti un'attività, ne avvii un'altra e mentre aspetti entrambe, ne avvii un'altra e così via, fino a quando non hai molte attività tutte avviate e poi, aspetti inattivo, ma su tutto loro. Quindi appena hai finito, puoi procedere con la gestione della sua risposta e poi tornare ad aspettare gli altri. È noto come multiplex, perché mentre aspetti, devi controllare ogni attività una dopo l'altra per vedere se sono state completate, ad vitam, fino a quando non lo sei. È un po 'un'estensione oltre al normale non bloccante.
Nel nostro esempio sarebbe come avviare il tostapane, quindi la lavastoviglie, quindi il forno a microonde, ecc. E poi aspettare su uno di essi. Dove controlleresti il tostapane per vedere se è fatto, in caso contrario, controlleresti la lavastoviglie, in caso contrario, il microonde e ancora.
2) Anche se credo che sia un grosso errore, sincrono è spesso usato per significare una cosa alla volta. E asincrone molte cose alla volta. In questo modo vedrai il blocco sincrono e il non blocco usati per riferirsi al blocco e al non blocco. E il blocco asincrono e il non-blocco utilizzati per riferirsi a multiplexing ed evented.
Non capisco davvero come ci siamo arrivati. Ma quando si tratta di IO e calcolo, sincrono e asincrono si riferiscono spesso a ciò che è meglio noto come non sovrapposto e sovrapposto. Cioè, asincrono significa che IO e calcolo sono sovrapposti, ovvero che avvengono contemporaneamente. Mentre sincrono significa che non lo sono, quindi accadendo in sequenza. Per il non blocco sincrono, ciò significherebbe che non si avvia un altro IO o calcolo, si deve solo aspettare e simulare una chiamata di blocco. Vorrei che le persone smettessero di abusare sincrono e asincrono in quel modo. Quindi non lo sto incoraggiando.
Blocco della chiamata: il controllo ritorna solo al termine della chiamata.
Chiamata senza blocco : il controllo ritorna immediatamente. Il sistema operativo successivo in qualche modo notifica al processo che la chiamata è completa.
Programma sincrono : un programma che utilizza il blocco delle chiamate. Per non bloccarsi durante la chiamata, deve contenere 2 o più thread (ecco perché si chiama Synchronous: i thread vengono eseguiti in modo sincrono).
Programma asincrono : un programma che utilizza chiamate senza blocco . Può avere solo 1 thread e rimane comunque interattivo.
Differiscono solo per l'ortografia. Non vi è alcuna differenza in ciò a cui si riferiscono. Per essere tecnici potresti dire che differiscono per enfasi. Il non blocco si riferisce al flusso di controllo (non blocca.) Asincrono si riferisce a quando l'evento \ dati viene gestito (non in modo sincrono).
I modelli di blocco richiedono che l'applicazione di avvio si blocchi all'avvio dell'I / O. Ciò significa che non è possibile sovrapporre elaborazione e I / O contemporaneamente. Il modello sincrono non bloccante consente la sovrapposizione di elaborazione e I / O, ma richiede che l'applicazione controlli lo stato dell'I / O su base ricorrente. Ciò lascia un I / O asincrono non bloccante, che consente la sovrapposizione di elaborazione e I / O, inclusa la notifica del completamento dell'I / O.
Blocco: il controllo ritorna al richiamo della precessione al termine dell'elaborazione della primitiva (sincronizzazione o asincronizzazione)
Non bloccante: il controllo ritorna al processo immediatamente dopo l'invocazione