在设置属性的时候, 我们都会写上nonatomic,  基本没有写过atomic, 苹果建议这么做, 因为atomic严重影响了性能.

但是atomic影响了多少? 如果一个属性真的需要在多线程下读写, 那么使用atomic和其他锁之间的性能差多少?

atomic的底层实现只是在 setter 和 getter 方法中加了一个锁, 这个锁表面上是自旋锁, 但是在最新的runtime版本上是一个os_unfair_lock。

但是spinlock_t从名字上看是一个自旋锁, 但是真正对应的类实现中采用的是 os_unfair_lock, 这波操作真的是挂羊头卖狗肉。

写下测试代码测试100W次, 让atomic和信号量 | unfair_lock | NSLock | synchronized 进行PK, 看看到底那个的效率更高.

最终结果, 按照升序排列后, 可以看到 原子性的效率最高, 然后是unfair_lock, 而 synchronized 果然是效率最低, 处于鄙视链的底端.

还是用图更直观的感受,

单独来看, atomic的加锁效率是很高的啊,  为什么苹果不推荐使用atomic了?  个人总结为以下2点 ,更详细的原因和原理参考 :   ios 原子属性nonatomic/atomic

  1. 系统用一个全局生效的字典保存属性值与atomic锁的对应关系, 系统最多提供8个atomic锁给atomic加锁解锁, 当一个项目中有几万个属性都是原子性的时候,  几万映射到8个锁上, 很多属性都会对应到同一把锁上, 那么这个属性就得等其他毫不相关的属性完成读写, 自己才能进行操作, 而且set/get是一个特别高频的操作.
  2. atomic只针对特定场景保证线程安全, 存在局限性. 只能保证set/get的线程安全, 对于更大范围的线程安全是无法保证的. 
            举一个很简单的例子,​​​假设定义属性 NSInteger i 是原子的,对i进行 i = i + 1;
    这个操作就是不安全的。因为原子性只能保证读写安全,而该表达式需要三步操作:
    1.先进行get, 读取i的值存入寄存器;
    2.将寄存器的值加1;
    3.使用寄存器修改后的值给i赋值;
    atomic只能保证1和3是线程安全的, 如果在第1步完成的时候,i被其他线程修改了,那么表达式执行的结果就会与预期的不一样,也就是不安全的。所以要解决这样的线程安全问题, 只能对 整个表达式进行加锁, 单纯对i 设置atomic达不到预期的.

综上, atomic在大范围使用的情况下效率低下, 而且效果不太好, 存在局限性, 所以苹果把线程安全的责任交给了开发者, 由开发者来保证线程安全.

经常看到网上有对比加锁/解锁效率,这次我也借这个机会简单对比下, 加锁解锁1000W次, 数据如下

最后, 本次测试使用设备为iPhone 6S, 系统为iOS 14.0, 下面是测试的代码

#import "ViewController.h"
@import Darwin.os.lock;// 循环1000W次
static const NSInteger TestCount = 10000 * 1000;@interface ViewController ()
// 使用原子性的锁
@property (atomic, strong) NSObject *obj_atomic;
// 外界加锁
@property (nonatomic, strong) NSObject *obj_nonatomic;
@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];CFTimeInterval start = 0;CFTimeInterval end = 0;// 原子性加锁解锁100W次,耗时:0.23Sstart = CACurrentMediaTime();[self testAtomic];end = CACurrentMediaTime();NSLog(@"原子性加锁解锁%zd次,耗时:%.2lfS",TestCount,end-start);// 信号量加锁解锁100W次,耗时:0.54Sstart = CACurrentMediaTime();[self testSemaphore];end = CACurrentMediaTime();NSLog(@"信号量加锁解锁%zd次,耗时:%.2lfS",TestCount,end-start);// NSLock加锁解锁100W次,耗时:0.52Sstart = CACurrentMediaTime();[self testLock];end = CACurrentMediaTime();NSLog(@"NSLock加锁解锁%zd次,耗时:%.2lfS",TestCount,end-start);// UnfairLock加锁解锁100W次,耗时:0.30Sstart = CACurrentMediaTime();[self testUnfairLock];end = CACurrentMediaTime();NSLog(@"UnfairLock加锁解锁%zd次,耗时:%.2lfS",TestCount,end-start);// Synchronized加锁解锁100W次,耗时:0.70Sstart = CACurrentMediaTime();[self testSynchronized];end = CACurrentMediaTime();NSLog(@"Synchronized加锁解锁%zd次,耗时:%.2lfS",TestCount,end-start);
}- (void)testAtomic {for (NSInteger i = 0; i < TestCount; i++) {self.obj_atomic = [[NSObject alloc] init];}for (NSInteger i = 0; i < TestCount; i++) {[self.obj_atomic class];}
}- (void)testSemaphore {dispatch_semaphore_t sem = dispatch_semaphore_create(1);for (NSInteger i = 0; i < TestCount; i++) {dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);self.obj_nonatomic = [[NSObject alloc] init];dispatch_semaphore_signal(sem);}for (NSInteger i = 0; i < TestCount; i++) {dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);[self.obj_nonatomic class];dispatch_semaphore_signal(sem);}
}- (void)testLock {NSLock *lock = [[NSLock alloc] init];for (NSInteger i = 0; i < TestCount; i++) {[lock lock];self.obj_nonatomic = [[NSObject alloc] init];[lock unlock];}for (NSInteger i = 0; i < TestCount; i++) {[lock lock];[self.obj_nonatomic class];[lock unlock];}
}- (void)testUnfairLock {os_unfair_lock_t unfair_lock = &(OS_UNFAIR_LOCK_INIT);for (NSInteger i = 0; i < TestCount; i++) {os_unfair_lock_lock(unfair_lock);self.obj_nonatomic = [[NSObject alloc] init];os_unfair_lock_unlock(unfair_lock);}for (NSInteger i = 0; i < TestCount; i++) {os_unfair_lock_lock(unfair_lock);[self.obj_nonatomic class];os_unfair_lock_unlock(unfair_lock);}
}- (void)testSynchronized {for (NSInteger i = 0; i < TestCount; i++) {@synchronized (self) {self.obj_nonatomic = [[NSObject alloc] init];}}for (NSInteger i = 0; i < TestCount; i++) {@synchronized (self) {[self.obj_nonatomic class];}}
}@end

