iPhone - Grand Central Dispatch ana ileti dizisi


145

Uygulamalarımda başarılı bir şekilde büyük merkezi gönderim kullanıyorum, ancak bunun gibi bir şeyi kullanmanın gerçek avantajının ne olduğunu merak ediyordum:

dispatch_async(dispatch_get_main_queue(), ^{ ... do stuff

ya da

dispatch_sync(dispatch_get_main_queue(), ^{ ... do stuff

Demek istediğim, her iki durumda da, ana iş parçacığı üzerinde yürütülecek bir bloğu ateşliyorsunuz, tam olarak uygulamanın çalıştığı yerde ve bu, yükü azaltmaya yardımcı olmayacak. İlk durumda, bloğun ne zaman çalışacağı konusunda herhangi bir kontrole sahip değilsiniz. Onları ateşledikten yarım saniye sonra blokların infaz edildiğini gördüm. İkinci durum, şuna benzer

[self doStuff];

sağ?

Ne düşünüyorsunuz merak ediyorum.


9
Bu arada, dispatch_sync'e bir ana kuyruk atmak bir kilitlenmeyle sonuçlanacaktır.
Brooks Hanes

5
Dokümanlarda okuyun: "dispatch_async'in aksine, [dispatch_sync] blok bitene kadar dönmez. Bu işlevi çağırmak ve mevcut kuyruğu hedeflemek kilitlenmeye neden olur." ... Ama belki de bunu yanlış okuyorum ... ( mevcut kuyruk ana iş parçacığı anlamına gelmez). Lütfen yanılıyorsam düzeltin.
Brooks Hanes

4
@BrooksHanes her zaman doğru değildir. Zaten ana iş parçacığı üzerindeyseniz kilitlenmeye neden olur . Aksi takdirde bir kilitlenme olmazdı. Buraya
Honey

Yanıtlar:


296

Ana kuyruğa bir bloğun gönderilmesi, genellikle arka planda işlemenin tamamlandığını işaret etmek için bir arka plan kuyruğundan yapılır, örn.

- (void)doCalculation
{
    //you can use any string instead "com.mycompany.myqueue"
    dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);

    dispatch_async(backgroundQueue, ^{
        int result = <some really long calculation that takes seconds to complete>;

        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateMyUIWithResult:result];
        });    
    });
}

Bu durumda, bir arka plan kuyruğunda uzun bir hesaplama yapıyoruz ve hesaplama tamamlandığında kullanıcı arayüzümüzü güncellememiz gerekiyor. Kullanıcı arayüzünün güncellenmesi normalde ana kuyruktan yapılmalıdır, bu nedenle ikinci bir iç içe geçmiş dispatch_async kullanarak ana kuyruğa geri 'sinyal' veririz.

Ana kuyruğa geri göndermek isteyebileceğiniz başka örnekler de vardır, ancak bu genellikle bu şekilde yapılır, yani bir arka plan kuyruğuna gönderilen bir bloğun içinden yuvalanmıştır.

  • arka planda işlem bitti -> kullanıcı arayüzünü güncelle
  • arka planda işlenen veri yığını -> sonraki parçayı başlatmak için ana kuyruğa sinyal gönderir
  • Arka plan kuyruğunda gelen ağ verileri -> mesajın geldiğini ana kuyruğa bildirir
  • vs vs

Eğer ana kuyruğuna sevk isteyebilirsiniz neden olarak gelen ana sıranın ... Eh, genellikle makul çalıştırma döngü etrafında bir dahaki sefere yapacak işlerimiz planlamak için bunu yapabilir olmaz rağmen.


Ah, anlıyorum. Yani haklıyım. Zaten ana kuyruktaysanız, yalnızca başka bir kuyruktaysanız ve kullanıcı arayüzünü güncellemek istiyorsanız, bunu yapmanın hiçbir avantajı yoktur. Teşekkürler.
Duck

Bunu ana kuyruktan yapmanın neden çok yararlı olmadığı hakkında konuşmak için cevabımı düzenledim.
Robin Summerhill

