Dispatch_async'i anlama


233

Bu kod etrafında bir sorum var

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData* data = [NSData dataWithContentsOfURL: 
      kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:) 
      withObject:data waitUntilDone:YES];
});

Bu kodun ilk parametresi

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

Bu koddan, tanımı belirli bir öncelik seviyesinin global eşzamanlı kuyruğunu döndürmesi olan global kuyrukta seri görevler gerçekleştirmesini istiyor muyuz?

dispatch_get_global_queueAna kuyrukta kullanmanın avantajı nedir ?

Kafam karıştı. Lütfen bunu daha iyi anlamama yardım eder misin?


1
Kodunuzu birkaç satırda daha iyi kesmelisiniz, böylece daha mantıklı. dispatch_get_global_queuedeğişken bir tür içinde güvenli dispatch_queue_t myQueue. Daha okunabilir `` dispatch_async '' e sadece myQueue iletiliyor
Alex Cio

Yanıtlar:


517

Ana kuyruğun üzerinde varsayılan kuyruğu kullanmanızın temel nedeni, görevleri arka planda çalıştırmaktır.

Örneğin, internetten bir dosya indiriyorsam ve indirme işlemi sırasında kullanıcıyı güncellemek istersem, indirmeyi öncelikli varsayılan kuyrukta çalıştıracağım ve ana kuyruktaki kullanıcı arayüzünü eşzamansız olarak güncelleyeceğim.

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});

David'in cevabınız için teşekkürler anlıyorum ama sorum bu işi yapma mantığını anlamak için daha etraftaydı yani bu kodu, eşzamanlı kuyruğun kendisi olan küresel kuyrukta seri görevler gerçekleştirmesini
istiyorlar

Ben tam olarak ne önerdiğini yapıyorum ama bir şekilde, Ui Güncellemeleri Çalıştır [self.tableView reloadData] çağırdığınızda uiTableViewCell hemen güncel değil. Yaklaşık 4 veya 5 saniye sürer. Birkaç gün boyunca beni deli ediyor .
GrandSteph

@GrandSteph Bu yönteme çok aşina değilim. Belki bu yöntemin çalışması sadece 5 saniye sürer. Dispatch_async ile önemli olan, ana iş parçacığı asmadan arka planda bir şeyler yapmanıza izin vermesidir.
David

2
ne anlama geliyor 0?
Bal

3
@Honey 0 flagsşu anda kesinlikle hiçbir şey yapmayan parametredir. Dokümanlardan:Flags that are reserved for future use. Always specify 0 for this parameter.
David

199

Tüm DISPATCH_QUEUE_PRIORITY_X kuyrukları eşzamanlı kuyruklardır (yani aynı anda birden fazla görevi yürütebilecekleri anlamına gelir) ve belirli bir kuyruktaki görevlerin "ilk giren ilk çıkar" sırası kullanılarak yürütülmeye başlaması anlamında FIFO'dur. Bu, ana kuyrukla (seri kuyruğu olan dispatch_get_main_queue () kaynağından) karşılaştırılır (görevler yürütülmeye başlanır ve alınma sırasına göre tamamlanır).

Bu nedenle, DISPATCH_QUEUE_PRIORITY_DEFAULT'a 1000 dispatch_async () bloğu gönderirseniz, bu görevler kuyruğa gönderdiğiniz sırayla yürütülmeye başlar. Aynı şekilde YÜKSEK, DÜŞÜK ve ARKA PLAN kuyrukları için. Bu kuyruklardan herhangi birine gönderdiğiniz her şey, ana uygulama iş parçanızdan uzakta alternatif iş parçacıklarında arka planda yürütülür. Bu nedenle, bu kuyruklar arka plan indirme, sıkıştırma, hesaplama vb. Görevleri yürütmek için uygundur.

Yürütme sırasının kuyruk başına temelinde FIFO olduğunu unutmayın. Bu nedenle, dört farklı eşzamanlı kuyruğa 1000 dispatch_async () görevi gönderirseniz, bunları eşit olarak böler ve sırasıyla ARKA PLAN, DÜŞÜK, VARSAYILAN ve YÜKSEK'e gönderirseniz (yani, YÜKSEK kuyruktaki son 250 görevi zamanlarsınız) başlangıçta gördüğünüz ilk görevler, sistem bu görevlerin CPU'ya olabildiğince çabuk ulaşması gerektiği anlamına geldiğinden YÜKSEK kuyrukta olacaktır.