ios 原子属性atomic加锁性能与锁对比, 不推荐的原因相关推荐

  1. iOS - 线程中常见的几种锁

    线程锁主要是用来解决"共享资源"的问题,实际开发中或多或少的都会用到各类线程锁,为了线程的安全我们有必要了解常见的几种锁,下面是本人查看一些大牛的博客然后整理的内容,加上自己的一些 ...

  2. iOS进阶之atomic一定是线程安全的吗(10)

    IOS项目中nonatomic和atomic分析 //有两个属性,分别设置为nonatomic和atomic #import <UIKit/UIKit.h>@interface ViewC ...

  3. ios 线程休眠_iOS底层分析 - 线程锁(一)NSLock

    大纲 常用锁介绍 自旋锁和互斥锁的一些问题 NSLock及源码分析 NSLock 坑 一.常用锁介绍 锁的目的是为了解决资源抢夺 iOS中的常用的锁有如下几种: 1.自旋锁: 使用与多线程同步的一种锁 ...

  4. 偏向锁、轻量级锁、重量级锁加锁过程即锁升级膨胀过程

    偏向锁.轻量级锁.重量级锁加锁过程即锁升级膨胀过程 synchronized 偏向锁 为什么要引入偏向锁 偏向锁加锁过程 线程获取到锁对象的偏向锁之后,执行完同步代码块之后,会释放这个偏向锁吗 使用了 ...

  5. 高性能iOS开发--移动应用的性能

    打算把<高性能iOS开发>这本书公开出来,供大家学习.这是第一章,感兴趣的可以订阅我的专题 高性能iOS应用开发. 本书假设你是 iOS 开发人员,有长期开发原生 iOS 应用的经验,并且 ...

  6. iOS 使用Instruments优化内存性能

    iOS 使用Instruments优化内存性能 问题 项目中使用到图片合成视频,发现内存增长十分的迅速,导致一些因为内存引起的问题,本文使用这个案例,结合Instruments工具检测和分析问题,最终 ...

  7. python 多人连接mysql 进行事务操作 对mysql加锁与释放锁

    python 多人连接mysql 对mysql进行事务操作 对mysql加锁与释放锁 下面这个是user1代码块 # -*- coding: utf-8 -*- # user1 import pymy ...

  8. 如何修改3D模型的原子属性

    Chem3D是专门用于绘制化学三维模型和进行计算化学数据的ChemOffice组件,在三维模型中每个原子都有众多属性,比如原子类型.原子符号.原子编号以及原子颜色等等.掌握Chem 3D模型的原子属性 ...

  9. 白鹭引擎用java_白鹭引擎发布 5.1.6 版 优化打包 iOS Android App 的运行性能

    原标题:白鹭引擎发布 5.1.6 版 优化打包 iOS Android App 的运行性能 在3月12日,我们将为白鹭引擎推出5.1.6 版本.5.1.6版本是对去年12月份发布的5.1版本的一次功能 ...

  10. java synchronized加锁 或者redis锁不起作用

    前几天在代码中需要加锁 使用了synchronized 以及redis锁均一直不起作用 , 寻找几天后发现是因为在Controller层加了@Transactional(rollbackFor = E ...

最新文章

  1. 计算机音乐戏子多秋,抖音戏子多秋是什么歌
  2. 河科大c语言上机实验答案,2016年河南科技学院信息工程学院C语言上机编程考研复试题库...
  3. LSTM模型在问答系统中的应用
  4. 通过流程构建组织的【个人能力】和【团队能力】
  5. maven笔记(2)-- 构建Java Project 及 Maven命令使用
  6. 持久化保存iptables规则
  7. 下岗工人到达退休年龄,养老保险未缴纳满15年,补缴合适吗?
  8. 【NLPCC 2020】Call for Participation: Shared Tasks in NLPCC 2020
  9. vesamenu.c32:not a COM32R image报错解决方案
  10. 年底将至 怎么向国外客户开口催单 附话术模板
  11. Kindle Paperwhite2测评剧本.
  12. mysql添加用户并赋予权限命令
  13. 堆米微信H5页面怎么制作?易企秀微信H5页面制作,微信简历制作,
  14. 深入了解机器学习(Descending into ML):线性回归
  15. 边缘计算的下一场革命:1+12?
  16. python车辆定位调度管理系统,基于django+twisted
  17. 第三方推送服务:个推服务推送流程
  18. vue3图片描点标记
  19. 【Java基础1】Java开发工具包JDK
  20. Axure 团队原型创建

热门文章

  1. TXT阅读神器 分分钟打造一本电子书
  2. 代码对比工具Sublime——Sublimerge
  3. Java Web实战详细教程(一)系列介绍+环境搭建
  4. 计算机上安装了更新ie版本,安装ie浏览器提示系统有更新的版本怎么办_ie提示有更新版本的解决方法...
  5. 使用java,求100以内的质数(素数)
  6. vmware workstation 12 密钥
  7. sklearn做文本聚类分析
  8. SosoApi,编辑Swagger UI的神器
  9. spring常用注解使用讲解
  10. 百战学堂python教学文档_尚学堂百战程序员:python对文件的操作