Perbedaan antara DispatchQueue.main.async dan DispatchQueue.main.sync


109

Saya telah menggunakan DispatchQueue.main.asyncwaktu yang lama untuk melakukan operasi terkait UI.



Swift menyediakan DispatchQueue.main.asyncdan DispatchQueue.main.sync, dan keduanya dilakukan di antrean utama.



Adakah yang bisa memberi tahu saya perbedaan di antara mereka? Kapan saya harus menggunakan masing-masing?



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

}

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

Jawaban:


56

Saat Anda menggunakannya async, biarkan antrian panggilan terus berjalan tanpa menunggu sampai blok yang dikirim dijalankan. Sebaliknya syncakan membuat antrian panggilan berhenti dan menunggu sampai pekerjaan yang Anda kirim di blok selesai. Oleh karena syncitu dapat menyebabkan kebuntuan. Coba jalankan DispatchQueue.main.syncdari antrian utama dan aplikasi akan berhenti karena antrian panggilan akan menunggu sampai blok yang dikirim selesai tetapi bahkan tidak dapat dimulai (karena antrian berhenti dan menunggu)

Kapan digunakan sync? Ketika Anda perlu menunggu sesuatu selesai pada antrian yang BERBEDA dan hanya kemudian melanjutkan mengerjakan antrian Anda saat ini

Contoh penggunaan sinkronisasi:

Pada antrian serial, Anda dapat menggunakan syncsebagai mutex untuk memastikan bahwa hanya satu utas yang dapat melakukan bagian kode yang dilindungi pada saat yang bersamaan.


Apakah salah menelepon DispatchQueue.main.syncdari utas latar belakang?
Madu

@Honey Secara umum tidak, tidak ada yang salah dengan panggilan seperti itu (selama antrian utama tidak melakukan sesuatu yang berat dan memakan waktu), tetapi dalam praktiknya saya tidak dapat memikirkan situasi di mana Anda benar-benar membutuhkan ini. Pasti ada solusi yang lebih baik
Andrey Chernukha

1
@Honey Salah satu situasi tersebut adalah memperbarui CollectionView PHAsset dari API PhotoKit, seperti yang ditunjukkan dalam dokumentasi di sini: developer.apple.com/documentation/photokit/…
teacup

1
@teacup menarik. Aku hanya ingin tahu apa bedanya jika kita menelepon ke asyncsana? Maksud saya karena tidak ada yang lain di utas setelah itu maka tidak ada bedanya. Jika demikian DispatchQueue.main.sync {block1}; DispatchQueue.main.sync {block2};maka itu akan masuk akal. Tetapi ketika tidak ada blok lain maka saya tidak dapat memikirkan manfaat menggunakan DispatchQueue.main.sync {Oneblock}lebih DispatchQueue.main.async {Oneblock}. Untuk keduanya, mereka akan mendapatkan prioritas / kesegeraan mainQueue dan tidak ada yang akan mengganggu mereka.
Madu

3
@Honey "karena tidak ada lagi yang lain di utas setelahnya" tidak benar saat Anda berada di utas utama, yang bertanggung jawab untuk menangani semua interaksi pengguna dengan aplikasi. Jadi, misalnya, pengguna mungkin menghapus foto lain sebelum photoLibraryDidChange ditampilkan dengan sumber data yang diperbarui yang menyebabkan kesalahan inkonsistensi yang fatal.
cangkir teh

166

Mengapa Concurrency?

Segera setelah Anda menambahkan tugas-tugas berat ke aplikasi Anda seperti pemuatan data, itu memperlambat kerja UI Anda atau bahkan membekukannya. Concurrency memungkinkan Anda melakukan 2 tugas atau lebih "secara bersamaan". Kerugian dari pendekatan ini adalah keamanan benang yang tidak selalu mudah dikendalikan. Fe ketika tugas yang berbeda ingin mengakses sumber daya yang sama seperti mencoba mengubah variabel yang sama pada utas yang berbeda atau mengakses sumber daya yang sudah diblokir oleh utas yang berbeda.

Ada beberapa abstraksi yang perlu kita waspadai.

  • Antrian.
  • Performa tugas Sinkron / Asinkron.
  • Prioritas.
  • Masalah umum.

Antrian

Harus serial atau bersamaan . Serta global atau pribadi pada saat bersamaan.

Dengan antrian serial, tugas akan diselesaikan satu per satu sementara dengan antrian bersamaan, tugas akan dilakukan secara bersamaan dan akan diselesaikan pada jadwal yang tidak terduga. Kelompok tugas yang sama akan menghabiskan lebih banyak waktu pada antrian serial dibandingkan dengan antrian bersamaan.

Anda dapat membuat antrean pribadi Anda sendiri (baik serial atau bersamaan ) atau menggunakan antrean global (sistem) yang sudah tersedia . The antrian utama adalah satu-satunya antrian seri dari semua antrian global yang .

Sangat disarankan untuk tidak melakukan tugas berat yang tidak dirujuk ke pekerjaan UI pada antrean utama (fe memuat data dari jaringan), tetapi melakukannya di antrean lain untuk menjaga UI tidak membeku dan responsif terhadap tindakan pengguna. Jika kami membiarkan UI diubah pada antrian lain, perubahan dapat dilakukan pada jadwal dan kecepatan yang berbeda dan tidak terduga. Beberapa elemen UI dapat digambar sebelum atau setelah dibutuhkan. Itu bisa merusak UI. Kita juga perlu mengingat bahwa karena antrian global adalah antrian sistem, ada beberapa tugas lain yang dapat dijalankan oleh sistem di dalamnya.

