Pertanyaan Apa perbedaan antara atribut atom dan nonatomik?


Apa yang atomic dan nonatomic berarti dalam deklarasi properti?

@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;

Apa perbedaan operasional antara ketiganya?


1722
2018-02-26 02:31


asal


Jawaban:


Dua yang terakhir identik; "Atomic" adalah perilaku default (perhatikan bahwa itu sebenarnya bukan kata kunci; itu hanya ditentukan oleh tidak adanya nonatomic - atomic ditambahkan sebagai kata kunci dalam versi terbaru dari llvm / clang).

Dengan asumsi bahwa Anda adalah @ menyintesis implementasi metode, atom vs non-atom mengubah kode yang dihasilkan. Jika Anda menulis sendiri setter / getter Anda, atomik / nonatomik / retain / assign / copy hanyalah sekedar nasihat. (Catatan: @synthesize sekarang adalah perilaku default dalam versi terbaru LLVM. Juga tidak perlu mendeklarasikan variabel instan; mereka juga akan disintesis secara otomatis, dan akan memiliki _ ditambahkan ke nama mereka untuk mencegah akses langsung yang tidak disengaja).

Dengan "atom", penyetel / pengambil yang disintesis akan memastikan bahwa a seluruh nilai selalu dikembalikan dari rajin atau diatur oleh setter, terlepas dari aktivitas penyetel pada utas lainnya. Yaitu, jika thread A berada di tengah pengambil ketika thread B memanggil setter, nilai aktual yang sebenarnya - sebuah objek autoreleased, kemungkinan besar - akan dikembalikan ke pemanggil di A.

Di nonatomic, tidak ada jaminan yang dibuat. Demikian, nonatomic jauh lebih cepat daripada "atom".

Apa yang "atom" lakukan tidak lakukan adalah membuat jaminan apapun tentang keamanan benang. Jika benang A memanggil pengambil secara bersamaan dengan untaian B dan C memanggil pembuat dengan nilai yang berbeda, untaian A dapat memperoleh salah satu dari tiga nilai yang dikembalikan - yang sebelum penyetel apa pun yang dipanggil atau salah satu dari nilai yang diteruskan ke pengatur di B dan C. Demikian juga, objek mungkin berakhir dengan nilai dari B atau C, tidak ada cara untuk memberi tahu.

Memastikan integritas data - salah satu tantangan utama pemrograman multi-berulir - dicapai dengan cara lain.

Menambah ini:

atomicity dari satu properti juga tidak dapat menjamin keamanan benang ketika beberapa sifat tergantung sedang dimainkan.

Mempertimbangkan:

 @property(atomic, copy) NSString *firstName;
 @property(atomic, copy) NSString *lastName;
 @property(readonly, atomic, copy) NSString *fullName;

Dalam hal ini, utas A bisa mengganti nama objek dengan memanggil setFirstName: dan kemudian menelepon setLastName:. Sementara itu, utas B dapat memanggil fullName di antara dua panggilan benang A dan akan menerima nama depan baru yang digabungkan dengan nama belakang lama.

Untuk mengatasi hal ini, Anda memerlukan model transaksional. Yaitu. beberapa jenis sinkronisasi dan / atau pengecualian lain yang memungkinkan seseorang untuk mengecualikan akses ke fullName sementara sifat tergantung sedang diperbarui.


1668
2018-02-26 06:40



Ini dijelaskan di Apple dokumentasi, tetapi di bawah ini adalah beberapa contoh dari apa yang sebenarnya terjadi. Perhatikan bahwa tidak ada kata kunci "atom", jika Anda tidak menentukan "nonatomik" maka properti adalah atom, tetapi menentukan "atom" secara eksplisit akan menghasilkan kesalahan.

//@property(nonatomic, retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    return userName;
}

- (void) setUserName:(UITextField *)userName_ {
    [userName_ retain];
    [userName release];
    userName = userName_;
}

Sekarang, varian atomnya sedikit lebih rumit:

//@property(retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    UITextField *retval = nil;
    @synchronized(self) {
        retval = [[userName retain] autorelease];
    }
    return retval;
}

- (void) setUserName:(UITextField *)userName_ {
    @synchronized(self) {
      [userName_ retain];
      [userName release];
      userName = userName_;
    }
}

