Vraag Wat is het verschil tussen de atomaire en niet-atomaire kenmerken?


Wat doen atomic en nonatomic betekenen in eigendomsverklaringen?

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

Wat is het operationele verschil tussen deze drie?


1722
2018-02-26 02:31


oorsprong


antwoorden:


De laatste twee zijn identiek; "atomisch" is het standaardgedrag (merk op dat het eigenlijk geen sleutelwoord is; het wordt alleen gespecificeerd door de afwezigheid van nonatomic - atomic is als een trefwoord toegevoegd in recente versies van llvm / clang).

Ervan uitgaande dat u de synthese van de methode-implementaties @synthetiseert, verandert atoom vs. niet-atomisch de gegenereerde code. Als u uw eigen setter / getters schrijft, zijn atomic / nonatomic / retain / assign / copy slechts adviserend. (Opmerking: @synthesize is nu het standaardgedrag in recente versies van LLVM. Het is ook niet nodig om instantievariabelen te declareren, ze worden ook automatisch gesynthetiseerd en hebben een _ aan hun naam toegevoegd om onbedoelde directe toegang te voorkomen).

Met "atomic" zorgt de gesynthetiseerde setter / getter ervoor dat een geheel de waarde wordt altijd geretourneerd door de getter of ingesteld door de setter, ongeacht de activiteit van de setter op een andere thread. Dat wil zeggen, als thread A zich in het midden van de getter bevindt, terwijl thread B de setter oproept, wordt een werkelijke haalbare waarde - een mogelijk autoreleased object wordt hoogstwaarschijnlijk teruggezonden naar de beller in A.

In nonatomic, dergelijke garanties zijn niet gemaakt. Dus, nonatomic is aanzienlijk sneller dan "atomisch".

Wat "atomisch" doet niet do is om het even welke waarborgen over draadveiligheid. Als thread A de getter gelijktijdig roept terwijl thread B en C de setter met verschillende waarden aanroepen, kan thread A een van de drie waarden teruggeven - de waarde voorafgaand aan eventuele setters die worden aangeroepen of een van de waarden die aan de setters worden doorgegeven in B en C. Evenzo kan het object eindigen met de waarde van B of C, geen manier om te vertellen.

Het waarborgen van gegevensintegriteit - een van de belangrijkste uitdagingen van multi-threaded programmeren - wordt op andere manieren bereikt.

Voeg hieraan toe:

atomicity van een enkele eigenschap kan ook de veiligheid van threads niet garanderen als meerdere afhankelijke eigenschappen in het spel zijn.

Overwegen:

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

In dit geval kan thread A het object hernoemen door te callen setFirstName: en dan bellen setLastName:. In de tussentijd kan thread B bellen fullName tussen de twee gesprekken van thread A in en ontvangt de nieuwe voornaam gekoppeld aan de oude achternaam.

Om dit aan te pakken, hebt u een transactiemodel. D.w.z. een ander soort synchronisatie en / of uitsluiting waarmee iemand toegang kan uitsluiten fullName terwijl de afhankelijke eigenschappen worden bijgewerkt.


1668
2018-02-26 06:40



Dit wordt uitgelegd in Apple's documentatie, maar hieronder zijn enkele voorbeelden van wat er daadwerkelijk gebeurt. Merk op dat er geen "atoom" sleutelwoord is, als u niet "niet-atomisch" specificeert, dan is de eigenschap atomisch, maar het expliciet specificeren van "atoom" zal resulteren in een fout.

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

- (UITextField *) userName {
    return userName;
}

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

Nu is de atomaire variant een beetje ingewikkelder:

//@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_;
    }
}

Kortom, de atomaire versie moet een vergrendeling nemen om de veiligheid van threads te garanderen en stoot ook de ref-telling op het object (en het aantal autoreleases om het te balanceren) zodat het object gegarandeerd voor de beller bestaat, anders is er is een potentiële race-voorwaarde als een andere thread de waarde instelt, waardoor de ref-telling naar 0 daalt.