Ayrıca, ana iş parçacığından ana sıraya dispatch_sync'in yalnızca bir takılmaya neden olduğu iOS 4'te (iOS 5'te gitmiş olabilir) bir hata olduğunu düşünüyorum, bu yüzden bunu tamamen yapmaktan kaçınırdım.
joerick

10
Bu bir hata değil, beklenen davranış bu. Kuşkusuz pek kullanışlı bir davranış değil, ancak dispatch_sync'i kullanırken her zaman kilitlenmelerden haberdar olmanız gerekir. Sistemin sizi her zaman programcı hatasından korumasını bekleyemezsiniz.
Robin Summerhill

2
Burada backgroundQueue nedir? BackgroundQueue nesnesini nasıl oluşturabilirim
Nilesh Tupe

16

Ana iş parçacığından ana kuyruğa blokların gönderilmesi yararlı olabilir . Ana kuyruğa sıraya alınmış diğer blokları işleme şansı verir, böylece diğer her şeyin yürütülmesini engellemiyorsunuz.

Örneğin, aslında birçok eşzamanlı bağlantıyı idare eden, esasen tek iş parçacıklı bir sunucu yazabilirsiniz. Kuyruktaki hiçbir blok çok uzun sürmediği sürece, sunucu yeni isteklere yanıt vermeyi sürdürür.

Programınız tüm yaşamını olaylara yanıt vererek geçirmekten başka bir şey yapmıyorsa, bu oldukça doğal olabilir. Sadece olay işleyicilerinizi ana kuyrukta çalışacak şekilde ayarlayın ve ardından dispatch_main () öğesini çağırın ve iş parçacığı güvenliği konusunda endişelenmenize gerek kalmayabilir.


11

Dispatch_async ve dispatch_sync arasındaki farkları merak ettiğiniz için, umarım sorunuzu doğru anlıyorum.

dispatch_async

bloğu eşzamansız olarak bir kuyruğa gönderir. Yani bloğu kuyruğa gönderecek ve yönteminizdeki kalan kodun yürütülmesine devam etmeden önce geri dönmesini beklemeyecektir.

dispatch_sync

bloğu eşzamanlı olarak bir kuyruğa gönderir. Bu, blok yürütmeyi bitirene kadar yöntemde kalan kodun daha fazla yürütülmesini önleyecektir.

dispatch_asyncAna kuyruktan çıkmak ve cihazın sahip olabileceği ekstra çekirdeklerden yararlanmak için çoğunlukla bir arka plan kuyruğuna kullandım. Daha sonra dispatch_asynckullanıcı arayüzünü güncellemem gerekirse ana iş parçacığına.

İyi şanslar


1
teşekkürler, ama ana sıraya bir şey göndermenin, ana sırada olmanın avantajlarını soruyorum.
Duck

9

Kullanışlı olduğu yerlerden biri, uzun bir işlemden önce bir değer değiştirici ayarlamak gibi UI etkinlikleri içindir:

- (void) handleDoSomethingButton{

    [mySpinner startAnimating];

    (do something lengthy)
    [mySpinner stopAnimating];
}

çalışmayacaktır, çünkü uzun işiniz sırasında ana iş parçacığını bloke ediyorsunuz ve UIKit'in eğiriciyi gerçekten başlatmasına izin vermiyorsunuz.

- (void) handleDoSomethingButton{
     [mySpinner startAnimating];

     dispatch_async (dispatch_get_main_queue(), ^{
          (do something lengthy)
          [mySpinner stopAnimating];
    });
}

kontrolü çalıştırma döngüsüne geri döndürecektir; bu, UI güncellemesini programlayacak, döndürücüyü başlatacak ve ardından bir sonraki şeyi gönderim kuyruğundan alacak, bu da sizin gerçek işlemenizdir. İşlemeniz tamamlandığında, animasyon durdurma çağrılır ve çalışma döngüsüne dönersiniz, burada UI daha sonra durdurma ile güncellenir.


@Jerceratops evet ama mevcut runloop'un tamamlanmasına izin veriyor.
Dan Rosenstark

3
Evet, ama yine de korkunç. Hala kullanıcı arayüzünü engelliyor. Bundan hemen sonra başka bir düğmeye basabilirim. Veya deneyin ve kaydırın. "(uzun bir şey yap)" ana iş parçacığında olmamalıdır ve düğmenin "bitir" tıklamasına izin vermek için dispatch_async kabul edilebilir bir çözüm değildir.
Jerceratops

8

Hızlı 3, 4 ve 5

Ana iş parçacığı üzerinde kod çalıştırma

DispatchQueue.main.async {
    // Your code here
}

1

Zaman uyumsuz, eşzamansız anlamına gelir ve bunu çoğu zaman kullanmalısınız. Asla ana iş parçacığında senkronizasyonu çağırmamalısınız çünkü görev tamamlanana kadar kullanıcı arayüzünüzü kilitleyecektir. You Here bunu Swift'de yapmanın daha iyi bir yolu:

runThisInMainThread { () -> Void in
    // Run your code like this:
    self.doStuff()
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

Depomda standart bir işlev olarak yer alıyor, kontrol edin: https://github.com/goktugyil/EZSwiftExtensions

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.