在属性声明中,原子和非原子意味着什么?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
这三者之间的操作差异是什么?
在属性声明中,原子和非原子意味着什么?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
这三者之间的操作差异是什么?
当前回答
-原子意味着只有一个线程访问变量(静态类型)。-原子是线程安全的。-但它的性能很慢
如何申报:
由于原子是默认的,
@property (retain) NSString *name;
实现文件中的AND
self.name = @"sourov";
假设与三个财产相关的任务是
@property (retain) NSString *name;
@property (retain) NSString *A;
@property (retain) NSString *B;
self.name = @"sourov";
所有财产并行工作(如异步)。
如果从线程A调用“name”,
And
同时如果你打电话
[self setName:@"Datta"]
从线程B,
现在,如果*name属性是非原子的,那么
它将返回A的值“Datta”它将返回B的值“Datta”
这就是为什么非原子被称为线程不安全的原因,但由于并行执行,它的性能很快
现在如果*name属性是原子的
这将确保A的价值“Sourov”然后它将返回B的值“Datta”
这就是为什么原子被称为线程安全和这就是为什么它被称为读写安全
这种情况操作将连续执行。性能缓慢
-非原子意味着多线程访问变量(动态类型)。
-非原子是线程不安全的。
-但它的性能很快
-非原子不是默认行为,我们需要在属性属性中添加非原子关键字。
对于In Swift确认Swift财产在ObjC意义上是非原子的。一个原因是,您需要考虑每个属性的原子性是否足以满足您的需求。
参考:https://forums.developer.apple.com/thread/25642
有关更多信息,请访问网站http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html
其他回答
原子=螺纹安全
非原子=无线程安全
螺纹安全:
如果实例变量在从多个线程访问时行为正确,则它们是线程安全的,而不考虑运行时环境对这些线程执行的调度或交织,并且调用代码部分没有额外的同步或其他协调。
在我们的背景下:
如果一个线程更改了实例的值,则所有线程都可以使用更改的值,并且一次只有一个线程可以更改该值。
在何处使用原子:
如果要在多线程环境中访问实例变量。
原子的含义:
没有非原子的速度快,因为非原子的运行时不需要任何看门狗的工作。
在何处使用非原子:
如果实例变量不会被多个线程更改,您可以使用它。它可以提高性能。
原子的
是默认行为将确保当前进程在另一个进程访问变量之前由CPU完成速度不快,因为它可以确保整个过程完全完成
非原子的
不是默认行为更快(对于合成代码,即使用@property和@synthetic创建的变量)非线程安全当两个不同的进程同时访问同一变量时,可能会导致意外行为
原子意味着一次只能有一个线程访问变量(静态类型)。原子是线程安全的,但它很慢。
非原子意味着多个线程可以同时访问变量(动态类型)。非原子线程不安全,但速度很快。
最后两个是相同的;“atomic”是默认行为(请注意,它实际上不是一个关键字;它仅在不存在非atomic的情况下被指定——在最近版本的llvm/claung中,atomic被添加为关键字)。
假设您正在@合成方法实现,原子与非原子将更改生成的代码。如果您正在编写自己的setter/getter,原子/非原子/保留/分配/复制只是建议。(注意:@synthey现在是LLVM最新版本中的默认行为。也不需要声明实例变量;它们也会自动合成,并且在名称前加一个_,以防止意外的直接访问)。
使用“atomic”,合成的setter/getter将确保始终从getter返回或由setter设置整个值,而不管setter在任何其他线程上的活动如何。也就是说,如果线程A位于getter的中间,而线程B调用setter,则实际可行的值(很可能是自动释放的对象)将返回给A中的调用方。
在非原子中,没有这样的保证。因此,非原子比“原子”快得多。
“原子”不做的是保证线程安全。如果线程A同时调用getter,而线程B和C使用不同的值调用setter,那么线程A可能会得到返回的三个值中的任何一个值——在调用setter之前的值,或者在B和C中传递给setter的值。同样,对象可能会以B或C的值结束,这是无法分辨的。
确保数据完整性——多线程编程的主要挑战之一——是通过其他方式实现的。
添加到此:
当使用多个依赖财产时,单个属性的原子性也不能保证线程安全。
考虑:
@property(atomic, copy) NSString *firstName;
@property(atomic, copy) NSString *lastName;
@property(readonly, atomic, copy) NSString *fullName;
在这种情况下,线程A可以通过调用setFirstName:然后调用setLastName:来重命名对象。同时,线程B可以在线程A的两次调用之间调用fullName,并将接收新的名字和旧的姓氏。
要解决这个问题,您需要一个事务模型。也就是说,某些其他类型的同步和/或排除允许在更新依赖财产时排除对fullName的访问。
这个问题的其他优秀答案已经定义了语法和语义。因为执行和性能没有很好地详细描述,我将补充我的答案。
这三者之间的功能差异是什么?
我一直认为原子是一个默认值,这很奇怪。在我们工作的抽象级别上,使用类的原子财产作为实现100%线程安全的工具是一个很难的情况。对于真正正确的多线程程序,几乎肯定需要程序员的干预。同时,性能特征和执行还没有详细描述。多年来,我编写了一些大量的多线程程序,一直在声明我的财产是非原子的,因为原子对于任何目的都是不敏感的。在讨论原子和非原子财产这个问题的细节时,我做了一些分析,遇到了一些奇怪的结果。
处决
好的。我首先要澄清的是,锁定实现是由实现定义和抽象的。Louis在他的示例中使用了@synchronized(self)——我认为这是一个常见的混淆来源。该实现实际上没有使用@synchronized(self);它使用对象级自旋锁。Louis的插图很适合使用我们都熟悉的结构进行高级插图,但重要的是要知道它没有使用@synchronized(self)。
另一个区别是,原子财产将在getter中保留/释放对象的循环。
表演
这里有一个有趣的部分:在无竞争(例如单线程)的情况下,使用原子属性访问的性能在某些情况下会非常快。在不太理想的情况下,使用原子访问的开销可能是非原子访问的20倍以上。而使用7个线程的Contested情况下,三字节结构(2.2 GHz Core i7四核,x86_64)的速度慢了44倍。三字节结构是一个非常慢的属性的示例。
有趣的补充说明:三字节结构的用户定义访问器比合成原子访问器快52倍;或合成非原子存取器速度的84%。
在有争议的情况下,物体也可以超过50倍。
由于实现中的优化和变化的数量,很难在这些环境中测量真实世界的影响。你可能经常听到这样的话:“相信它,除非你分析并发现它是个问题”。由于抽象级别的原因,实际上很难衡量实际影响。从概要文件中提取实际成本可能非常耗时,而且由于抽象,非常不准确。同样,ARC与MRC可以产生巨大的差异。
因此,让我们后退一步,不关注属性访问的实现,我们将包括像objc_msgSend这样的常见问题,并在无争议的情况下(以秒为单位的值)检查对NSString getter的许多调用的一些实际高级结果:
MRC|非原子|手动实现的getter:2MRC|非原子|合成吸气剂:7MRC|原子|合成吸气剂:47ARC |非原子|合成吸气剂:38(注意:ARC在此添加了循环引用计数)ARC |原子|合成吸气剂:47
正如你可能已经猜到的,引用计数活动/循环是原子论和ARC下的一个重要贡献。你也会在有争议的案例中看到更大的差异。
虽然我非常关注性能,但我还是说Semantics First!。同时,性能对于许多项目来说是一个低优先级。然而,了解您所使用的技术的执行细节和成本当然不会有什么坏处。你应该根据自己的需要、目的和能力使用正确的技术。希望这将节省您几个小时的比较,并帮助您在设计程序时做出更明智的决定。