原子属性和非原子属性有什么区别?
属性声明中的atomic
和 nonatomic
是什么意思?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
这三者在操作上有什么区别呢?
What do atomic
and nonatomic
mean in property declarations?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
What is the operational difference between these three?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(28)
原子 = 线程安全
非原子 = 无线程安全
线程安全:
如果从多个线程访问实例变量时行为正确,则实例变量是线程安全的,无论调度或交错如何运行时环境执行这些线程的过程,并且调用代码部分没有额外的同步或其他协调。
在我们的上下文中:
如果一个线程更改了实例的值,则更改后的值可供所有线程使用,并且一次只有一个线程可以更改该值。
在哪里使用原子:
如果要在多线程环境中访问实例变量。
atomic
的含义:不如
nonatomic
快,因为nonatomic
不需要运行时对其进行任何看门狗工作。在哪里使用非原子:
如果实例变量不会被多个线程更改,则可以使用它。 它提高了性能。
Atomic = thread safety
Non-atomic = No thread safety
Thread safety:
Instance variables are thread-safe if they behave correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.
In our context:
If a thread changes the value of the instance the changed value is available to all the threads, and only one thread can change the value at a time.
Where to use
atomic
:if the instance variable is gonna be accessed in a multithreaded environment.
Implication of
atomic
:Not as fast as
nonatomic
becausenonatomic
doesn't require any watchdog work on that from runtime .Where to use
nonatomic
:If the instance variable is not gonna be changed by multiple threads you can use it. It improves the performance.
阅读了这么多文章、Stack Overflow 帖子并制作了演示应用程序来检查可变属性属性后,我决定将所有属性信息放在一起:
atomic
// Defaultnonatomic
weak = unsafe_unretained
retain
assign
// 默认unsafe_unretained
readonly
readwrite
//文章中默认 iOS中的变量属性属性或修饰符你可以找到上面提到的所有属性,那肯定会帮你。
原子
atomic
表示只有一个线程访问该变量(静态类型)。atomic
是线程安全的。原子
是默认行为示例:
非原子
nonatomic
表示多线程访问变量(动态类型)。nonatomic
是线程不安全的。nonatomic
不是默认行为。 我们需要在 property 属性中添加nonatomic
关键字。示例:
After reading so many articles, Stack Overflow posts and making demo applications to check variable property attributes, I decided to put all the attributes information together:
atomic
// Defaultnonatomic
strong = retain
// Defaultweak = unsafe_unretained
retain
assign
// Defaultunsafe_unretained
copy
readonly
readwrite
// DefaultIn the article Variable property attributes or modifiers in iOS you can find all the above-mentioned attributes, and that will definitely help you.
atomic
atomic
means only one thread access the variable (static type).atomic
is thread safe.atomic
is the default behaviorExample:
nonatomic
nonatomic
means multiple thread access the variable (dynamic type).nonatomic
is thread-unsafe.nonatomic
is NOT default behavior. We need to add thenonatomic
keyword in the property attribute.Example:
我找到了对原子和非原子属性的很好的解释 这里。 以下是相同的一些相关文本:
由于
原子
变量不能被中断,因此它们在任何点所包含的值都保证(线程锁)未损坏,尽管确保此线程锁可以访问对他们来说要慢一些。 另一方面,非原子变量不提供此类保证,但确实提供了更快的访问速度。 总而言之,当您知道多个线程不会同时访问您的变量并加快速度时,请选择非原子
。I found a pretty well put explanation of atomic and non-atomic properties here. Here's some relevant text from the same:
Because the
atomic
variables can not be interrupted, the value contained by them at any point is (thread-lock) guaranteed to be uncorrupted, although, ensuring this thread lock makes access to them slower.non-atomic
variables, on the other hand, make no such guarantee but do offer the luxury of quicker access. To sum it up, go withnon-atomic
when you know your variables won't be accessed by multiple threads simultaneously and speed things up.原子:
原子保证对属性的访问将以原子方式执行。 例如,它总是返回一个完全初始化的对象,一个线程上属性的任何获取/设置都必须先完成,然后另一个线程才能访问它。
如果您想象以下函数同时在两个线程上发生,您就会明白为什么结果不会很好。
优点:
每次返回完全初始化的对象使其成为多线程情况下的最佳选择。
缺点:
性能下降,使执行速度稍慢
非原子:
与原子不同,它不能确保每次都返回完全初始化的对象。
优点:
执行速度极快。
缺点:
多线程情况下可能出现垃圾值。
Atomic :
Atomic guarantees that access to the property will be performed in an atomic manner. E.g. it always return a fully initialised objects, any get/set of a property on one thread must complete before another can access it.
If you imagine the following function occurring on two threads at once you can see why the results would not be pretty.
Pros :
Return of fully initialised objects each time makes it best choice in case of multi-threading.
Cons :
Performance hit, makes execution a little slower
Non-Atomic :
Unlike Atomic, it doesn't ensure fully initialised object return each time.
Pros :
Extremely fast execution.
Cons :
Chances of garbage value in case of multi-threading.
首先最简单的答案:你的第二个例子之间没有区别。 默认情况下,属性访问器是原子的。
非垃圾收集环境中的原子访问器(即使用保留/释放/自动释放时)将使用锁来确保另一个线程不会干扰值的正确设置/获取。
请参阅“Performance and Threading" Apple Objective-C 2.0 文档部分了解更多信息和创建多线程应用程序时的其他注意事项。
Easiest answer first: There's no difference between your second two examples. By default, property accessors are atomic.
Atomic accessors in a non garbage collected environment (i.e. when using retain/release/autorelease) will use a lock to ensure that another thread doesn't interfere with the correct setting/getting of the value.
See the "Performance and Threading" section of Apple's Objective-C 2.0 documentation for some more information and for other considerations when creating multi-threaded apps.
原子性意味着只有一个线程访问该变量(静态类型)。 Atomic是线程安全的,但速度很慢。
非原子意味着多个线程访问变量(动态类型)。 非原子是线程不安全的,但速度很快。
Atomic means only one thread accesses the variable (static type). Atomic is thread-safe, but it is slow.
Nonatomic means multiple threads access the variable (dynamic type). Nonatomic is thread-unsafe, but it is fast.
Atomic 是线程安全,它慢并且它很好地保证(不保证)无论有多少线程,都只提供锁定的值正在尝试访问同一区域。 当使用原子时,在该函数内编写的一段代码成为临界区的一部分,一次只能有一个线程执行。
它仅保证线程安全; 它不能保证这一点。 我的意思是你为你的车聘请了一位专业司机,但这并不能保证汽车不会发生事故。 然而,概率仍然是最小的。
原子 - 它无法被分解,因此结果是预期的。 对于非原子 - 当另一个线程访问内存区域时,它可以修改它,因此结果是意外的。
代码对话:
原子使属性的 getter 和 setter 线程安全。 例如,如果你写了:
是线程安全的。
不是线程安全的。
Atomic is thread safe, it is slow and it well-assures (not guaranteed) that only the locked value is provided no matter how many threads are attempting access over the same zone. When using atomic, a piece of code written inside this function becomes the part of the critical section, to which only one thread can execute at a time.
It only assures the thread safety; it does not guarantee that. What I mean is you hire an expert driver for you car, still it doesn't guarantees car won't meet an accident. However, probability remains the slightest.
Atomic - it can't be broken down, so the result is expected. With nonatomic - when another thread access the memory zone it can modify it, so the result is unexpected.
Code Talk :
Atomic make getter and setter of the property thread safe. for example if u have written :
is thread safe.
is NOT thread safe.
在此处查看更多信息:https://realm.io/news/tmi-objective-c-property-attributes /
See more here: https://realm.io/news/tmi-objective-c-property-attributes/
没有这样的关键字“atomic”
我们可以使用上面的内容,例如
参见堆栈溢出问题我遇到问题如果我使用@property(atomic,retain)NSString *myString。
There is no such keyword "atomic"
We can use the above like
See Stack Overflow question I am getting issues if I use @property(atomic,retain)NSString *myString.
默认是
原子
,这意味着每当您使用该属性时,它都会降低性能,但它是线程安全的。 Objective-C 所做的是设置一个锁,因此只要执行 setter/getter,只有实际线程可以访问该变量。具有 ivar _internal 的属性的 MRC 示例:
所以最后两个是相同的:
另一方面,
nonatomic
不会向您的代码添加任何内容。 因此,只有您自己编写安全机制,它才是线程安全的。关键字根本不必写为第一个属性属性。
不要忘记,这并不意味着该属性作为一个整体是线程安全的。 只有setter/getter的方法调用是。 但是如果你在 2 个不同的线程中同时使用 setter 和 getter,它也可能会被破坏!
The default is
atomic
, this means it does cost you performance whenever you use the property, but it is thread safe. What Objective-C does, is set a lock, so only the actual thread may access the variable, as long as the setter/getter is executed.Example with MRC of a property with an ivar _internal:
So these last two are the same:
On the other hand does
nonatomic
add nothing to your code. So it is only thread safe if you code security mechanism yourself.The keywords doesn't have to be written as first property attribute at all.
Don't forget, this doesn't mean that the property as a whole is thread-safe. Only the method call of the setter/getter is. But if you use a setter and after that a getter at the same time with 2 different threads, it could be broken too!
如何声明:
由于原子性是默认的,
并且在实现文件中
假设与三个属性相关的任务是
所有属性并行工作(如异步)。
如果您从线程 A 调用“name”,
并且
同时如果您
从线程 B 调用“name”,
现在如果 *name属性是非原子的那么
这就是为什么非原子被称为线程不安全但是因为并行执行所以性能很快
现在如果 *name 属性是原子的
这就是为什么原子被称为线程安全 和
这就是为什么它被称为读写安全
这种情况下的操作将串行执行。
并且性能缓慢
- 非原子意味着多线程访问变量(动态类型)。
- 非原子是线程不安全的。
- 但它性能很快
-Nonatomic 不是默认行为,我们需要在 property 属性中添加 nonatomic 关键字。
对于 In Swift
确认 Swift 属性在 ObjC 意义上是非原子的。 原因之一是您需要考虑每个属性的原子性是否足以满足您的需求。
参考: https://forums.developer.apple.com/thread/25642 信息请访问网站
http://rdcworld-iphone.blogspot.in/2012 /12/variable-property-attributes-or.html
How to declare:
As atomic is default so,
AND in implementation file
Suppose a task related to three properties are
All properties work parallelly (like asynchronously).
If you call "name" from thread A,
And
At the same time if you call
from thread B,
Now If *name property is nonatomic then
Thats why non atomic is called thread unsafe But but it is fast in performance because of parallel execution
Now If *name property is atomic
That's why atomic is called thread Safe and
That's why it is called read-write safe
Such situation operation will perform serially.
And Slow in performance
- Nonatomic means multiple thread access the variable(dynamic type).
- Nonatomic is thread unsafe.
- but it is fast in performance
-Nonatomic is NOT default behavior, we need to add nonatomic keyword in property attribute.
For In Swift
Confirming that Swift properties are nonatomic in the ObjC sense. One reason is so you think about whether per-property atomicity is sufficient for your needs.
Reference: https://forums.developer.apple.com/thread/25642
Fro more info please visit the website
http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html
如果您在多线程代码中使用属性,那么您将能够看到非原子属性和原子属性之间的区别。 非原子比原子更快,并且原子是线程安全的,而不是非原子。
Vijayendra Tripathi 已经给出了多线程环境的示例。
If you are using your property in multi-threaded code then you would be able to see the difference between nonatomic and atomic attributes. Nonatomic is faster than atomic and atomic is thread-safe, not nonatomic.
Vijayendra Tripathi has already given an example for a multi-threaded environment.
开始之前:您必须知道,内存中的每个对象都需要从内存中释放,以便发生新的写入操作。 你不能像在纸上那样简单地在某物上书写。 您必须首先擦除(释放)它,然后才能在上面写入。 如果此时擦除已完成(或完成一半)并且尚未写入任何内容(或写入一半),而您尝试读取它可能会出现很大问题! 原子和非原子可以帮助您以不同的方式处理这个问题。
首先阅读这个问题,然后阅读Bbum 的回答。 另外,再看看我的总结。
原子
将始终保证什么?! 多线程和线程安全有何不同?
是的。 多线程意味着:多个线程可以同时读取共享的数据,并且我们不会崩溃,但它不能保证您不会读取非自动释放的值。 有了线程安全,就可以保证你读到的内容不会被自动释放。
默认情况下,我们不将所有内容设为原子的原因是,存在性能成本,并且对于大多数事情来说,并不真正需要线程安全。 我们代码的某些部分需要它,对于这几个部分,我们需要使用锁、互斥锁或同步以线程安全的方式编写代码。
nonatomic
总体而言,它们在两个方面有所不同:
是否由于有或没有自动释放池而崩溃。
Before you begin: You must know that every object in memory needs to be deallocated from memory for a new writer to happen. You can't just simply write on top of something as you do on paper. You must first erase (dealloc) it and then you can write onto it. If at the moment that the erase is done (or half done) and nothing has yet been wrote (or half wrote) and you try to read it could be very problematic! Atomic and nonatomic help you treat this problem in different ways.
First read this question and then read Bbum's answer. In addition, then read my summary.
atomic
will ALWAYS guaranteeWhat?! Are multithreading and thread safety different?
Yes. Multithreading means: multiple threads can read a shared piece of data at the same time and we will not crash, yet it doesn't guarantee that you aren't reading from a non-autoreleased value. With thread safety, it's guaranteed that what you read is not auto-released.
The reason that we don't make everything atomic by default is, that there is a performance cost and for most things don't really need thread safety. A few parts of our code need it and for those few parts, we need to write our code in a thread-safe way using locks, mutex or synchronization.
nonatomic
Overall they are different in 2 aspects:
Crashing or not because of having or not having an autorelease pool.
Allowing to be read right in the middle of a 'not yet finished write or empty value' or not allowing and only allowing to read when the value is fully written.
原子性
原子(默认)
非原子
https://academy.realm.io/posts/tmi- Objective-c-property-attributes/
原子性属性属性(原子和非原子)不会反映在相应的 Swift 属性声明中,但当导入的属性为从 Swift 访问。
它在 Swift 使用时将保持原子性。
所以——如果你在 Objective-C 中定义了一个原子属性,
https://medium.com/@YogevSitton/atomic -vs-非原子属性-crash-course-d11c23f4366c
Atomicity
atomic (default)
nonatomic
courtesy https://academy.realm.io/posts/tmi-objective-c-property-attributes/
Atomicity property attributes (atomic and nonatomic) are not reflected in the corresponding Swift property declaration, but the atomicity guarantees of the Objective-C implementation still hold when the imported property is accessed from Swift.
So — if you define an atomic property in Objective-C it will remain atomic when used by Swift.
courtesy
https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c
原子属性确保无论有多少线程正在执行 getter 和 getter 操作,都保留完全初始化的值。 设置器在其上。
非原子属性指定合成访问器只是直接设置或返回一个值,不能保证从不同线程同时访问同一值时会发生什么。
The atomic property ensures to retain a fully initialised value irrespective of how many threads are doing getter & setter on it.
The nonatomic property specifies that synthesized accessors simply set or return a value directly, with no guarantees about what happens if that same value is accessed simultaneously from different threads.
原子性意味着一次只有一个线程可以访问该变量(静态类型)。 Atomic是线程安全的,但速度很慢。
非原子意味着多个线程可以同时访问该变量(动态类型)。 非原子是线程不安全的,但速度很快。
Atomic means only one thread can access the variable at a time (static type). Atomic is thread-safe, but it is slow.
Nonatomic means multiple threads can access the variable at same time (dynamic type). Nonatomic is thread-unsafe, but it is fast.
事实是他们使用自旋锁来实现原子属性。 代码如下:
The truth is that they use spin lock to implement atomic property. The code as below:
在一行中:
Atomic
是线程安全的。Nonatomic
是线程不安全的。In a single line:
Atomic
is thread safe.Nonatomic
is thread-unsafe.如果您使用原子性,则意味着线程将是安全且只读的。 如果使用nonatomic,则意味着多个线程访问该变量,是线程不安全的,但执行速度很快,完成了读写操作; 这是一个动态类型。
If you are using atomic, it means the thread will be safe and read-only. If you are using nonatomic, it means the multiple threads access the variable and is thread unsafe, but it is executed fast, done a read and write operations; this is a dynamic type.
原子性:通过使用 NSLOCK 锁定线程来确保线程安全。
非原子:不确保线程安全,因为没有线程锁定机制。
Atomic: Ensure thread-safety by locking the thread using NSLOCK.
Non atomic: Doesn't ensure thread-safety as there is no thread-locking mechanism.
为了简化整个混乱,让我们了解互斥锁。
互斥锁,顾名思义,锁定对象的可变性。 因此,如果该对象被一个类访问,则其他类就不能访问同一个对象。
在 iOS 中,@sychronise 还提供了互斥锁。现在它以 FIFO 模式提供服务,并确保流程不会受到共享同一实例的两个类的影响。 但是,如果任务位于主线程上,请避免使用原子属性访问对象,因为它可能会占用您的 UI 并降低性能。
To simplify the entire confusion, let us understand mutex lock.
Mutex lock, as per the name, locks the mutability of the object. So if the object is accessed by a class, no other class can access the same object.
In iOS,
@sychronise
also provides the mutex lock .Now it serves in FIFO mode and ensures the flow is not affected by two classes sharing the same instance. However, if the task is on main thread, avoid accessing object using atomic properties as it may hold your UI and degrade the performance.在 Objective-C 中,原子属性的实现允许从不同线程安全地读取和写入属性。 对于非原子属性,当同时写入新值时,可以释放读取值的底层指针。
原子性意味着只有一个线程访问该变量(静态类型)。 Atomic是线程安全的,但速度很慢。 非原子意味着多个线程访问变量(动态类型)。非原子是线程不安全的,但速度很快。
In Objective-C the implementation of an atomic property allows properties to be safely read and written from different threads. For nonatomic properties, the underlying pointer of a read value could be released when a new value is being written at the same time.
Atomic means only one thread accesses the variable (static type). Atomic is thread-safe, but it is slow. Nonatomic means multiple threads access the variable (dynamic type). Nonatomic is thread-unsafe, but it is fast.
原子属性:- 当一个变量分配有原子属性时,这意味着它只有一个线程访问,并且它将是线程安全的,并且从性能角度来看会很慢,将具有默认行为。
非原子属性:- 当一个变量分配有非原子属性时,这意味着它具有多线程访问,并且它不是线程安全的,并且从性能角度来看会很快,将具有默认行为,并且当两个不同的线程时想要同时访问变量会给出意想不到的结果。
Atomic properties :- When a variable assigned with atomic property that means it has only one thread access and it will be thread safe and will be slow in performance perspective, will have default behaviour.
Non Atomic Properties :- When a variable assigned with nonatomic property that means it has multi thread access and it will not be thread safe and will be fast in performance perspective, will have default behaviour and when two different threads want to access variable at same time it will give unexpected results.
最后两个是相同的; “atomic”是默认行为(
请注意,它实际上不是关键字;它仅通过缺少来指定 -nonatomic
atomic
在最新版本的 llvm/clang 中添加为关键字)。假设您正在 @synthesizing 方法实现,原子与非原子会更改生成的代码。 如果您正在编写自己的 setter/getter,原子/非原子/保留/分配/复制只是建议性的。 (注意:@synthesize 现在是 LLVM 最新版本中的默认行为。也无需声明实例变量;它们也会自动合成,并且名称前会添加
_
以防止意外直接访问)。使用“atomic”,合成的 setter/getter 将确保始终从 getter 返回整个值或由 setter 设置,无论任何其他线程上的 setter 活动如何。 也就是说,如果线程 A 位于 getter 中间,而线程 B 调用 setter,则实际可行的值(很可能是自动释放的对象)将返回给 A 中的调用者。
在非原子中代码>,不做这样的保证。 因此,
nonatomic
比“atomic”快得多。“原子”不所做的是对线程安全做出任何保证。 如果线程 A 与线程 B 和 C 同时调用 getter,同时线程 B 和 C 使用不同的值调用 setter,则线程 A 可能会获取返回的三个值中的任何一个 - 调用任何 setter 之前的值或传递到 setter 的值之一同样,该对象最终可能会得到 B 或 C 中的值,但无法判断。
确保数据完整性(多线程编程的主要挑战之一)是通过其他方式实现的。
除此之外:
当多个依赖属性发挥作用时,单个属性的原子性也无法保证线程安全。
考虑:
在这种情况下,线程 A 可以通过调用
setFirstName:
然后调用setLastName:
来重命名该对象。 同时,线程 B 可以在线程 A 的两次调用之间调用fullName
,并将收到新的名字和旧的姓氏。为了解决这个问题,您需要一个事务模型。 即,某种其他类型的同步和/或排除,允许在更新依赖属性时排除对
fullName
的访问。The last two are identical; "atomic" is the default behavior (
note that it is not actually a keyword; it is specified only by the absence of--nonatomic
atomic
was added as a keyword in recent versions of llvm/clang).Assuming that you are @synthesizing the method implementations, atomic vs. non-atomic changes the generated code. If you are writing your own setter/getters, atomic/nonatomic/retain/assign/copy are merely advisory. (Note: @synthesize is now the default behavior in recent versions of LLVM. There is also no need to declare instance variables; they will be synthesized automatically, too, and will have an
_
prepended to their name to prevent accidental direct access).With "atomic", the synthesized setter/getter will ensure that a whole value is always returned from the getter or set by the setter, regardless of setter activity on any other thread. That is, if thread A is in the middle of the getter while thread B calls the setter, an actual viable value -- an autoreleased object, most likely -- will be returned to the caller in A.
In
nonatomic
, no such guarantees are made. Thus,nonatomic
is considerably faster than "atomic".What "atomic" does not do is make any guarantees about thread safety. If thread A is calling the getter simultaneously with thread B and C calling the setter with different values, thread A may get any one of the three values returned -- the one prior to any setters being called or either of the values passed into the setters in B and C. Likewise, the object may end up with the value from B or C, no way to tell.
Ensuring data integrity -- one of the primary challenges of multi-threaded programming -- is achieved by other means.
Adding to this:
atomicity
of a single property also cannot guarantee thread safety when multiple dependent properties are in play.Consider:
In this case, thread A could be renaming the object by calling
setFirstName:
and then callingsetLastName:
. In the meantime, thread B may callfullName
in between thread A's two calls and will receive the new first name coupled with the old last name.To address this, you need a transactional model. I.e. some other kind of synchronization and/or exclusion that allows one to exclude access to
fullName
while the dependent properties are being updated.Apple 的文档对此进行了解释,但以下是实际发生情况的一些示例。
请注意,没有“atomic”关键字,如果不指定“nonatomic”,则该属性是原子的,但显式指定“atomic”会导致错误。如果不指定“ nonatomic”,则该属性是原子的,但如果您愿意,您仍然可以在最新版本中显式指定“atomic”。
现在,原子变体有点复杂:
基本上,原子版本必须获取锁以保证线程安全,并且还会增加对象上的引用计数(以及自动释放计数以平衡它),以便保证调用者存在对象,否则如果另一个线程正在设置该值,则存在潜在的竞争条件,导致引用计数下降到 0。
实际上,这些东西的工作方式有大量不同的变体,具体取决于是否属性是标量值或对象,以及保留、复制、只读、非原子等如何交互。 一般来说,属性合成器只知道如何为所有组合做“正确的事情”。
This is explained in Apple's documentation, but below are some examples of what is actually happening.
Note that there is no "atomic" keyword, if you do not specify "nonatomic", then the property is atomic, but specifying "atomic" explicitly will result in an error.If you do not specify "nonatomic", then the property is atomic, but you can still specify "atomic" explicitly in recent versions if you want to.
Now, the atomic variant is a bit more complicated:
Basically, the atomic version has to take a lock in order to guarantee thread safety, and also is bumping the ref count on the object (and the autorelease count to balance it) so that the object is guaranteed to exist for the caller, otherwise there is a potential race condition if another thread is setting the value, causing the ref count to drop to 0.
There are actually a large number of different variants of how these things work depending on whether the properties are scalar values or objects, and how retain, copy, readonly, nonatomic, etc interact. In general the property synthesizers just know how to do the "right thing" for all combinations.
原子
非原子
Atomic
Non-Atomic
理解差异的最佳方法是使用以下示例。
假设有一个名为“name”的原子字符串属性,如果从线程 A 调用
[self setName:@"A"]
,则调用[self setName:@"B"]< /code> 从线程 B 调用,并从线程 C 调用
[self name]
,那么不同线程上的所有操作将串行执行,这意味着如果一个线程正在执行 setter 或 getter,那么其他线程将执行等待。这使得属性“name”读/写安全,但如果另一个线程 D 同时调用
[name release]
那么此操作可能会产生崩溃,因为这里不涉及 setter/getter 调用。 这意味着对象是读/写安全的(ATOMIC),但不是线程安全的,因为另一个线程可以同时向该对象发送任何类型的消息。 开发人员应该确保此类对象的线程安全。如果属性“name”是非原子的,则上例中的所有线程 - A、B、C 和 D 将同时执行,产生任何不可预测的结果。 在原子的情况下,A、B或C之一将首先执行,但D仍然可以并行执行。
The best way to understand the difference is using the following example.
Suppose there is an atomic string property called "name", and if you call
[self setName:@"A"]
from thread A, call[self setName:@"B"]
from thread B, and call[self name]
from thread C, then all operations on different threads will be performed serially which means if one thread is executing a setter or getter, then other threads will wait.This makes property "name" read/write safe, but if another thread, D, calls
[name release]
simultaneously then this operation might produce a crash because there is no setter/getter call involved here. Which means an object is read/write safe (ATOMIC), but not thread-safe as another threads can simultaneously send any type of messages to the object. The developer should ensure thread-safety for such objects.If the property "name" was nonatomic, then all threads in above example - A,B, C and D will execute simultaneously producing any unpredictable result. In case of atomic, either one of A, B or C will execute first, but D can still execute in parallel.
这个问题的其他优秀答案已经很好地定义了语法和语义。 由于执行和性能没有详细说明,我将添加我的答案。
我一直认为原子作为默认值非常好奇。 在我们工作的抽象级别,使用类的原子属性作为实现 100% 线程安全的工具是一种特殊情况。 对于真正正确的多线程程序,几乎肯定需要程序员的干预。 同时,性能特征和执行尚未深入详细说明。 多年来,我编写了一些大量的多线程程序,我一直将我的属性声明为非原子的,因为原子对于任何目的都是不明智的。 在讨论原子和非原子属性的细节时 这个问题,我做了一些分析,遇到了一些奇怪的结果。
执行
好的。 我要澄清的第一件事是锁定实现是实现定义的和抽象的。 Louis 在他的示例中使用了
@synchronized(self)
——我认为这是一个常见的混乱来源。 该实现实际上并未使用@synchronized(self)
; 它使用对象级自旋锁。 Louis 的插图非常适合使用我们都熟悉的结构进行高级插图,但重要的是要知道它不使用@synchronized(self)
。另一个区别是原子属性将在 getter 中保留/释放循环您的对象。
性能
这是有趣的部分:在无竞争(例如单线程)情况下使用原子属性访问的性能在某些情况下可能非常快。 在不太理想的情况下,使用原子访问的开销可能是非原子访问开销的 20 倍以上。 而使用 7 个线程的有争议情况对于三字节结构 (2.2 GHz 核心 i7 四核,x86_64)。 三字节结构是一个非常慢的属性的示例。
有趣的旁注:三字节结构的用户定义访问器比合成原子访问器快 52 倍; 或合成非原子访问器速度的 84%。
有争议案件中的对象也可能超过 50 次。
由于实施过程中存在大量优化和变化,因此很难衡量这些环境中的实际影响。 您可能经常听到类似“相信它,除非您分析并发现它是一个问题”之类的话。 由于抽象级别的原因,实际上很难衡量实际影响。 从配置文件中收集实际成本可能非常耗时,而且由于抽象,非常不准确。 同样,ARC 与 MRC 可以产生很大的不同。
因此,让我们退一步,不关注属性访问的实现,我们将包括诸如
objc_msgSend
之类的常见嫌疑人,并检查许多现实世界的高级结果在无争议情况下调用NSString
getter(值以秒为单位):正如您可能已经猜到的那样,引用计数活动/循环是原子和 ARC 下的重要贡献者。 您还会在有争议的案件中看到更大的差异。
尽管我非常关注性能,但我仍然说语义第一!。 与此同时,对于许多项目来说,性能并不是最重要的。 然而,了解您所使用的技术的执行细节和成本当然不会有什么坏处。 您应该根据您的需求、目的和能力使用正确的技术。 希望这将为您节省几个小时的比较时间,并帮助您在设计程序时做出更明智的决定。
The syntax and semantics are already well-defined by other excellent answers to this question. Because execution and performance are not detailed well, I will add my answer.
I'd always considered atomic as a default quite curious. At the abstraction level we work at, using atomic properties for a class as a vehicle to achieve 100% thread-safety is a corner case. For truly correct multithreaded programs, intervention by the programmer is almost certainly a requirement. Meanwhile, performance characteristics and execution have not yet been detailed in depth. Having written some heavily multithreaded programs over the years, I had been declaring my properties as
nonatomic
the entire time because atomic was not sensible for any purpose. During discussion of the details of atomic and nonatomic properties this question, I did some profiling encountered some curious results.Execution
Ok. The first thing I would like to clear up is that the locking implementation is implementation-defined and abstracted. Louis uses
@synchronized(self)
in his example -- I have seen this as a common source of confusion. The implementation does not actually use@synchronized(self)
; it uses object level spin locks. Louis's illustration is good for a high-level illustration using constructs we are all familiar with, but it's important to know it does not use@synchronized(self)
.Another difference is that atomic properties will retain/release cycle your objects within the getter.
Performance
Here's the interesting part: Performance using atomic property accesses in uncontested (e.g. single-threaded) cases can be really very fast in some cases. In less than ideal cases, use of atomic accesses can cost more than 20 times the overhead of
nonatomic
. While the Contested case using 7 threads was 44 times slower for the three-byte struct (2.2 GHz Core i7 Quad Core, x86_64). The three-byte struct is an example of a very slow property.Interesting side note: User-defined accessors of the three-byte struct were 52 times faster than the synthesized atomic accessors; or 84% the speed of synthesized nonatomic accessors.
Objects in contested cases can also exceed 50 times.
Due to the number of optimizations and variations in implementations, it's quite difficult to measure real-world impacts in these contexts. You might often hear something like "Trust it, unless you profile and find it is a problem". Due to the abstraction level, it's actually quite difficult to measure actual impact. Gleaning actual costs from profiles can be very time consuming, and due to abstractions, quite inaccurate. As well, ARC vs MRC can make a big difference.
So let's step back, not focussing on the implementation of property accesses, we'll include the usual suspects like
objc_msgSend
, and examine some real-world high-level results for many calls to aNSString
getter in uncontested cases (values in seconds):As you have probably guessed, reference count activity/cycling is a significant contributor with atomics and under ARC. You would also see greater differences in contested cases.
Although I pay close attention to performance, I still say Semantics First!. Meanwhile, performance is a low priority for many projects. However, knowing execution details and costs of technologies you use certainly doesn't hurt. You should use the right technology for your needs, purposes, and abilities. Hopefully this will save you a few hours of comparisons, and help you make a better informed decision when designing your programs.