ios线程安全
来源:互联网 发布:C 释放动态数组内存 编辑:程序博客网 时间:2024/06/16 07:23
在iOS开发中,支持多种同步方法,我们从耗时角度出发,评估各种同步对象的性能。
- @synchronized
- NSLock
- NSCondition
- NSConditionLock
- NSRecursiveLock
- pthread_mutex_t
- OSSpinLock
- dispatch_barrier_async
示例代码如下:
const NSInteger KRunTimes = 1000 *1000;
double curTime, lastTime;
// 1.同步synchronized
id obj = [NSObject new];
lastTime = CFAbsoluteTimeGetCurrent();
for (NSInteger i =0; i < KRunTimes; ++i) {
@synchronized(obj) {
}
}
curTime = CFAbsoluteTimeGetCurrent();
NSLog(@"@synchronized: %f ms", (curTime - lastTime) *1000);
// 2.NSLock
NSLock *myLock = [NSLock new];
lastTime = CFAbsoluteTimeGetCurrent();
for (NSInteger i =0; i < KRunTimes; ++i) {
[myLock lock];
[myLock unlock];
}
curTime = CFAbsoluteTimeGetCurrent();
NSLog(@"NSLock: %f ms", (curTime - lastTime) *1000);
// NSLock IMP
typedefvoid (*func)(id, SEL);
SEL lockSEL = @selector(lock);
SEL unlockSEL = @selector(unlock);
func lockFunc = (void (*)(id, SEL))[myLock methodForSelector : lockSEL];
func unlockFunc = (void (*)(id, SEL))[myLock methodForSelector : unlockSEL];
lastTime = CFAbsoluteTimeGetCurrent();
for (NSInteger i =0; i < KRunTimes; ++i) {
lockFunc(myLock, lockSEL);
unlockFunc(myLock, unlockSEL);
}
curTime = CFAbsoluteTimeGetCurrent();
NSLog(@"NSLock + IMP: %f ms", (curTime - lastTime) *1000);
// 3.NSCondition
NSCondition *condition = [[NSCondition alloc] init];
lastTime = CFAbsoluteTimeGetCurrent();
for (NSInteger i =0; i < KRunTimes; ++i) {
[condition lock];
[condition unlock];
}
curTime = CFAbsoluteTimeGetCurrent();
NSLog(@"NSCondition: %f ms", (curTime - lastTime) *1000);
// 4.NSConditionLock
NSConditionLock *conditionLock = [[NSConditionLock alloc] init];
lastTime = CFAbsoluteTimeGetCurrent();
for (NSInteger i =0; i < KRunTimes; ++i) {
[conditionLock lock];
[conditionLock unlock];
}
curTime = CFAbsoluteTimeGetCurrent();
NSLog(@"NSConditionLock: %f ms", (curTime - lastTime) *1000);
// 5.NSRecursiveLock
NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc] init];
lastTime = CFAbsoluteTimeGetCurrent();
for (NSInteger i =0; i < KRunTimes; ++i) {
[recursiveLock lock];
[recursiveLock unlock];
}
curTime = CFAbsoluteTimeGetCurrent();
NSLog(@"NSRecursiveLock: %f ms", (curTime - lastTime) *1000);
// 6.pthread_mutex_t
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
lastTime = CFAbsoluteTimeGetCurrent();
for (NSInteger i =0; i < KRunTimes; ++i) {
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
}
curTime = CFAbsoluteTimeGetCurrent();
NSLog(@"pthread_mutex: %f ms", (curTime - lastTime) *1000);
pthread_mutex_destroy(&mutex);
// 7.OSSpinLock 自旋锁;
OSSpinLock spinlock = OS_SPINLOCK_INIT;
lastTime = CFAbsoluteTimeGetCurrent();
for (NSInteger i =0; i < KRunTimes; ++i) {
OSSpinLockLock(&spinlock);
OSSpinLockUnlock(&spinlock);
}
curTime = CFAbsoluteTimeGetCurrent();
NSLog(@"OSSpinlock: %f ms", (curTime - lastTime) *1000);
// 8 dispatch_barrier_async
dispatch_queue_t queue =
dispatch_queue_create("com.qq.ksnow", DISPATCH_QUEUE_CONCURRENT);
lastTime = CFAbsoluteTimeGetCurrent();
for (NSInteger i =0; i < KRunTimes; ++i) {
dispatch_barrier_async(queue, ^{});
}
curTime = CFAbsoluteTimeGetCurrent();
NSLog(@"@dispatch_barrier_async: %f ms", (curTime - lastTime) *1000);
一.模拟器/iOS7/XCode6下性能对比
日志情况:
2014-09-0711:26:48.071LockTest[2713:98107] @synchronized:232.551038ms
2014-09-0711:26:48.173LockTest[2713:98107]NSLock:100.879967ms
2014-09-0711:26:48.263LockTest[2713:98107]NSLock + IMP: 89.570999ms
2014-09-0711:26:48.353LockTest[2713:98107]NSCondition:89.850008ms
2014-09-0711:26:48.587LockTest[2713:98107]NSConditionLock:233.431995ms
2014-09-0711:26:48.677LockTest[2713:98107]NSRecursiveLock:89.230001ms
2014-09-0711:26:48.740LockTest[2713:98107]pthread_mutex:62.326968ms
2014-09-0711:26:48.750LockTest[2713:98107]OSSpinlock:10.430992ms
2014-09-0711:26:49.985LockTest[2713:98107]dispatch_barrier_async:1234.429002ms
总结对比
二.iPad Mini2/iOS7/XCode6下性能对比
2014-09-0713:32:47.720LockTest[3494:60b] @synchronized:499.736011ms
2014-09-0713:32:47.948LockTest[3494:60b]NSLock:227.194011ms
2014-09-0713:32:48.170LockTest[3494:60b]NSLock + IMP: 221.384048ms
2014-09-0713:32:48.393LockTest[3494:60b]NSCondition:221.689999ms
2014-09-0713:32:49.030LockTest[3494:60b]NSConditionLock:636.340976ms
2014-09-0713:32:49.260LockTest[3494:60b]NSRecursiveLock:229.423046ms
2014-09-0713:32:49.431LockTest[3494:60b]pthread_mutex:170.615971ms
2014-09-0713:32:49.495LockTest[3494:60b]OSSpinlock:63.916981ms
2014-09-0713:32:49.826LockTest[3494:60b]dispatch_barrier_async:329.769015ms
总结
- 耗时方面:
- OSSpinlock耗时最少;
- pthread_mutex其次。
- NSLock/NSCondition/NSRecursiveLock 耗时接近,220ms上下居中。
- NSConditionLock最差,我们常用synchronized倒数第二。
- dispatch_barrier_async也许,性能并不像我们想象中的那么好.推测与线程同步调度开销有关。单独block耗时在1ms以下基本上可以忽略不计的。
- 在访问次数比较多的情况下,IMP访问耗时要比消息发送略小。 参看NSLock 与NSLock + IMP 对比。
- 为什么不直接使用 IMP 而使用直接声明函数指针的方式? XCode6下IMP不能指定参数,报错如下
- 如何解决呢?修改LLVM预处理设置即可。详情见XCode6下Too many arguments to function call, expected 0, have 2解决办法
原因分析
1.synchronized
会创建一个异常捕获handler和一些内部的锁。所以,使用@synchronized替换普通锁的代价是,你付出更多的时间消耗。
创建给@synchronized指令的对象是一个用来区别保护块的唯一标示符。如果你在两个不同的线程里面执行上述方法,每次在一个线程传递了一个不同的对象给anObj参数,那么每次都将会拥有它的锁,并持续处理,中间不被其他线程阻塞。然而,如果你传递的是同一个对象,那么多个线程中的一个线程会首先获得该锁,而其他线程将会被阻塞直到第一个线程完成它的临界区。
作为一种预防措施,@synchronized块隐式的添加一个异常处理例程来保护代码。该处理例程会在异常抛出的时候自动的释放互斥锁。这意味着为了使用@synchronized指令,你必须在你的代码中启用异常处理。了如果你不想让隐式的异常处理例程带来额外的开销,你应该考虑使用锁的类。
2.NSConditionLock
条件锁,与特定的,用户定义的条件有关。可以确保一个线程可以获取满足一定条件的锁。
内部会涉及到信号量机制,一旦一个线程获得锁后,它可以放弃锁并设置相关条件;其它线程竞争该锁。
线程之间的竞争激烈,涉及到条件锁检测,线程间通信。系统调用,上下切换方切换比较频繁。
3.OSSpinLock
自旋锁几乎不进入内核,仅仅是重新加载自旋锁。
如果自旋锁被占用时间是几十,上百纳秒,性能还是挺高的。减少了代价较高的系统调用和一系列上下文言切换。
但是,该锁不是万能的;如果该锁抢占比较多的时候,不要使用该锁。会占用较多cpu,导致耗电较多。
这种情况下使用pthread_mutex虽然耗时多一点,但是,避免了电量过多的消耗。是不错的选择。
官方描述:
Spin locks are a simple, fast, thread-safe synchronization primitive thatis suitablein situations where contentionis expectedto be low. The spinlock operations use memory barriersto synchronize accesstoshared memoryprotectedby the lock. Preemptionis possiblewhile the lock is held.
4.pthread_mutex
底层的API还是性能比较高啊,在各种同步对象中,性能属于佼佼者。
结论:
- 如果只是粗略的使用锁,不考虑性能问题可以使用synchronized。
- 如果对效率有较高的要求,还是采用OSSpinlock比较好。
- 因为Pthread的锁在也是用 OSSpinlock 实现的。OSSpinlock 的实现过程中,并没有进入系统kernel,使用OSSpinlock可以节省系统调用和上下文切换。
- ios 线程安全
- iOS线程安全数组
- iOS 线程安全
- iOS线程安全
- ios多线程 -- 线程安全
- iOS--线程安全03
- iOS 保证线程安全
- ios线程安全
- iOS Coredata安全之多线程
- iOS多线程之线程安全
- iOS中单例的线程安全
- IOS 多线程(3) --线程安全
- iOS开发多线程-线程安全
- iOS中单例的线程安全
- iOS中单例的线程安全
- iOS线程安全的问题
- iOS --- 线程安全之semaphore
- iOS多线程安全 - 线程同步
- 《scala程序设计》笔记
- ELK介绍安装
- django学习3
- 到底该不该妥协?
- angularjs2 组件的生命周期
- ios线程安全
- Long-term Recurrent Convolutional Networks for Visual Recognition and Description
- 小知识
- 算法训练 未名湖边的烦恼
- AJAX入门学习
- synchronized(this)总结
- Android点击EditText以外区域隐藏键盘Fragment同样适用
- 文件IO编程十二
- oj28. Implement strStr()