NSOperation vs Grand Central Dispatch

465

Saya belajar tentang pemrograman bersamaan untuk iOS. Sejauh ini saya sudah membaca tentang NSOperation/NSOperationQueue dan GCD. Apa alasan untuk menggunakan NSOperationQueuelebih GCDdan sebaliknya?

Kedengarannya seperti keduanya GCDdan NSOperationQueueabstrak jauh penciptaan eksplisit NSThreadsdari pengguna. Namun hubungan antara kedua pendekatan itu tidak jelas bagi saya sehingga umpan balik untuk dihargai!

Minggu Senin
sumber
10
+1 untuk pertanyaan yang bagus - ingin tahu hasilnya. Sejauh ini, saya baru saja membaca bahwa GCD dapat dengan mudah dikirim melalui core CPU, menjadikannya sebagai "kotoran panas baru".
Hingga
3
Beberapa diskusi terkait dapat ditemukan dalam pertanyaan ini: Mengapa saya harus memilih GCD daripada NSOperation dan blok untuk aplikasi tingkat tinggi?
Brad Larson

Jawaban:

517

GCDadalah API berbasis C tingkat rendah yang memungkinkan penggunaan model konkurensi berbasis tugas yang sangat sederhana. NSOperationdan NSOperationQueuekelas Objective-C yang melakukan hal serupa. NSOperationdiperkenalkan pertama kali, tetapi pada 10.5 dan iOS 2 , NSOperationQueuedan teman-teman diimplementasikan secara internal menggunakan GCD.

Secara umum, Anda harus menggunakan tingkat abstraksi tertinggi yang sesuai dengan kebutuhan Anda. Ini berarti bahwa Anda biasanya harus menggunakan NSOperationQueuealih-alih GCD, kecuali jika Anda perlu melakukan sesuatu yang NSOperationQueuetidak mendukung.

Perhatikan bahwa NSOperationQueueini bukan versi GCD "bodoh"; sebenarnya, ada banyak hal yang dapat Anda lakukan dengan sangat sederhana NSOperationQueueyang membutuhkan banyak pekerjaan dengan murni GCD. (Contoh: antrian terbatas-bandwidth yang hanya menjalankan operasi N pada satu waktu; membangun ketergantungan antar operasi. Keduanya sangat sederhana NSOperation, sangat sulit dengan GCD.) Apple telah melakukan kerja keras memanfaatkan GCD untuk membuat API ramah objek yang sangat bagus NSOperation. Manfaatkan pekerjaan mereka kecuali Anda memiliki alasan untuk tidak melakukannya.

Peringatan : Di sisi lain, jika Anda benar-benar hanya perlu mengirim blok, dan tidak memerlukan fungsi tambahan apa pun yang NSOperationQueuemenyediakan, tidak ada yang salah dengan menggunakan GCD. Pastikan itu adalah alat yang tepat untuk pekerjaan itu.

BJ Homer
sumber
1
NSOperation khusus kelas abstrak.
Roshan
3
@Sandy Sebenarnya sebaliknya, GCD digunakan oleh NSOperation (setidaknya di versi iOS dan OS X yang lebih baru).
garrettmoon
1
@BJ Homer Kita dapat menambahkan tugas dalam antrian pengiriman serial untuk mencapai depeancy. sangat beralasan bagaimana operasi antrian memiliki keuntungan lebih dari itu
Raj Aggrawal
3
@RajAggrawal Ya, itu berhasil ... tapi kemudian Anda terjebak dengan antrian serial. NSOperation dapat melakukan "jalankan operasi ini setelah ketiga lainnya selesai, tetapi bersamaan dengan semua hal lain yang terjadi." Ketergantungan operasi bahkan dapat ada antara operasi pada antrian yang berbeda. Kebanyakan orang tidak akan membutuhkan itu, tetapi jika Anda melakukannya, NSOperation akan menjadi pilihan yang lebih baik.
BJ Homer
369

Sejalan dengan jawaban saya untuk pertanyaan terkait , saya tidak akan setuju dengan BJ dan menyarankan Anda melihat GCD lebih dulu dari NSOperation / NSOperationQueue, kecuali yang terakhir menyediakan sesuatu yang Anda butuhkan, sedangkan GCD tidak.