Pada dasarnya, versi atom harus mengambil kunci untuk menjamin keamanan benang, dan juga menabrak hitungan ref pada objek (dan jumlah autorelease untuk menyeimbangkannya) sehingga objek dijamin ada untuk pemanggil, jika tidak ada adalah kondisi perlombaan yang potensial jika untaian lain menetapkan nilai, menyebabkan penghitungan ulang untuk turun ke 0.

Sebenarnya ada sejumlah besar variasi berbeda tentang bagaimana hal-hal ini bekerja tergantung pada apakah properti adalah nilai skalar atau objek, dan bagaimana mempertahankan, menyalin, baca-saja, non-atomik, dll. Berinteraksi. Secara umum, synthesizer properti hanya tahu bagaimana melakukan "hal yang benar" untuk semua kombinasi.


342
2018-02-26 06:24



Atom

  • adalah perilaku default
  • akan memastikan proses ini selesai oleh CPU, sebelum proses lain mengakses variabel
  • tidak cepat, karena memastikan proses selesai sepenuhnya

Non-Atom

  • BUKAN perilaku default
  • lebih cepat (untuk kode yang disintesis, yaitu, untuk variabel yang dibuat menggunakan @property dan @synthesize)
  • tidak aman dari benang
  • dapat menyebabkan perilaku tak terduga, ketika dua proses yang berbeda mengakses variabel yang sama pada saat yang bersamaan

148
2018-05-25 10:56



Cara terbaik untuk memahami perbedaannya adalah dengan menggunakan contoh berikut.

Misalkan ada properti string atom yang disebut "nama", dan jika Anda menelepon [self setName:@"A"] dari utas A, panggil [self setName:@"B"] dari utas B, dan panggil [self name] dari thread C, maka semua operasi pada thread yang berbeda akan dilakukan secara serial yang berarti jika satu thread mengeksekusi seorang setter atau getter, maka thread lain akan menunggu.

Ini membuat properti "nama" baca / tulis aman, tetapi jika thread lain, D, panggilan [name release] secara bersamaan maka operasi ini mungkin menghasilkan crash karena tidak ada setter / pengambil panggilan yang terlibat di sini. Yang berarti sebuah objek dibaca / tulis aman (ATOMIC), tetapi tidak aman-thread karena utas lainnya dapat secara bersamaan mengirim semua jenis pesan ke objek. Pengembang harus memastikan keamanan benang untuk objek semacam itu.

Jika "nama" properti adalah nonatomik, maka semua untaian dalam contoh di atas - A, B, C, dan D akan dijalankan secara bersamaan sehingga menghasilkan hasil yang tidak dapat diprediksi. Dalam kasus atom, salah satu dari A, B atau C akan mengeksekusi pertama, tetapi D masih bisa dijalankan secara paralel.


125
2018-01-31 18:36



Sintaks dan semantik sudah didefinisikan dengan baik oleh jawaban yang sangat bagus untuk pertanyaan ini. Karena eksekusi dan kinerja tidak terinci dengan baik, saya akan menambahkan jawaban saya.

Apa perbedaan fungsional antara 3 ini?

Saya selalu menganggap atom sebagai standar cukup penasaran. Pada tingkat abstraksi tempat kita bekerja, menggunakan properti atomik untuk kelas sebagai kendaraan untuk mencapai 100% keselamatan benang adalah kasus sudut. Untuk program multithread yang benar-benar tepat, intervensi oleh programmer hampir pasti merupakan persyaratan. Sementara itu, karakteristik kinerja dan pelaksanaannya belum terperinci secara mendalam. Setelah menulis beberapa program yang sangat multithread selama bertahun-tahun, saya telah menyatakan properti saya sebagai nonatomicsepanjang waktu karena atom tidak masuk akal untuk tujuan apa pun. Selama diskusi tentang rincian sifat atom dan nonatomik pertanyaan iniSaya melakukan beberapa pemrofilan, menemukan beberapa hasil yang aneh.

Eksekusi

