Seri kuyrukta dispatch_async ve dispatch_sync arasındaki fark nedir?


125

Bunun gibi bir seri kuyruk oluşturdum:

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

dispatch_asyncBuna benzer arasındaki fark nedir

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

Ve dispatch_syncbu seri kuyrukta böyle mi çağırıldı?

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

Anladığım kadarıyla, hangi gönderim yöntemi kullanılırsa kullanılsın, TASK 1daha önce yürütülecek ve tamamlanacak TASK 2, doğru mu?

Yanıtlar:


410

Evet. Seri kuyruğun kullanılması, görevlerin seri olarak yürütülmesini sağlar. Tek fark, dispatch_syncyalnızca blok bittikten dispatch_asyncsonra geri dönerken kuyruğa eklendikten sonra geri dönebilir ve tamamlanamayabilir.

bu kod için

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

Yazdırabilir 2413veya 2143veya 1234ancak 1her zaman önce3

bu kod için

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

her zaman yazdırır 1234


Not: İlk kod için yazdırılmaz 1324. Çünkü icra edildikten sonraprintf("3") gönderilir . Ve bir görev ancak gönderildikten sonra yürütülebilir . printf("2")


Görevlerin icra süresi hiçbir şeyi değiştirmez. Bu kod her zaman yazdırılır12

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

Ne olabilir

  • İş parçacığı 1: zaman alıcı bir görevi (görev 1) seri kuyruğa gönder
  • İş Parçacığı 2: Görev 1'i yürütmeye başlayın
  • İş parçacığı 1: başka bir görevi (görev 2) seri kuyruğa gönder
  • Konu 2: görev 1 bitti. 2. görevi yürütmeye başla
  • Konu 2: Görev 2 bitti.

ve her zaman görüyorsun 12


7
2134 ve 1243'ü de basabilir
Matteo Gobbi

Sorum şu ki, bunu neden normal şekilde yapmadık? printf("1");printf("2") ;printf("3") ;printf("4")- ile karşılaştırıldığındadispatch_sync
androniennn

İkinci örnek için @androniennn? çünkü başka bir iş parçacığı dispatch_sync(_serialQueue, ^{ /*change shared data*/ });aynı anda çalışabilir .
Bryan Chen

1
@ asma22 Birden çok iş parçacığı / gönderme kuyruğu arasında iş parçacığı olmayan güvenli bir nesneyi paylaşmak çok kullanışlıdır. Nesneye yalnızca bir seri kuyrukta erişirseniz, ona güvenli bir şekilde eriştiğinizi bilirsiniz.
Bryan Chen

1
Seri infaz demek istiyorum . Bakış açısına göre, tüm görevler aynı kuyruktaki diğer görevlere göre seri olarak yürütülür. Bunun nedeni, diğer kuyruklarla eşzamanlı olarak hala olabilir. Görevlerin eşzamanlı olarak gönderilip yürütülebilmesi GCD'nin tüm noktasıdır.
Bryan Chen

19

Arasındaki fark dispatch_syncve dispatch_asyncbasittir.

Her iki örneğinizde de, ondan önce gönderildiği için TASK 1her zaman daha önce yürütülür TASK 2.

In dispatch_syncÖrneğin Ancak, sevk olmaz TASK 2sonrasına kadar TASK 1sevk edildi ve idam . Buna "engelleme" denir . Kodunuz görev yürütülene kadar bekler (veya "engeller").

In dispatch_asyncÖrneğin, kodunuz tamamlanmasını yürütülmesi için beklemeyecek. Her iki blok da kuyruğa gönderilir (ve sıraya alınır) ve kodunuzun geri kalanı bu iş parçacığı üzerinde yürütülmeye devam eder. Sonra gelecekte bir noktada (kuyruğunuza başka ne gönderildiğine bağlı olarak) Task 1çalıştırılacak ve sonra Task 2çalıştırılacaktır.


2
Sanırım yanlış sipariş verdin. ilk örnek, asyncengellemeyen versiyondur
Bryan Chen

Ne demek istediğini düşündüğüm cevabını düzenledim . Eğer durum böyle değilse lütfen değiştirin ve açıklığa kavuşturun.
JRG-Developer

1
Ya dispatch_sync'i çağırır ve ardından aynı kuyrukta dispatch_async'i çağırırsanız? (ve tersi)
0xSina

1
Bir seri kuyrukta, her iki görev de birbiri ardına yürütülmeye devam eder. İlk durumda, arayan kişi ilk bloğun bitmesini bekler ancak ikinci bloğu beklemez. İkinci durumda, arayan kişi ilk bloğun bitmesini beklemiyor, ancak ikinci bloğu bekler. Ancak sıra, blokları sırayla yürüttüğü için, arayan, her ikisinin de bitmesini etkin bir şekilde bekler.
gnasher729

1
Bir blok ayrıca kendi kuyruğunda dispatch_async yapabilir (daha sonra yürütülecek başka bloklar ekleyerek); kendi seri kuyruğunda veya ana kuyrukta dispatch_sync kilitlenebilir. Bu durumda, arayan kişi orijinal bloğun bitmesini bekleyecek, ancak diğer blokları beklemeyecektir. Unutmayın: dispatch_sync bloğu kuyruğun sonuna koyar, kuyruk kodu bu blok bitene kadar çalıştırır ve sonra dispatch_sync döner. dispatch_async sadece bloğu kuyruğun sonuna ekler.
gnasher729

6

Hepsi ana kuyrukla ilgili. 4 permütasyon vardır.

i) Seri kuyruk, eşzamansız gönderme: Burada görevler birbiri ardına yürütülür, ancak ana iş parçacığı (UI üzerindeki etki) geri dönüşü beklemeyecektir

ii) Seri kuyruk, gönderim senkronizasyonu: Burada görevler birbiri ardına yürütülür, ancak ana iş parçacığı (UI üzerindeki etki) gecikme gösterecektir

iii) Eşzamanlı kuyruk, eşzamansız gönderme: Burada görevler paralel olarak yürütülecek ve ana iş parçacığı (UI üzerindeki etki) geri dönüşü beklemeyecek ve sorunsuz olacaktır.

iv) Eşzamanlı sıra, gönderim senkronizasyonu: Burada görevler paralel olarak yürütülecek, ancak ana iş parçacığı (UI üzerindeki etki) gecikme gösterecektir

Eşzamanlı veya seri sıra seçiminiz, sonraki görev için önceki bir görevden bir çıktıya ihtiyacınız olup olmadığına bağlıdır. Önceki göreve bağlıysanız, seri kuyruğu benimseyin, aksi takdirde eşzamanlı kuyruğu alın.

Ve son olarak bu, işimiz bittiğinde ana konuya geri dönmenin bir yoludur:

DispatchQueue.main.async {
     // Do something here
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.