Sebelum GCD, saya menggunakan banyak NSOperations / NSOperationQueues dalam aplikasi saya untuk mengelola konkurensi. Namun, sejak saya mulai menggunakan GCD secara teratur, saya hampir sepenuhnya mengganti NSOperations dan NSOperationQueues dengan blok dan mengirim antrian. Ini datang dari bagaimana saya menggunakan kedua teknologi dalam praktik, dan dari profil yang saya lakukan pada mereka.

Pertama, ada jumlah overhead nontrivial saat menggunakan NSOperations dan NSOperationQueues. Ini adalah objek Kakao, dan mereka perlu dialokasikan dan dialokasikan. Dalam aplikasi iOS yang saya tulis yang menjadikan adegan 3-D pada 60 FPS, saya menggunakan NSOperations untuk merangkum setiap frame yang diberikan. Ketika saya memprofilkan ini, pembuatan dan penghancuran NSOperations ini merupakan bagian penting dari siklus CPU dalam aplikasi yang sedang berjalan, dan memperlambat segalanya. Saya menggantinya dengan blok sederhana dan antrian serial GCD, dan overhead itu hilang, yang menyebabkan kinerja rendering yang lebih baik. Ini bukan satu-satunya tempat di mana saya perhatikan overhead menggunakan NSOperations, dan saya sudah melihat ini di Mac dan iOS.

Kedua, ada keanggunan untuk kode pengiriman berbasis blok yang sulit untuk dicocokkan ketika menggunakan NSOperations. Sangat nyaman untuk membungkus beberapa baris kode dalam satu blok dan mengirimkannya untuk dilakukan pada antrian serial atau bersamaan, di mana membuat NSOperation khusus atau NSInvocationOperation untuk melakukan ini memerlukan lebih banyak kode pendukung. Saya tahu bahwa Anda dapat menggunakan NSBlockOperation, tetapi Anda mungkin akan mengirim sesuatu ke GCD saat itu. Membungkus kode ini dalam blok sejalan dengan pemrosesan terkait dalam aplikasi Anda mengarah pada pendapat saya untuk organisasi kode yang lebih baik daripada memiliki metode terpisah atau NSOperations khusus yang merangkum tugas-tugas ini.

NSOperations dan NSOperationQueues masih memiliki kegunaan yang sangat baik. GCD tidak memiliki konsep dependensi yang nyata, di mana NSOperationQueues dapat mengatur grafik ketergantungan yang cukup kompleks. Saya menggunakan NSOperationQueues untuk ini dalam beberapa kasus.

Secara keseluruhan, sementara saya biasanya menganjurkan untuk menggunakan abstraksi tingkat tertinggi yang menyelesaikan tugas, ini adalah satu kasus di mana saya berdebat untuk API tingkat rendah GCD. Di antara pengembang iOS dan Mac saya sudah bicara dengan ini, sebagian besar memilih untuk menggunakan GCD lebih dari NSOperations kecuali mereka menargetkan versi OS tanpa dukungan untuk itu (sebelum iOS 4.0 dan Snow Leopard).

Brad Larson
sumber
20
Saya hanya sedikit tidak setuju; Saya menggunakan GCD biasa sedikit. Tapi saya pikir Anda terlalu mendiskon NSBlockOperation dalam jawaban ini. Semua manfaat NSOperationQueue (dependensi, debugability, dll.) Berlaku untuk memblokir operasi juga.
BJ Homer
4
@ BJHomer - Saya pikir penghindaran NSBlockOperation lebih merupakan masalah preferensi pribadi dalam kasus saya, meskipun saya telah menjauh dari NSOperations secara umum setelah melihat biaya overhead dari penggunaannya menyeret beberapa aplikasi. Jika saya akan menggunakan blok, saya cenderung menggunakan all-in pada GCD, dengan pengecualian langka ketika saya membutuhkan dukungan ketergantungan.
Brad Larson
1
+1, terima kasih untuk analisis ini. Apple tampaknya akan mengadvokasi keduanya (seperti sesi WWDC 2012 tentang UI bersamaan), jadi ini sangat dihargai.
orip
1
@VolureDarkAngel - GCD sangat cepat dalam menangani pengiriman seperti itu. Seharusnya itu bukan hambatan Anda dalam situasi seperti yang Anda jelaskan, kecuali jika Anda entah bagaimana mencadangkan tumpukan pembaruan ke dalam antrian karena lambatnya akses I / O atau semacamnya. Itu mungkin tidak terjadi di sini.
Brad Larson
1
@ asma22 - Sudah umum untuk memiliki perhitungan yang dapat dilakukan dalam potongan, tetapi perhitungan akhir dari satu tahap mungkin membutuhkan hasil dari beberapa tahap sebelumnya. Dalam hal ini, Anda dapat membuat operasi nanti bergantung pada operasi sebelumnya, dan penjadwalan akan dikelola sedemikian rupa sehingga semuanya selesai sebelum yang terakhir berjalan.
Brad Larson
101