Baik. Hal pertama yang saya ingin bersihkan adalah bahwa implementasi penguncian adalah implementasi-didefinisikan dan diabstraksikan. Louis menggunakan @synchronized(self) dalam contohnya - saya telah melihat ini sebagai sumber kebingungan yang umum. Implementasinya tidak sebenarnya menggunakan @synchronized(self); itu menggunakan level objek kunci berputar. Ilustrasi Louis bagus untuk ilustrasi tingkat tinggi menggunakan konstruksi yang kita semua kenal, tetapi penting untuk mengetahui bahwa itu tidak digunakan @synchronized(self).

Perbedaan lain adalah bahwa properti atom akan mempertahankan / melepaskan siklus objek Anda di dalam pengambil.

Kinerja

Inilah bagian yang menarik: Kinerja menggunakan akses properti atom di tidak terbantahkan (mis. satu-threaded) kasus dapat benar-benar sangat cepat dalam beberapa kasus. Dalam kasus yang kurang ideal, penggunaan akses atom dapat menghabiskan biaya lebih dari 20 kali lipat biaya overhead nonatomic. Selagi Berlomba Kasus menggunakan 7 thread adalah 44 kali lebih lambat untuk struct tiga byte (2,2 GHz Core i7 Quad Core, x86_64). Struk tiga byte adalah contoh properti yang sangat lambat.

Catatan samping yang menarik: User-defined accessors dari struct tiga byte 52 kali lebih cepat daripada accessor atom yang disintesis; atau 84% kecepatan akses non-atom yang disintesis.

Objek dalam kasus yang diperebutkan juga bisa melebihi 50 kali.

Karena banyaknya pengoptimalan dan variasi dalam penerapan, cukup sulit untuk mengukur dampak dunia nyata dalam konteks ini. Anda mungkin sering mendengar sesuatu seperti "Percayai, kecuali Anda membuat profil dan menemukannya adalah masalah". Karena tingkat abstraksi, sebenarnya cukup sulit untuk mengukur dampak yang sebenarnya. Memungut biaya nyata dari profil bisa sangat memakan waktu, dan karena abstraksi, cukup tidak akurat. Juga, ARC vs MRC dapat membuat perbedaan besar.

Jadi mari melangkah mundur, tidak fokus pada implementasi akses properti, kami akan menyertakan tersangka seperti biasa objc_msgSend, dan memeriksa beberapa hasil tingkat tinggi dunia nyata untuk banyak panggilan ke a NSString rajin masuk tidak terbantahkan kasus (nilai dalam detik):

  • MRC | nonatomik | getters yang diimplementasikan secara manual: 2
  • MRC | nonatomik | pengambil disintesis: 7
  • MRC | atom | pengambil disintesis: 47
  • ARC | nonatomik | pengambil disintesis: 38 (catatan: ARC menambahkan penghitungan ulang bersepeda di sini)
  • ARC | atom | pengambil disintesis: 47

Seperti yang Anda duga, aktivitas hitung referensi / bersepeda adalah kontributor signifikan dengan atomik dan di bawah ARC. Anda juga akan melihat perbedaan yang lebih besar dalam kasus yang diperebutkan.

Meskipun saya memperhatikan kinerja, saya masih berkata Semantik Pertama!. Sementara itu, kinerja merupakan prioritas rendah untuk banyak proyek. Namun, mengetahui detail pelaksanaan dan biaya teknologi yang Anda gunakan tentu tidak merugikan. Anda harus menggunakan teknologi yang tepat untuk kebutuhan, tujuan, dan kemampuan Anda. Semoga ini akan menghemat beberapa jam perbandingan, dan membantu Anda membuat keputusan yang lebih baik saat merancang program Anda.


108
2017-08-18 09:47



Atom= keamanan benang

Non-atom = Tidak ada keamanan benang

Keamanan benang:

Variabel instan adalah aman-thread jika mereka berperilaku dengan benar ketika diakses dari beberapa utas, terlepas dari penjadwalan atau interleaving dari pelaksanaan thread tersebut oleh lingkungan runtime, dan tanpa sinkronisasi tambahan atau koordinasi lain pada bagian kode panggilan.

Dalam konteks kami:

Jika thread mengubah nilai instance, nilai yang diubah tersedia untuk semua untaian, dan hanya satu utas yang dapat mengubah nilai pada satu waktu.

Di mana untuk digunakan atomic:

jika variabel instan akan diakses dalam lingkungan multithread.

Implikasi dari atomic:

Tidak secepat nonatomic karena nonatomic tidak memerlukan pekerjaan pengawas apa pun dari saat runtime.

