DispatchQueue.main.async ve DispatchQueue.main.sync arasındaki fark


109

DispatchQueue.main.asyncUI ile ilgili işlemleri gerçekleştirmek için uzun süredir kullanıyorum .



Swift hem DispatchQueue.main.asyncve hem de sağlar DispatchQueue.main.syncve her ikisi de ana kuyrukta gerçekleştirilir.



Biri bana aralarındaki farkı söyleyebilir mi? Her birini ne zaman kullanmalıyım?



DispatchQueue.main.async {
    self.imageView.image = imageView
    self.lbltitle.text = ""

}

DispatchQueue.main.sync {
    self.imageView.image = imageView
    self.lbltitle.text = ""
}

Yanıtlar:


56

Kullandığınızda async, gönderilen bloğun yürütülmesini beklemeden çağrı kuyruğunun devam etmesini sağlar. Aksine sync, arama kuyruğunu durduracak ve blokta gönderdiğiniz iş bitene kadar bekleyecektir. Bu nedenle sync, kilitlenmelere yol açabilir. DispatchQueue.main.syncAna kuyruktan çalıştırmayı deneyin ve uygulama donacaktır çünkü arama kuyruğu gönderilen blok bitene kadar bekleyecek ancak başlayamayacaktır (çünkü kuyruk durdurulmuş ve beklemelidir)

Ne zaman kullanılmalı sync? FARKLI bir kuyrukta yapılan bir şeyi beklemeniz ve ancak o zaman mevcut kuyruğunuz üzerinde çalışmaya devam etmeniz gerektiğinde

Eşitlemeyi kullanma örneği:

Bir seri kuyrukta sync, aynı anda yalnızca bir iş parçacığının korumalı kod parçasını gerçekleştirebildiğinden emin olmak için bir muteks olarak kullanabilirsiniz .


DispatchQueue.main.syncArka plan iş parçacığından aramak yanlış olur mu?
Honey

@Honey Genel olarak hayır, böyle bir aramada yanlış bir şey yok (ana kuyruk ağır ve zaman alıcı bir şey yapmadığı sürece), ancak pratikte buna gerçekten ihtiyacın olan bir durum düşünemiyorum. Kesinlikle daha iyi bir çözüm olmalı
Andrey Chernukha

1
: Burada belgelerinde gösterildiği gibi @Honey böyle bir durum, PhotoKit API PHAssets bir CollectionView'ın güncelliyor developer.apple.com/documentation/photokit/...
çay fincanı

1
@teacup ilginç. Merak ediyorum da orayı ararsak nasıl bir değişiklik olur async? Demek istediğim, daha sonra iplikte başka bir şey kalmadığı için o zaman bir fark yaratmaz. Eğer öyle olsaydı DispatchQueue.main.sync {block1}; DispatchQueue.main.sync {block2};o zaman mantıklı olurdu. Başka bir blok olduğunda Ama sonra kullanmanın yararı düşünemiyorum DispatchQueue.main.sync {Oneblock}üzerinde DispatchQueue.main.async {Oneblock}. Her ikisi için de mainQueue önceliğini / yakınlığını alacaklar ve hiçbir şey onları engellemeyecek.
Honey

3
@Honey "daha sonra ileti dizisinde başka hiçbir şey kalmadığından", uygulamayla tüm kullanıcı etkileşimlerinden sorumlu olan ana ileti dizisindeyken doğru değildir. Bu nedenle, örneğin, bir kullanıcı, önemli bir tutarsızlık hatasına neden olan güncellenmiş bir veri kaynağıyla photoLibraryDidChange dönmeden önce başka bir fotoğrafı silebilir.
çay fincanı

166

Neden Eş Zamanlılık?

Uygulamanıza veri yükleme gibi ağır görevler eklediğiniz anda, kullanıcı arayüzünüzü yavaşlatır ve hatta dondurur. Eşzamanlılık, 2 veya daha fazla görevi "aynı anda" gerçekleştirmenize olanak tanır. Bu yaklaşımın dezavantajı, kontrol edilmesi her zaman kolay olmayan iplik güvenliğidir. Farklı görevler, aynı değişkeni farklı bir iş parçacığında değiştirmeye çalışmak veya farklı iş parçacıkları tarafından zaten engellenen kaynaklara erişmek gibi aynı kaynaklara erişmek istediğinde.

Farkında olmamız gereken birkaç soyutlama var.

  • Kuyruklar.
  • Eşzamanlı / Eşzamansız görev performansı.
  • Öncelikler.
  • Yaygın sorunlar.

Kuyruklar

Olmalı seri veya eşzamanlı . Yanı sıra küresel veya özel aynı anda.

Seri kuyruklarda görevler tek tek, eşzamanlı kuyruklarla bitirilecek, görevler eşzamanlı olarak gerçekleştirilecek ve beklenmedik programlarda bitirilecektir. Aynı görev grubu, eşzamanlı bir kuyruğa kıyasla bir seri kuyrukta daha fazla zaman alacaktır.

Kendi oluşturabilirsiniz özel sıraları (hem seri veya eşzamanlı ) ya da zaten mevcut kullanmak küresel (sistem) sıraları . Ana kuyruk sadece seri kuyruk tüm dışarı küresel kuyruklar .

Ana kuyrukta UI çalışmasına atıfta bulunulmayan ağır görevlerin yerine getirilmemesi (ağdan veri yükleme), bunun yerine UI'nin donmamış ve kullanıcı eylemlerine yanıt vermesini sağlamak için diğer kuyruklarda yapılması şiddetle tavsiye edilir . UI'nin diğer kuyruklarda değiştirilmesine izin verirsek, değişiklikler farklı ve beklenmedik bir program ve hızda yapılabilir. Bazı UI öğeleri, ihtiyaç duyulduktan önce veya sonra çizilebilir. Kullanıcı arayüzünü çökertebilir. Ayrıca beri akılda tutmak gerekir küresel kuyruklar vardır sistem kuyruklar üzerlerinde sistem tarafından çalıştırılabilir diğer bazı görevler vardır.