Kualitas Layanan / Prioritas

Antrian juga memiliki qos berbeda (Kualitas Layanan) yang menetapkan prioritas pelaksanaan tugas (dari yang tertinggi ke terendah di sini):
.userInteractive - antrian utama
.userInitiated - untuk tugas yang dimulai pengguna di mana pengguna menunggu beberapa respons
.utility - untuk tugas yang membutuhkan waktu dan tidak memerlukan respons segera, misalnya bekerja dengan data
.background - untuk tugas-tugas yang tidak terkait dengan bagian visual dan yang tidak ketat untuk waktu penyelesaian).

Ada juga antrian

default yang tidak mentransfer informasi qos . Jika tidak mungkin mendeteksi qos theqos akan digunakan antara .userInitiated dan .utility .

Tugas dapat dilakukan secara sinkron atau asinkron .

  • Fungsi sinkron mengembalikan kontrol ke antrian saat ini hanya setelah tugas selesai. Ini memblokir antrian dan menunggu sampai tugas selesai.

  • Fungsi asynchronous mengembalikan kontrol ke antrian saat ini tepat setelah tugas dikirim untuk dilakukan pada antrian yang berbeda. Itu tidak menunggu sampai tugas selesai. Itu tidak memblokir antrian.

Masalah Umum.

Kesalahan paling populer yang dibuat programmer saat memproyeksikan aplikasi bersamaan adalah sebagai berikut:

  • Kondisi balapan - disebabkan saat aplikasi bekerja tergantung pada urutan eksekusi bagian kode.
  • Inversi prioritas - saat tugas dengan prioritas lebih tinggi menunggu tugas dengan prioritas yang lebih kecil diselesaikan karena beberapa sumber daya diblokir
  • Kebuntuan - ketika beberapa antrian menunggu tanpa batas untuk sumber (variabel, data, dll.) Sudah diblokir oleh beberapa antrian ini.

JANGAN PERNAH memanggil fungsi sinkronisasi pada antrian utama .
Jika Anda memanggil fungsi sinkronisasi pada antrian utama, itu akan memblokir antrian serta antrian akan menunggu tugas diselesaikan tetapi tugas tidak akan pernah selesai karena itu bahkan tidak akan bisa dimulai karena antriannya sudah diblokir. Ini disebut deadlock .

Kapan menggunakan sinkronisasi? Kapan kita perlu menunggu sampai tugas selesai. Fe ketika kita memastikan bahwa beberapa fungsi / metode tidak dipanggil ganda. Fe kita memiliki sinkronisasi dan berusaha mencegahnya menjadi panggilan ganda sampai benar-benar selesai. Berikut beberapa kode untuk masalah ini:
Bagaimana cara mengetahui penyebab error crash report pada perangkat IOS?


3
Saya tidak berpikir bahwa "JANGAN PERNAH memanggil fungsi sinkronisasi di antrean utama" adalah benar. Ada beberapa kasus ketika Anda memanggil sinkronisasi di utas utama misalnya ketika Anda memiliki penghitung global yang Anda perlukan setiap objek untuk digunakan dan meningkatkan: dispatchQueue.sync {count + = 1; self.orderId = count}
Elisa Sterngold

6
Kelas QOS - .userInteractive BUKAN antrian utama.
Kunal Shah

1
Apakah salah menelepon DispatchQueue.main.syncdari utas latar belakang?
Madu

1
@Honey, tidak itu tidak salah untuk menyebutnya tetapi dari pengalaman saya, Anda akan menemukan diri Anda lebih memanggil DispatchQueue.main.async selain sinkronisasi.
James Kim

2
Bukankah lebih akurat untuk mengatakan bahwa Anda tidak boleh memanggil fungsi sync () pada antrian saat ini? Tidak salah memanggil sync () pada antrian utama jika Anda berada dalam antrian lain, jika saya mengerti dengan benar.
ykay

1

GCDmemungkinkan Anda untuk menjalankan tugas synchronouslyatau asynchronously[Tentang]

synchronousFungsi (blok dan tunggu) mengembalikan kontrol saat tugas akan diselesaikan

asynchronous(dispatch dan lanjutkan) fungsi mengembalikan kontrol segera, mengirimkan tugas untuk memulai antrian yang sesuai tetapi tidak menunggu sampai selesai.

[DispatchQueue]


0

syncatau asyncmetode tidak berpengaruh pada antrian di mana mereka dipanggil.

syncakan memblokir benang dari yang disebut dan tidak antrian di mana ia disebut. Ini adalah properti DispatchQueueyang memutuskan apakah DispatchQueueakan menunggu eksekusi tugas (antrian serial) atau dapat menjalankan tugas berikutnya sebelum tugas saat ini selesai (antrian bersamaan).

Jadi, meskipun DispatchQueue.main.asyncpanggilan asinkron, operasi tugas berat yang ditambahkan di dalamnya dapat membekukan UI karena operasinya dijalankan secara serial pada thread utama. Jika metode ini dipanggil dari thread latar belakang, kontrol akan kembali ke thread tersebut secara instan bahkan saat UI tampak terhenti. Ini karena asyncpanggilan dilakukanDispatchQueue.main

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.