Er zijn eigenlijk een groot aantal verschillende varianten van hoe deze dingen werken, afhankelijk van of de eigenschappen scalaire waarden of objecten zijn en hoe behouden, kopiëren, alleen lezen, niet-atomisch, enz. Communiceren. Over het algemeen weten de eigenschappensynthesizers gewoon hoe ze het "juiste" voor alle combinaties moeten doen.


342
2018-02-26 06:24



atomair

  • is het standaardgedrag
  • zorgt ervoor dat het huidige proces wordt voltooid door de CPU, voordat een ander proces toegang krijgt tot de variabele
  • is niet snel, want het zorgt ervoor dat het proces volledig wordt voltooid

Non-Atomic

  • is NIET het standaardgedrag
  • sneller (voor gesynthetiseerde code, dat wil zeggen, voor variabelen gemaakt met @property en @synthesize)
  • niet draadveilig
  • kan resulteren in onverwacht gedrag, wanneer twee verschillende processen tegelijkertijd toegang hebben tot dezelfde variabele

148
2018-05-25 10:56



De beste manier om het verschil te begrijpen, is het gebruik van het volgende voorbeeld.

Stel dat er een atoomstringeigenschap is die "naam" heet en als u belt [self setName:@"A"] van draad A, bel [self setName:@"B"] van draad B, en bel [self name] van thread C, dan worden alle bewerkingen op verschillende threads in serie uitgevoerd, wat betekent dat als één thread een setter of getter uitvoert, andere threads zullen wachten.

Dit maakt eigenschap "name" lezen / schrijven veilig, maar als een andere thread, D, roept [name release] tegelijkertijd kan deze operatie een crash veroorzaken, omdat hier geen setter / getter-call betrokken is. Wat betekent dat een object lees- / schrijfveilig (ATOMIC) is, maar niet threadveilig, aangezien een ander threads tegelijkertijd elk type berichten naar het object kan sturen. De ontwikkelaar moet zorgen voor draadveiligheid voor dergelijke objecten.

Als de eigenschap "name" niet-atomair was, worden alle threads in het bovenstaande voorbeeld - A, B, C en D gelijktijdig uitgevoerd, wat een onvoorspelbaar resultaat oplevert. In het geval van atomic, zal een van A, B of C als eerste worden uitgevoerd, maar D kan nog steeds parallel worden uitgevoerd.


125
2018-01-31 18:36



De syntaxis en semantiek zijn al goed gedefinieerd door andere uitstekende antwoorden op deze vraag. Omdat executie en prestatie zijn niet goed gedetailleerd, ik zal mijn antwoord toevoegen.

Wat is het functionele verschil tussen deze 3?

Ik had atoom altijd als een beetje nieuwsgierig beschouwd. Op het abstractieniveau waar we aan werken, is het gebruik van atomaire eigenschappen voor een klasse als een voertuig om 100% draadveiligheid te bereiken een hoekgeval. Voor echt correcte multithreaded programma's is interventie door de programmeur bijna zeker een vereiste. Ondertussen zijn de prestatiekenmerken en -uitvoering nog niet gedetailleerd beschreven. Na het schrijven van een aantal zwaar multithreaded programma's door de jaren heen, had ik mijn eigenschappen als verklaard nonatomicde hele tijd omdat atomic voor geen enkel doel zinvol was. Tijdens de bespreking van de details van atomaire en niet-atomaire eigenschappen deze vraag, Ik heb wat profilering gedaan tegen een paar merkwaardige resultaten.

Executie

OK. Het eerste wat ik wil ophelderen is dat de implementatie van de vergrendeling is geïmplementeerd en geabstraheerd. Louis gebruikt @synchronized(self) in zijn voorbeeld - ik heb dit als een algemene bron van verwarring gezien. De implementatie doet dat niet werkelijk gebruik @synchronized(self); het gebruikt objectniveau spin sloten. De illustratie van Louis is goed voor een illustratie op hoog niveau met behulp van constructies waar we allemaal bekend mee zijn, maar het is belangrijk om te weten dat het niet gebruikt wordt @synchronized(self).