Ayrıca "sırayla yürütmeye başlayacağımı" söylüyorum, ancak eşzamanlı sıralar olarak her görev için sürenin uzunluğuna bağlı olarak bir şeyin zorunlu olarak yürütmeyi bitirmeyeceğini unutmayın.

Apple'a göre:

https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

Paralel olarak çalışabilen birden fazla göreviniz olduğunda, eşzamanlı bir gönderme kuyruğu yararlıdır. Eşzamanlı bir kuyruk, görevleri bir ilk giren ilk çıkar sırasına göre ayıkladığı için hala bir kuyruktur; ancak, eşzamanlı bir kuyruk önceki görevler tamamlanmadan önce ek görevleri aldatabilir. Herhangi bir anda eşzamanlı bir kuyruk tarafından yürütülen gerçek görev sayısı değişkendir ve uygulamanızdaki koşullar değiştikçe dinamik olarak değişebilir. Kullanılabilir çekirdeklerin sayısı, diğer işlemler tarafından yapılan iş miktarı ve diğer seri dağıtım kuyruklarındaki görevlerin sayısı ve önceliği dahil olmak üzere, eşzamanlı kuyruklar tarafından yürütülen görevlerin sayısını etkiler.

Temel olarak, bu 1000 dispatch_async () bloğunu bir VARSAYILAN, YÜKSEK, DÜŞÜK veya ARKA PLAN kuyruğuna gönderirseniz, tümü bunları gönderdiğiniz sırayla yürütmeye başlayacaktır. Ancak, kısa görevler daha uzun görevlerden önce bitebilir. Bunun arkasındaki nedenler, kullanılabilir CPU çekirdeği olup olmadığı veya mevcut kuyruk görevlerinin hesaplamalı olarak yoğun olmayan bir iş yapmasıdır (böylece sistemin, çekirdek sayısına bakılmaksızın ek görevler gönderebileceğini düşünmesini sağlar).

Eşzamanlılık düzeyi tamamen sistem tarafından ele alınır ve sistem yüküne ve dahili olarak belirlenen diğer faktörlere dayanır. Bu, Grand Central Dispatch (dispatch_async () sisteminin) güzelliğidir - sadece çalışma ünitelerinizi kod bloğu olarak yapar, onlar için bir öncelik ayarlarsınız (seçtiğiniz kuyruğa göre) ve sistemin geri kalanını halletmesine izin verirsiniz.

Yukarıdaki sorunuza cevap vermek için: kısmen haklısınız. "Bu kodu, belirtilen öncelik düzeyinde bir genel eşzamanlı kuyrukta eşzamanlı görevler gerçekleştirmesini istiyorsunuz. Bloktaki kod arka planda yürütülür ve diğer (benzer) kodlar, sistemin kullanılabilir kaynakları değerlendirmesine bağlı olarak potansiyel olarak paralel olarak yürütülür.

Öte yandan "ana" kuyruk (dispatch_get_main_queue () 'den) bir seri kuyruktur (eşzamanlı değil). Ana kuyruğa gönderilen görevler her zaman sırayla yürütülür ve her zaman sırayla tamamlanır. Bu görevler UI İş Parçacığında da yürütülür, böylece kullanıcı arayüzünüzü ilerleme mesajları, tamamlama bildirimleri vb. İle güncellemek için uygundur.


+1, ancak pratikte eşzamanlı sıraların FIFO veya sadece rastgele sıra olması önemli değil. Bir döngüde 5 görev başlatırsanız, bunların aynı anda başlayacağını varsayalım. Örneğin, 1. görevin ilk G / Ç işleminin aynı kodu yürütseler bile, 5. görevden önce gerçekleşeceğinin garantisi yoktur. OTOH, seri kuyruklar için FIFO davranışı esastır ve IMHO bu iki kuyruk tipi arasındaki tanımlayıcı farktır.
Gerhard Wesp

İnanılmaz açıklama. Çok çırpıyor!
Okhan Okbay

36

Hızlı sürüm

Bu David'in Objective-C cevabının Swift versiyonudur. Arka planda işleri çalıştırmak için genel kuyruğu ve kullanıcı arayüzünü güncelleştirmek için ana kuyruğu kullanırsınız.

DispatchQueue.global(qos: .background).async {
    
    // Background Thread
    
    DispatchQueue.main.async {
        // Run UI Updates
    }
}
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.