Hizmet Kalitesi / Öncelik

Kuyruklar ayrıca görev gerçekleştirme önceliğini (burada en yüksekten en düşüğe ) ayarlayan farklı qos'a (Hizmet Kalitesi) sahiptir : .userInteractive - ana kuyruk .userInitiated - kullanıcının bir miktar yanıt beklediği kullanıcı tarafından başlatılan görevler için. Kullanışlılık - görevler için biraz zaman alan ve anında yanıt gerektirmeyen, örneğin , görsel kısımla ilgili olmayan ve tamamlanma süresi için katı olmayan görevler için data .background ile çalışma ). Ayrıca qos bilgilerini aktarmayan .default kuyruğu da vardır . O saptamak mümkün değilse QoS







qos , .userInitiated ve .utility arasında kullanılacaktır .

Görevler eşzamanlı veya eşzamansız olarak gerçekleştirilebilir .

  • Eşzamanlı işlev, yalnızca görev tamamlandıktan sonra denetimi geçerli kuyruğa döndürür. Sırayı bloke eder ve görev bitene kadar bekler.

  • Eşzamansız işlev, farklı kuyrukta gerçekleştirilmek üzere görev gönderildikten hemen sonra mevcut kuyruğa denetim döndürür. Görev bitene kadar beklemez. Sırayı engellemez.

Yaygın Sorunlar.

Programcıların eşzamanlı uygulamaları yansıtırken yaptıkları en popüler hatalar şunlardır:

  • Yarış koşulu - uygulamanın çalışması kod parçalarının yürütülme sırasına bağlı olduğunda ortaya çıkar.
  • Öncelikli ters çevirme - daha yüksek öncelikli görevler, bazı kaynakların engellendiği için daha küçük öncelikli görevlerin tamamlanmasını beklediğinde
  • Kilitlenme - birkaç kuyrukta bu kuyruklardan bazıları tarafından zaten engellenen kaynaklar (değişkenler, veriler vb.) İçin sonsuz bekleme olduğunda.

Ana kuyruktaki senkronizasyon işlevini ASLA çağırmayın .
Ana kuyrukta senkronizasyon işlevini çağırırsanız, kuyruğu bloke eder ve ayrıca kuyruk, görevin tamamlanmasını bekler ancak kuyruk nedeniyle başlatılamayacağı için görev asla bitirilmez. zaten engellendi. Kilitlenme denir .

Senkronizasyon ne zaman kullanılır? Görev bitene kadar beklememiz gerektiğinde. Fe, bazı işlevlerin / yöntemin çift çağrılmadığından emin olduğumuzda. Fe senkronizasyonumuz var ve tamamen bitene kadar çift çağrılmasını engellemeye çalışıyoruz. İşte bu endişe için bazı kodlar:
IOS cihazında hata çökme raporuna neyin neden olduğunu nasıl öğrenebilirim?


3
"ASLA ana kuyruktaki senkronizasyon işlevini çağırmanın" doğru olduğunu düşünmüyorum. Ana iş parçacığında senkronizasyonu çağıracağınız durumlar vardır, örneğin her nesnenin kullanması ve artırması gereken genel bir sayacınız olduğunda: dispatchQueue.sync {count + = 1; self.orderId = count}
Elisha Sterngold

6
QOS Sınıfı - .userInteractive ana kuyruk DEĞİLDİR.
Kunal Shah

1
DispatchQueue.main.syncArka plan iş parçacığından aramak yanlış olur mu?
Honey

1
@Honey, hayır, bunu aramak yanlış değil ama tecrübelerime göre, kendinizi senkronizasyon dışında daha çok DispatchQueue.main.async aradığınızı göreceksiniz.
James Kim

2
Mevcut kuyrukta asla sync () işlevini çağırmamanız gerektiğini söylemek daha doğru olmaz mı? Doğru anladıysam, başka bir kuyruktaysanız ana kuyrukta sync () çağırmak yanlış değildir.
ykay

1

GCDbir görevi yürütmenize synchronouslyveya asynchronously[Hakkında]

synchronous(engelle ve bekle) işlevi, görev tamamlanınca bir denetim döndürür

asynchronous(gönder ve devam et) işlevi, görevi uygun bir kuyruğa başlatmak için ancak tamamlanmasını beklemeden hemen göndererek bir denetim döndürür.

[DispatchQueue]


0

syncveya asyncyöntemlerin çağrıldıkları kuyruk üzerinde hiçbir etkisi yoktur.

synciplik engeller gelen o kuyruğu denilen ve almayan üzerine çağrıldığı. Görevin yürütülmesini bekleyip bekleyemeyeceğine (seri sıra) veya mevcut görev tamamlanmadan önce bir sonraki görevi çalıştırıp çalıştırmayacağına (eşzamanlı sıra) DispatchQueuekarar veren özelliktir DispatchQueue.

Bu nedenle DispatchQueue.main.async, bir zaman uyumsuz çağrı olduğunda bile , eklenen bir ağır görev işlemi, işlemleri ana iş parçacığı üzerinde seri olarak yürütüldüğü için kullanıcı arayüzünü dondurabilir. Bu yöntem arka plan iş parçacığından çağrılırsa, kullanıcı arabirimi donmuş gibi görünse bile denetim o iş parçacığına anında dönecektir. Bunun nedeni, asyncaramanın yapıldığıDispatchQueue.main

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.