Frage Was ist der Unterschied zwischen atomaren und nicht atomaren Attributen?


Was tun? atomic und nonatomic meine in Eigenschaftsdeklarationen?

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

Was ist der operative Unterschied zwischen diesen drei?


1722
2018-02-26 02:31


Ursprung


Antworten:


Die letzten beiden sind identisch; "atomisch" ist das Standardverhalten (Beachten Sie, dass es sich nicht um ein Keyword handelt. es wird nur durch die Abwesenheit von angegeben nonatomic - atomic wurde in den letzten Versionen von llvm / clang als Schlüsselwort hinzugefügt.

Unter der Annahme, dass Sie die Methodenimplementierungen synthetisieren, ändert der atomare vs. nicht-atomare Code den generierten Code. Wenn Sie Ihre eigenen Setter / Getter schreiben, sind atomare / nichtatomare / behalten / assign / copy nur beratend. (Hinweis: @synthesize ist jetzt das Standardverhalten in den letzten Versionen von LLVM. Es ist auch nicht notwendig, Instanzvariablen zu deklarieren; sie werden auch automatisch synthetisiert und haben eine _ ihrem Namen vorangestellt, um einen versehentlichen direkten Zugriff zu verhindern).

Mit "Atom" wird der synthetisierte Setter / Getter dafür sorgen, dass a ganze Der Wert wird immer vom Getter zurückgegeben oder vom Setter festgelegt, unabhängig von der Setter-Aktivität in einem anderen Thread. Das heißt, wenn sich Thread A in der Mitte des Getters befindet, während Thread B den Setter aufruft, wird ein tatsächlicher realisierbarer Wert - höchstwahrscheinlich ein Objekt mit Autorelease - an den Aufrufer in A zurückgegeben.

Im nonatomic, keine solchen Garantien werden gemacht. So, nonatomic ist wesentlich schneller als "atomar".

Was "Atom" tut nicht Machen Sie keine Garantien über die Sicherheit von Gewinden. Wenn Thread A den Getter gleichzeitig mit Thread B aufruft und C den Setter mit anderen Werten aufruft, kann Thread A jeden der drei zurückgegebenen Werte abrufen - den einen vor dem Aufruf der Setter oder einen der an die Setter übergebenen Werte in B und C. Ebenso kann das Objekt mit dem Wert von B oder C enden, keine Möglichkeit zu erzählen.

Die Gewährleistung der Datenintegrität - eine der Hauptherausforderungen der Multi-Thread-Programmierung - wird auf andere Weise erreicht.

Hinzu kommt:

atomicity einer einzelnen Eigenschaft kann auch die Threadsicherheit nicht garantieren, wenn mehrere abhängige Eigenschaften im Spiel sind.

Erwägen:

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

In diesem Fall könnte Thread A das Objekt durch Aufruf umbenennen setFirstName: und dann anrufen setLastName:. In der Zwischenzeit kann Thread B anrufen fullName zwischen den beiden Aufrufen von Thread A und erhält den neuen Vornamen zusammen mit dem alten Nachnamen.

Um dies anzugehen, benötigen Sie ein Transaktionsmodell. I.e. eine andere Art von Synchronisation und / oder Ausschluss, mit der man den Zugriff auf fullName während die abhängigen Eigenschaften aktualisiert werden.


1668
2018-02-26 06:40



Dies wird in Apples erklärt Dokumentation, aber unten sind einige Beispiele dafür, was tatsächlich passiert. Beachten Sie, dass es kein "atomares" Schlüsselwort gibt, wenn Sie "nichtatomisch" nicht angeben, dann ist die Eigenschaft atomar, aber das explizite Angeben von "atomar" führt zu einem Fehler.

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

- (UITextField *) userName {
    return userName;
}

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

Die atomare Variante ist jetzt etwas komplizierter:

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

Grundsätzlich muss die atomare Version eine Sperre nehmen, um die Thread-Sicherheit zu garantieren, und auch die ref-Zählung auf dem Objekt (und der Autorelease-Zählung, um es auszugleichen) stoßen, so dass das Objekt garantiert für den Anrufer existiert, ansonsten dort ist eine potentielle Race Condition, wenn ein anderer Thread den Wert setzt, was dazu führt, dass der ref count auf 0 fällt.

Es gibt tatsächlich eine große Anzahl verschiedener Varianten, wie diese Dinge funktionieren, abhängig davon, ob die Eigenschaften skalare Werte oder Objekte sind und wie behalten, kopieren, schreibgeschützt, nicht-atomisch usw. interagieren. Im Allgemeinen wissen die Eigenschaftssynthesizer nur, wie man das "Richtige" für alle Kombinationen macht.


342
2018-02-26 06:24



Atomar

  • ist das Standardverhalten
  • stellt sicher, dass der aktuelle Prozess von der CPU abgeschlossen wird, bevor ein anderer Prozess auf die Variable zugreift
  • ist nicht schnell, da es sicherstellt, dass der Prozess vollständig abgeschlossen ist

Nicht-Atomic

  • ist nicht das Standardverhalten
  • schneller (für synthetisierten Code, dh für Variablen, die mit @property und @synthesize erstellt wurden)
  • nicht threadsicher
  • kann zu unerwartetem Verhalten führen, wenn zwei verschiedene Prozesse gleichzeitig auf dieselbe Variable zugreifen

148
2018-05-25 10:56



Der beste Weg, um den Unterschied zu verstehen, ist das folgende Beispiel.

Angenommen, es gibt eine atomare String-Eigenschaft namens "name", und wenn Sie anrufen [self setName:@"A"] von Thread A, Anruf [self setName:@"B"] von Thread B und Anruf [self name] Ab Thread C werden dann alle Operationen auf verschiedenen Threads seriell ausgeführt, dh wenn ein Thread einen Setter oder Getter ausführt, warten andere Threads.

Dies macht die Eigenschaft "name" lesensicher / schreibsicher, wenn aber ein anderer Thread D aufruft [name release] gleichzeitig kann diese Operation einen Absturz verursachen, da hier kein Setzer / Getter-Aufruf involviert ist. Dies bedeutet, dass ein Objekt schreibgeschützt (ATOMIC) ist, aber nicht Thread-sicher, da andere Threads gleichzeitig alle Arten von Nachrichten an das Objekt senden können. Der Entwickler sollte die Thread-Sicherheit für solche Objekte sicherstellen.

Wenn die Eigenschaft "name" nichtatomisch ist, werden alle Threads in obigem Beispiel - A, B, C und D - gleichzeitig ausgeführt, was zu unvorhersehbaren Ergebnissen führt. Im Fall von atomaren Systemen wird entweder A, B oder C zuerst ausgeführt, aber D kann immer noch parallel ausgeführt werden.


125
2018-01-31 18:36



Die Syntax und Semantik sind bereits durch andere ausgezeichnete Antworten auf diese Frage klar definiert. weil Ausführung und Performance sind nicht detailliert, ich werde meine Antwort hinzufügen.

Was ist der funktionelle Unterschied zwischen diesen 3?

Ich hatte atomare Standards immer als ziemlich merkwürdig betrachtet. Auf der Abstraktionsebene, an der wir arbeiten, ist die Verwendung von atomaren Eigenschaften für eine Klasse als ein Fahrzeug, um 100% Fadensicherheit zu erreichen, ein Eckfall. Für wirklich korrekte Multithread-Programme ist eine Intervention durch den Programmierer fast sicher eine Anforderung. In der Zwischenzeit wurden die Leistungsmerkmale und die Ausführung noch nicht detailliert beschrieben. Nachdem ich im Laufe der Jahre einige Multithread-Programme geschrieben hatte, erklärte ich meine Eigenschaften als nonatomicdie ganze Zeit, weil Atom zu keinem Zweck sinnvoll war. Bei der Diskussion der Details der atomaren und nichtatomaren Eigenschaften diese Frage, Ich habe einige Profiling gefunden einige seltsame Ergebnisse.

Ausführung

OK. Als erstes möchte ich aufklären, dass die Sperrimplementierung implementierungsdefiniert und abstrahiert ist. Louis benutzt @synchronized(self) in seinem Beispiel - ich habe das als eine gemeinsame Quelle der Verwirrung gesehen. Die Implementierung nicht tatsächlich benutzen @synchronized(self); Es verwendet Objektebene Spin-Sperren. Louis Illustration ist gut für eine High-Level-Illustration mit Konstrukten, die wir alle kennen, aber es ist wichtig zu wissen, dass es nicht verwendet wird @synchronized(self).

Ein weiterer Unterschied besteht darin, dass atomare Eigenschaften Ihre Objekte im Getter beibehalten / freigeben.

Performance

Hier ist der interessante Teil: Performance mit atomaren Eigenschaften Zugriffe in unbestritten (z. B. single-threaded) Fälle können in einigen Fällen wirklich sehr schnell sein. In weniger als idealen Fällen kann die Verwendung von atomaren Zugriffen mehr als das 20-fache des Overhead kosten nonatomic. Während Umstritten Fall mit 7 Threads war 44 mal langsamer für die Drei-Byte-Struktur (2,2 GHz Kern i7 Quad Core, x86_64). Die Drei-Byte-Struktur ist ein Beispiel für eine sehr langsame Eigenschaft.

Interessante Randnotiz: Benutzerdefinierte Accessoren der Drei-Byte-Struktur waren 52-mal schneller als die synthetisierten Atom-Accessoren; oder 84% der Geschwindigkeit von synthetisierten nicht-atomaren Zugriffsmethoden.

Gegenstände in umstrittenen Fällen können auch 50 Mal überschreiten.

Aufgrund der Anzahl von Optimierungen und Variationen in Implementierungen ist es ziemlich schwierig, reale Auswirkungen in diesen Kontexten zu messen. Sie können oft etwas wie "Vertraue es, es sei denn, du profilierst und es ist ein Problem" hören. Aufgrund der Abstraktionsebene ist es tatsächlich ziemlich schwierig, den tatsächlichen Einfluss zu messen. Die tatsächlichen Kosten von Profilen zu berechnen, kann sehr zeitaufwendig und aufgrund von Abstraktionen sehr ungenau sein. ARC vs MRC kann auch einen großen Unterschied machen.

Also lass uns zurücktreten, nicht Fokussiert auf die Implementierung von Property Access, werden wir die üblichen Verdächtigen wie objc_msgSend, und einige echte High-Level-Ergebnisse für viele Anrufe zu einem prüfen NSString Getter herein unbestritten Fälle (Werte in Sekunden):

  • MRC | nichtatomisch | manuell implementierte Getter: 2
  • MRC | nichtatomisch | synthetisierter Getter: 7
  • MRC | Atom | synthetisierter Getter: 47
  • ARC | nichtatomisch | synthetisierter Getter: 38 (Anmerkung: ARC's Ref-Count-Zyklus wird hier hinzugefügt)
  • ARC | Atom | synthetisierter Getter: 47

Wie Sie wahrscheinlich schon vermutet haben, ist die Referenzzählaktivität bzw. der zyklische Zyklus ein signifikanter Faktor bei Atomics und unter ARC. Sie würden auch größere Unterschiede in umstrittenen Fällen sehen.

Obwohl ich der Leistung viel Aufmerksamkeit schenke, sage ich immer noch Semantik zuerst!. In der Zwischenzeit hat die Leistung für viele Projekte eine niedrige Priorität. Das Wissen um Ausführungsdetails und die Kosten von Technologien, die Sie verwenden, ist jedoch nicht schädlich. Sie sollten die richtige Technologie für Ihre Bedürfnisse, Zwecke und Fähigkeiten verwenden. Dies wird Ihnen hoffentlich ein paar Stunden Vergleiche ersparen und Ihnen helfen, eine fundiertere Entscheidung beim Entwerfen Ihrer Programme zu treffen.


108
2017-08-18 09:47



Atomar= Fadensicherheit

Nicht atomar = Keine Fadensicherheit

Fadensicherheit:

Instanzvariablen sind Thread-sicher, wenn sie sich korrekt verhalten, wenn sie von mehreren Threads aus aufgerufen werden, unabhängig von der Planung oder Verschachtelung der Ausführung dieser Threads durch die Laufzeitumgebung und ohne zusätzliche Synchronisation oder andere Koordination seitens des aufrufenden Codes.

In unserem Zusammenhang:

Wenn ein Thread den Wert der Instanz ändert, ist der geänderte Wert für alle Threads verfügbar, und nur ein Thread kann den Wert gleichzeitig ändern.

Wo zu verwenden atomic:

Wenn auf die Instanzvariable in einer Multithread-Umgebung zugegriffen wird.

Implikation von atomic:

Nicht so schnell wie nonatomic weil nonatomic benötigt zur Laufzeit keine Watchdog-Arbeit.

Wo zu verwenden nonatomic:

Wenn die Instanzvariable nicht durch mehrere Threads geändert wird, können Sie sie verwenden. Es verbessert die Leistung.


89
2017-07-10 13:07



Ich fand eine recht gute Erklärung für atomare und nichtatomare Eigenschaften Hier. Hier ist ein relevanter Text vom selben:

"atomar" bedeutet, dass es nicht abgebaut werden kann.   In OS / Programmierung ist ein atomarer Funktionsaufruf einer, der nicht unterbrochen werden kann - die gesamte Funktion muss ausgeführt werden und nicht durch die übliche Kontextumschaltung des OS bis zum Abschluss aus der CPU ausgelagert werden. Nur für den Fall, dass Sie es nicht wussten: Da die CPU nur eine Sache gleichzeitig tun kann, rotiert das Betriebssystem den Zugriff auf die CPU auf alle laufenden Prozesse in kleinen Zeitscheiben, um den Illusion von Multitasking. Der CPU-Scheduler kann (und tut es) einen Prozess zu jedem Zeitpunkt seiner Ausführung unterbrechen - sogar während eines Funktionsaufrufs. Für Aktionen wie das Aktualisieren von Shared Counter - Variablen, bei denen zwei Prozesse gleichzeitig versuchen könnten, die Variable zu aktualisieren, müssen sie "atomisch" ausgeführt werden, dh jede Aktualisierungsaktion muss vollständig abgeschlossen sein, bevor ein anderer Prozess in die ZENTRALPROZESSOR.

Also würde ich vermuten, dass atomare in diesem Fall bedeutet, dass die Methoden des Attribut-Lesers nicht unterbrochen werden können - was bedeutet, dass die von der Methode gelesenen Variablen ihren Wert nicht halb ändern können, weil ein anderer Thread / Aufruf / Funktion kommt auf die CPU vertauscht.

Weil das atomic Variablen können nicht unterbrochen werden, der von ihnen enthaltene Wert ist an jedem Punkt (Thread-Lock) garantiert unverdorbenObwohl diese Thread-Sperre sichergestellt wird, wird der Zugriff auf sie langsamer. non-atomic Variablen dagegen geben keine Garantie, bieten aber den Luxus eines schnelleren Zugangs. Um es zusammenzufassen, gehen Sie mit non-atomic wenn Sie wissen, dass auf Ihre Variablen nicht gleichzeitig mehrere Threads zugreifen und die Geschwindigkeit erhöht wird.


67
2018-02-24 05:17



Nachdem ich so viele Artikel gelesen, Stack Overflow gepostet und Demo-Anwendungen erstellt habe, um Variablenattribute zu überprüfen, habe ich beschlossen, alle Attribute zusammen zu stellen:

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

Im Artikel Variable Eigenschaftenattribute oder Modifizierer in iOS Sie können alle oben genannten Attribute finden, und das wird Ihnen definitiv helfen.

  1. atomic

    • atomic bedeutet, dass nur ein Thread auf die Variable zugreift (statischer Typ).
    • atomic ist fadensicher.
    • Aber es ist langsam in der Leistung
    • atomic ist das Standardverhalten
    • Atomare Zugriffsmethoden in einer Umgebung, in der kein Müll gesammelt wird (d. H. Wenn Retain / Release / Autorelease verwendet wird), verwenden eine Sperre, um sicherzustellen, dass ein anderer Thread das korrekte Einstellen / Abrufen des Werts nicht beeinträchtigt.
    • Es ist kein Keyword.
       

    Beispiel:

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

    • nonatomic bedeutet, dass mehrere Threads auf die Variable zugreifen (dynamischer Typ).
    • nonatomic ist Thread-unsicher.
    • Aber es ist schnell in der Leistung
    • nonatomic ist kein Standardverhalten. Wir müssen hinzufügen nonatomic Schlüsselwort im Eigenschaftenattribut.
    • Es kann zu unerwartetem Verhalten führen, wenn zwei verschiedene Prozesse (Threads) gleichzeitig auf dieselbe Variable zugreifen.
       

    Beispiel:

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

61
2018-03-21 07:10



Die einfachste Antwort zuerst: Es gibt keinen Unterschied zwischen Ihren beiden zweiten Beispielen. Standardmäßig sind Eigenschaftenaccessoren atomar.

Atomare Zugriffsmethoden in einer Umgebung, in der kein Müll gesammelt wird (d. H. Wenn Retain / Release / Autorelease verwendet wird), verwenden eine Sperre, um sicherzustellen, dass ein anderer Thread das korrekte Einstellen / Abrufen des Werts nicht beeinträchtigt.

Siehe die "Leistung und Threading"Abschnitt der Objective-C 2.0-Dokumentation von Apple für einige weitere Informationen und für andere Überlegungen beim Erstellen von Multithread-Anwendungen.


52
2018-02-26 02:56