Een ander verschil is dat atomaire eigenschappen je objecten binnen de getter zullen behouden / vrijgeven.

Prestatie

Hier is het interessante deel: Prestaties met toegang tot atoomeigenschappen in onbetwist (bijvoorbeeld single-threaded) gevallen kunnen in sommige gevallen echt erg snel zijn. In minder dan ideale gevallen kost het gebruik van atomaire toegangen meer dan 20 keer de overheadkosten van nonatomic. Terwijl de omstreden case met 7 threads was 44 keer langzamer voor de structuur van drie bytes (2,2 GHz Core i7 Quad Core, x86_64). De structuur van drie bytes is een voorbeeld van een zeer trage eigenschap.

Interessante kanttekening: door de gebruiker gedefinieerde accessors van de structuur met drie bytes waren 52 keer sneller dan de gesynthetiseerde atomaire accessors; of 84% de snelheid van gesynthetiseerde niet-atomaire toegangen.

Objecten in betwiste gevallen kunnen ook 50 keer overschrijden.

Vanwege het aantal optimalisaties en variaties in implementaties, is het vrij moeilijk om real-world impacts in deze contexten te meten. Je hoort misschien wel zoiets als "Vertrouw het, tenzij je een profiel maakt en vindt dat het een probleem is". Vanwege het abstractieniveau is het eigenlijk vrij moeilijk om de werkelijke impact te meten. Het verzamelen van werkelijke kosten uit profielen kan erg tijdrovend zijn en vanwege abstracties nogal onnauwkeurig. Ook kan ARC versus MRC een groot verschil maken.

Dus laten we een stap terug doen, niet met de nadruk op de implementatie van toegang tot onroerend goed, nemen we de gebruikelijke verdachten mee zoals objc_msgSenden onderzoek enkele real-world resultaten op hoog niveau voor veel oproepen naar a NSString vangstof binnen onbetwist gevallen (waarden in seconden):

  • MRC | niet-atomair | handmatig geïmplementeerde getters: 2
  • MRC | niet-atomair | gesynthetiseerde getter: 7
  • MRC | atomisch | gesynthetiseerde getter: 47
  • ARC | niet-atomair | gesynthetiseerde getter: 38 (let op: ARC voegt hier ref-count-cycli toe)
  • ARC | atomisch | gesynthetiseerde getter: 47

Zoals je waarschijnlijk al geraden hebt, levert de activiteit van de referentietelling / fietsen een belangrijke bijdrage aan atoomgolven en onder ARC. Je zou ook grotere verschillen zien in betwiste zaken.

Hoewel ik veel aandacht besteed aan de uitvoering, zeg ik nog steeds Semantiek eerst!. Ondertussen hebben prestaties voor veel projecten een lage prioriteit. Het kennen van uitvoeringsdetails en kosten van technologieën die u gebruikt, doet echter zeker geen kwaad. U moet de juiste technologie gebruiken voor uw behoeften, doelen en mogelijkheden. Hopelijk bespaart u hiermee een paar uur aan vergelijkingen en kunt u een beter geïnformeerde beslissing nemen bij het ontwerpen van uw programma's.


108
2017-08-18 09:47



atomair= draadveiligheid

Non-atomaire = Geen draadveiligheid

Veiligheid van de draad:

Exemplaarvariabelen zijn thread-safe als ze zich correct gedragen wanneer ze worden geopend via meerdere threads, ongeacht de planning of verscherving van de uitvoering van die threads door de runtime-omgeving en zonder aanvullende synchronisatie of andere coördinatie van de kant van de aanroepcode.

In onze context:

Als een thread de waarde van de instantie wijzigt, is de gewijzigde waarde beschikbaar voor alle threads en kan slechts één thread de waarde per keer wijzigen.

Waar te gebruiken atomic:

als de instantievariabele wordt geopend in een multithread-omgeving.

Implicatie van atomic:

Niet zo snel als nonatomic omdat nonatomic vereist geen watchdog werk dat van runtime.

Waar te gebruiken nonatomic:

Als de instantievariabele niet door meerdere threads wordt gewijzigd, kunt u deze gebruiken. Het verbetert de prestaties.


89
2017-07-10 13:07



Ik vond een vrij goed verklaarde verklaring van atomaire en niet-atomaire eigenschappen hier. Hier is wat relevante tekst van hetzelfde:

'atomisch' betekent dat het niet kan worden afgebroken.   In OS / programmeertermen is een atomaire functieaanroep een oproep die niet kan worden onderbroken - de volledige functie moet worden uitgevoerd en niet uit de CPU worden geruild door de gebruikelijke contextomschakeling van het besturingssysteem totdat deze voltooid is. Voor het geval u het nog niet wist: aangezien de CPU maar één ding tegelijk kan doen, draait het besturingssysteem de toegang tot de CPU naar alle actieve processen in kleine tijdsegmenten, om de illusie van multitasking. De CPU-scheduler kan een proces op elk punt in de uitvoering ervan (en doet) dit onderbreken - zelfs tijdens de oproep in de middenfunctie. Dus voor acties zoals het bijwerken van gedeelde tellervariabelen waarbij twee processen kunnen proberen om de variabele tegelijkertijd bij te werken, moeten ze 'atomisch' worden uitgevoerd, dat wil zeggen, elke updateactie moet volledig worden voltooid voordat een ander proces kan worden geruild naar de CPU.

Dus ik vermoed dat atomisch in dit geval betekent dat de attribute reader methodes niet kunnen worden onderbroken - in feite betekent dat de variabele (n) die door de methode worden gelezen hun waarde halverwege niet kunnen veranderen omdat een andere thread / call / functie krijgt geruild op de CPU.

Omdat het atomic variabelen kunnen niet worden onderbroken, de waarde die ze op elk moment bevatten is (thread-lock) gegarandeerd onbedorven, hoewel, zorgen dat deze thread lock toegang tot hen langzamer maakt. non-atomic variabelen, aan de andere kant, bieden geen garantie, maar bieden wel de luxe van snellere toegang. Samenvattend, ga met non-atomic wanneer u weet dat uw variabelen niet tegelijkertijd door meerdere threads worden benaderd en de dingen versnellen.


67
2018-02-24 05:17



Na het lezen van zo veel artikelen, Stack Overflow-berichten en het maken van demotoepassingen om eigenschappen van variabele eigenschappen te controleren, besloot ik om alle attributeninformatie samen te voegen:

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

In het artikel Variabele eigenschapsattributen of modifiers in iOS je kunt alle bovengenoemde attributen vinden, en dat zal je zeker helpen.

  1. atomic

    • atomic betekent dat slechts één thread toegang heeft tot de variabele (statisch type).
    • atomic is draadveilig.
    • Maar het is traag in prestaties
    • atomic is het standaardgedrag
    • Atomaire accessors in een niet-garbage verzamelde omgeving (d.w.z. wanneer gebruik wordt gemaakt van retain / release / autorelease) zullen een slot gebruiken om te verzekeren dat een andere thread niet interfereert met de juiste instelling / het verkrijgen van de waarde.
    • Het is eigenlijk geen sleutelwoord.
       

    Voorbeeld:

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

    • nonatomic betekent meerdere threads toegang tot de variabele (dynamisch type).
    • nonatomic is thread-onveilig.
    • Maar het is snel in prestaties
    • nonatomic is NIET standaard gedrag. We moeten het toevoegen nonatomic zoekwoord in het eigenschapkenmerk.
    • Dit kan resulteren in onverwacht gedrag, wanneer twee verschillende processen (threads) tegelijkertijd toegang hebben tot dezelfde variabele.
       

    Voorbeeld:

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

61
2018-03-21 07:10