Di mana untuk digunakan nonatomic:

Jika variabel instan tidak akan diubah oleh beberapa utas Anda dapat menggunakannya. Ini meningkatkan kinerja.


89
2017-07-10 13:07



Saya menemukan penjelasan yang cukup baik tentang sifat atom dan non-atom sini. Berikut ini beberapa teks yang relevan dari yang sama:

'Atomic' berarti tidak bisa dipecah.   Dalam istilah OS / pemrograman panggilan fungsi atom adalah salah satu yang tidak dapat terganggu - seluruh fungsi harus dijalankan, dan tidak bertukar dari CPU dengan beralih konteks OS biasa sampai selesai. Hanya jika Anda tidak tahu: karena CPU hanya dapat melakukan satu hal pada satu waktu, OS memutar akses ke CPU untuk semua proses yang berjalan dalam irisan waktu kecil, untuk memberikan ilusi multitasking. Penjadwal CPU dapat (dan tidak) mengganggu proses pada titik mana pun dalam pelaksanaannya - bahkan di pertengahan fungsi panggilan. Jadi untuk tindakan seperti memperbarui variabel counter bersama di mana dua proses dapat mencoba untuk memperbarui variabel pada saat yang sama, mereka harus dieksekusi 'secara atom', yaitu setiap tindakan pembaruan harus selesai secara keseluruhan sebelum proses lain dapat ditukarkan ke CPU.

Jadi saya akan menebak bahwa atom dalam hal ini berarti metode pembaca atribut tidak dapat terganggu - pada dasarnya berarti bahwa variabel yang sedang dibaca oleh metode tidak dapat mengubah nilai mereka setengah jalan karena beberapa thread / panggilan / fungsi lain mendapat bertukar ke CPU.

Karena atomic variabel tidak dapat terganggu, nilai yang terkandung oleh mereka pada titik tertentu (thread-lock) dijamin tidak rusak, meskipun, memastikan kunci thread ini membuat akses ke mereka lebih lambat. non-atomic variabel, di sisi lain, tidak membuat jaminan seperti itu tetapi menawarkan kemewahan akses yang lebih cepat. Untuk menyimpulkannya, pergilah non-atomic ketika Anda tahu variabel Anda tidak akan diakses oleh beberapa utas secara bersamaan dan mempercepatnya.


67
2018-02-24 05:17



Setelah membaca begitu banyak artikel, posting Stack Overflow dan membuat aplikasi demo untuk memeriksa atribut properti variabel, saya memutuskan untuk menempatkan semua informasi atribut bersama-sama:

  1. atomic             // Default
  2. nonatomic
  3. strong = retain        // Default
  4. weak = unsafe_unretained
  5. retain
  6. assign             // Default
  7. unsafe_unretained
  8. copy
  9. readonly
  10. readwrite                 // Default

Di dalam artikel Variabel atribut properti atau pengubah di iOS Anda dapat menemukan semua atribut yang disebutkan di atas, dan itu pasti akan membantu Anda.

  1. atomic

    • atomic berarti hanya satu utas mengakses variabel (tipe statis).
    • atomic benang aman.
    • Tetapi kinerjanya lambat
    • atomic adalah perilaku default
    • Pengakses atom dalam lingkungan yang tidak dikumpulkan sampah (yaitu ketika menggunakan retain / release / autorelease) akan menggunakan kunci untuk memastikan bahwa thread lain tidak mengganggu pengaturan / perolehan nilai yang benar.
    • Itu sebenarnya bukan kata kunci.
       

    Contoh:

        @property (retain) NSString *name;
    
        @synthesize name;
    
  2. nonatomic

    • nonatomic berarti beberapa utas mengakses variabel (tipe dinamis).
    • nonatomic tidak aman.
    • Tetapi cepat dalam kinerjanya
    • nonatomic BUKAN perilaku default. Kita perlu menambahkan nonatomic kata kunci dalam atribut properti.
    • Ini dapat menghasilkan perilaku yang tidak diharapkan, ketika dua proses yang berbeda (untaian) mengakses variabel yang sama pada saat yang bersamaan.
       

    Contoh:

        @property (nonatomic, retain) NSString *name;
    
        @synthesize name;
    

61
2018-03-21 07:10