GCDadalah API berbasis C tingkat rendah.
NSOperationdan NSOperationQueueadalah kelas Objective-C.
NSOperationQueueadalah objektif C wrapper berakhir GCD. Jika Anda menggunakan NSOperation, maka Anda secara implisit menggunakan Grand Central Dispatch.

Keuntungan GCD dibandingkan NSOperation:
i. Implementasi
Untuk GCDimplementasi sangat ringan-
NSOperationQueuekompleks dan berat-berat

Keuntungan NSOperation dibandingkan GCD:

saya. Kontrol Pada Operasi
Anda dapat Jeda, Batalkan, LanjutkanNSOperation

ii. Ketergantungan
Anda dapat mengatur ketergantungan antara dua NSOperations
operasi tidak akan dimulai sampai semua dependensinya kembali benar untuk selesai.

aku aku aku. Keadaan Operasi
dapat memantau keadaan operasi atau antrian operasi. siap, menjalankan atau selesai

iv. Jumlah Operasi Maks.
Anda dapat menentukan jumlah operasi antrian maksimum yang dapat berjalan secara bersamaan

Kapan Pergi GCDatauNSOperation
ketika Anda ingin lebih mengontrol antrian (semua yang disebutkan di atas) digunakan NSOperation dan untuk kasus-kasus sederhana di mana Anda ingin lebih sedikit overhead (Anda hanya ingin melakukan beberapa pekerjaan "ke latar belakang" dengan sedikit pekerjaan tambahan) gunakanGCD

ref:
https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/ http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html http : //nshipster.com/nsoperation/

Sangram Shivankar
sumber
Seperti yang dikatakan, Max jumlah Operasi dapat ditentukan dalam NSOperationQueue, Lalu apa yang bisa menjadi jumlah maksimum operasi (pengiriman antrian) di GCD? Misalkan saya punya proyek, lalu berapa banyak operasi (pengiriman antrian) yang bisa saya lakukan. atau batas maksimum apa pun yang dapat kami lakukan.
Roshan Sah
Itu tergantung pada kondisi sistem di sini adalah info terperinci: stackoverflow.com/questions/14995801/…
Sangram Shivankar
Kami dapat membatalkan tugas di GCD juga menggunakan DispatchWorkItem dan kami dapat menangguhkan dan melanjutkan juga
Ankit garg
@Ankitgarg Membatalkan panggilan pada DispatchWorkItem akan menghentikan tugas dari mengeksekusi jika mereka belum dijalankan, tetapi tidak akan menghentikan sesuatu yang sudah dieksekusi. dan bagaimana Anda menjeda / melanjutkan DispatchWorkItem ??
abhimuralidharan
34

Alasan lain untuk lebih memilih NSOperation daripada GCD adalah mekanisme pembatalan NSOperation. Misalnya, Aplikasi seperti 500px yang menampilkan puluhan foto, gunakan NSOperation, kami dapat membatalkan permintaan sel gambar yang tidak terlihat saat kami menggulir tampilan tabel atau tampilan koleksi, ini dapat sangat meningkatkan kinerja App dan mengurangi jejak memori. GCD tidak dapat dengan mudah mendukung ini.

Juga dengan NSOperation, KVO dapat dimungkinkan.

Ini adalah artikel dari Eschaton yang layak dibaca.

evanchin
sumber
4
Perlu dicatat bahwa jika apa yang Anda batalkan adalah operasi jaringan memuat gambar, maka Anda tidak perlu melakukannya NSOperation, karena NSURLSessionTask.canceldan NSURLSession.invalidateAndCancelmenyediakan fungsi ini. Secara umum, NSURLSessionmenyediakan beberapa fungsi dari sebuah NSOperationQueue, seperti NSURLSessionTaskmenyediakan beberapa fungsi dari sebuahNSOperation
algal
@algal Sebagaimana dijelaskan di sini ( stackoverflow.com/questions/21918722/... ), tampaknya NSURLSession menggunakan NSOperationQueue sebagai blok penyusun.
kalan nawarathne
33

GCD memang lebih rendah levelnya daripada NSOperationQueue, keuntungan utamanya adalah implementasinya sangat ringan dan fokus pada algoritma dan kinerja bebas kunci.

