Differenza tra dispatch_async e dispatch_sync sulla coda seriale?


125

Ho creato una coda seriale come questa:

    dispatch_queue_t _serialQueue = dispatch_queue_create("com.example.name", DISPATCH_QUEUE_SERIAL);

Qual è la differenza tra dispatch_asyncchiamato in questo modo

 dispatch_async(_serialQueue, ^{ /* TASK 1 */ });
 dispatch_async(_serialQueue, ^{ /* TASK 2 */ });

E dispatch_syncchiamato così in questa coda seriale?

 dispatch_sync(_serialQueue, ^{ /* TASK 1 */ });
 dispatch_sync(_serialQueue, ^{ /* TASK 2 */ });

La mia comprensione è che, indipendentemente dal metodo di spedizione utilizzato, TASK 1verrà eseguito e completato prima TASK 2, corretto?

Risposte:


409

Sì. L'uso della coda seriale garantisce l'esecuzione seriale delle attività. L'unica differenza è che dispatch_syncrestituisce solo dopo che il blocco è terminato mentre dispatch_asyncrestituisce dopo che è stato aggiunto alla coda e potrebbe non essere finito.

per questo codice

dispatch_async(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_async(_serialQueue, ^{ printf("3"); });
printf("4");

Può stampare 2413o 2143o 1234, ma 1sempre prima3

per questo codice

dispatch_sync(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_sync(_serialQueue, ^{ printf("3"); });
printf("4");

stampa sempre 1234


Nota: per il primo codice, non verrà stampato 1324. Perché printf("3")viene inviato dopo l' printf("2") esecuzione. E un'attività può essere eseguita solo dopo l'invio.


Il tempo di esecuzione delle attività non cambia nulla. Questo codice viene sempre stampato12

dispatch_async(_serialQueue, ^{ sleep(1000);printf("1"); });
dispatch_async(_serialQueue, ^{ printf("2"); });

Quello che può essere successo è

  • Discussione 1: dispatch_async un'attività che richiede tempo (attività 1) alla coda seriale
  • Discussione 2: inizia a eseguire l'attività 1
  • Discussione 1: dispatch_async un'altra attività (attività 2) alla coda seriale
  • Discussione 2: attività 1 terminata. iniziare a eseguire l'attività 2
  • Discussione 2: compito 2 finito.

e vedi sempre 12


7
può anche stampare 2134 e 1243
Matteo Gobbi

la mia domanda è: perché non l'abbiamo fatto nel modo normale? printf("1");printf("2") ;printf("3") ;printf("4")- rispetto adispatch_sync
androniennn,

@androniennn per il secondo esempio? perché alcuni altri thread potrebbero essere dispatch_sync(_serialQueue, ^{ /*change shared data*/ });in esecuzione contemporaneamente.
Bryan Chen,

1
@ asma22 È molto utile condividere un oggetto sicuro non thread tra più thread / code di invio. Se accedi solo all'oggetto in una coda seriale, sai che stai accedendo in modo sicuro.
Bryan Chen

1
Intendo un'esecuzione seriale . Dal punto di vista del fatto che tutte le attività vengono eseguite in serie rispetto ad altre attività nella stessa coda. Di causa può ancora essere in relazione ad altre code. È il punto centrale di GCD che le attività possono essere inviate ed eseguite contemporaneamente.
Bryan Chen,

19

La differenza tra dispatch_synce dispatch_asyncè semplice.

In entrambi i tuoi esempi, TASK 1verrà sempre eseguito prima TASK 2perché è stato inviato prima di esso.

Nel dispatch_syncesempio, tuttavia, non sarà possibile inviare TASK 2fino a dopo TASK 1sia stato spedito ed eseguito . Questo si chiama "blocco" . Il codice attende (o "blocchi") fino all'esecuzione dell'attività.

Nel dispatch_asyncesempio, il codice non aspetterà per l'esecuzione al completo. Entrambi i blocchi verranno inviati (e accodati) alla coda e il resto del codice continuerà l'esecuzione su quel thread. Quindi ad un certo punto in futuro, (a seconda di cos'altro è stato inviato alla tua coda), Task 1verrà eseguito e quindi Task 2verrà eseguito.


2
Penso che tu abbia sbagliato ordine. il primo esempio è asyncla versione non bloccante
Bryan Chen,

Ho modificato la tua risposta a ciò che penso intendevi . In caso contrario, si prega di cambiarlo e chiarire.
JRG-Developer

1
Cosa succede se si chiama dispatch_sync e quindi dispatch_async sulla stessa coda? (e viceversa)
0xSina,

1
Su una coda seriale, entrambe le attività vengono comunque eseguite una dopo l'altra. Nel primo caso, il chiamante attende il completamento del primo blocco ma non attende il secondo blocco. Nel secondo caso, il chiamante non attende il completamento del primo blocco, ma attende il secondo blocco. Ma poiché la coda esegue i blocchi in ordine, il chiamante attende effettivamente che entrambi finiscano.
gnasher729,

1
Un blocco potrebbe anche eseguire un dispatch_async sulla propria coda (aggiungendo ulteriori blocchi che verranno eseguiti in seguito); dispatch_sync sulla propria coda seriale o la coda principale si bloccherebbe. In questa situazione, il chiamante attenderà il completamento del blocco originale, ma non gli altri blocchi. Ricorda: dispatch_sync inserisce il blocco alla fine della coda, la coda esegue il codice fino a quando il blocco non è terminato, quindi restituisce dispatch_sync. dispatch_async aggiunge semplicemente il blocco alla fine della coda.
gnasher729,

5

È tutto correlato alla coda principale. Ci sono 4 permutazioni.

i) Coda seriale, invio asincrono: qui le attività verranno eseguite una dopo l'altra, ma il thread principale (effetto sull'interfaccia utente) non attenderà il ritorno

ii) Coda seriale, sincronizzazione invio: qui le attività verranno eseguite una dopo l'altra, ma il thread principale (effetto sull'interfaccia utente) mostrerà il ritardo

iii) Coda simultanea, invio asincrono: qui le attività verranno eseguite in parallelo e il thread principale (effetto sull'interfaccia utente) non attenderà il ritorno e sarà fluido.

iv) Coda simultanea, sincronizzazione invio: qui le attività verranno eseguite in parallelo, ma il thread principale (effetto sull'interfaccia utente) mostrerà il ritardo

La scelta della coda simultanea o seriale dipende dalla necessità di un output da un'attività precedente per la successiva. Se si dipende dall'attività precedente, adottare la coda seriale altrimenti prendere la coda simultanea.

E infine questo è un modo per tornare al thread principale quando abbiamo finito con la nostra attività:

DispatchQueue.main.async {
     // Do something here
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.