NSOperationQueue memang menyediakan fasilitas yang tidak tersedia dalam GCD, tetapi mereka datang dengan biaya non-sepele, implementasi NSOperationQueue kompleks dan berat, melibatkan banyak penguncian, dan menggunakan GCD secara internal hanya dengan cara yang sangat minimal.

Jika Anda memerlukan fasilitas yang disediakan oleh NSOperationQueue dengan segala cara menggunakannya, tetapi jika GCD cukup untuk kebutuhan Anda, saya akan merekomendasikan menggunakannya secara langsung untuk kinerja yang lebih baik, secara signifikan lebih rendah CPU dan biaya daya dan fleksibilitas lebih banyak.

das
sumber
24

NSQueueOperations dan GCD memungkinkan menjalankan tugas komputasi berat di latar belakang pada utas terpisah dengan membebaskan Tapak Utama Aplikasi UI.

Nah, berdasarkan posting sebelumnya kita melihat NSOperations memiliki addDependency sehingga Anda dapat mengantri operasi Anda satu demi satu secara berurutan.

Tapi saya juga membaca tentang Antrian serial GCD yang dapat Anda buat jalankan operasi Anda dalam antrian menggunakan dispatch_queue_create. Ini akan memungkinkan menjalankan serangkaian operasi satu demi satu secara berurutan.

Keuntungan NSQueueOperation dibandingkan GCD:

  1. Hal ini memungkinkan untuk menambah ketergantungan dan memungkinkan Anda untuk menghapus ketergantungan sehingga untuk satu transaksi Anda dapat menjalankan urutan menggunakan ketergantungan dan untuk transaksi lainnya berjalan bersamaan sementara GCD tidak mengizinkan untuk menjalankan cara ini.

  2. Sangat mudah untuk membatalkan operasi jika dalam antrian itu dapat dihentikan jika sedang berjalan.

  3. Anda dapat menentukan jumlah maksimum operasi bersamaan.

  4. Anda dapat menangguhkan operasi yang ada di Antrian

  5. Anda dapat menemukan berapa banyak operasi yang tertunda ada dalam antrian.

Shashi3456643
sumber
6

GCD sangat mudah digunakan - jika Anda ingin melakukan sesuatu di latar belakang, yang perlu Anda lakukan hanyalah menulis kode dan mengirimkannya pada antrian latar belakang. Melakukan hal yang sama dengan NSOperation adalah banyak pekerjaan tambahan.

Keuntungan NSOperation adalah (a) Anda memiliki objek nyata yang dapat Anda kirimi pesan, dan (b) Anda dapat membatalkan NSOperation. Itu tidak sepele. Anda perlu subkelas NSOperation, Anda harus menulis kode dengan benar sehingga pembatalan dan menyelesaikan tugas keduanya berfungsi dengan benar. Jadi untuk hal-hal sederhana Anda menggunakan GCD, dan untuk hal-hal yang lebih rumit, Anda membuat subkelas NSOperation. (Ada subkelas NSInvocationOperation dan NSBlockOperation, tetapi semua yang mereka lakukan lebih mudah dilakukan dengan GCD, jadi tidak ada alasan yang baik untuk menggunakannya).

gnasher729
sumber
3

Nah, NSOperations hanyalah sebuah API yang dibangun di atas Grand Central Dispatch. Jadi ketika Anda menggunakan NSOperations, Anda benar-benar masih menggunakan Grand Central Dispatch. Hanya saja NSOperations memberi Anda beberapa fitur mewah yang mungkin Anda sukai. Anda dapat membuat beberapa operasi bergantung pada operasi lain, menyusun ulang antrian setelah Anda membuang item, dan hal-hal lain seperti itu. Bahkan, ImageGrabber sudah menggunakan operasi NSO dan antrian! ASIHTTPRequest menggunakannya di bawah tenda, dan Anda dapat mengonfigurasi antrian operasi yang digunakan untuk perilaku berbeda jika Anda mau. Jadi yang mana yang harus Anda gunakan? Apapun yang masuk akal untuk aplikasi Anda. Untuk aplikasi ini cukup sederhana sehingga kami hanya menggunakan Grand Central Dispatch secara langsung, tidak perlu fitur-fitur mewah NSOperation. Tetapi jika Anda membutuhkannya untuk aplikasi Anda, jangan ragu untuk menggunakannya!

Ankul Gaur
sumber