本篇文章是给一些常用和不常用的锁进行单线程跑分,常用的锁有信号量dispatch_semaphore和@synchronized同步锁。跑分的代码来自ibireme。这里记录一下我看代码的过程以及它如何计算跑分的。
如何计算跑分的? 通过记录循环开始和循环结束的时间,然后利用结束时间减去开始时间获取耗时,耗时越少的性能越好,其中循环体是加解锁代码。
部分代码
// 锁名称枚举
typedef NS_ENUM(NSUInteger, LockType) {
LockTypeOSSpinLock = 0,
LockTypedispatch_semaphore,
LockTypepthread_mutex,
LockTypeNSCondition,
LockTypeNSLock,
LockTypepthread_mutex_recursive,
LockTypeNSRecursiveLock,
LockTypeNSConditionLock,
LockTypesynchronized,
LockTypeCount,
};
NSTimeInterval TimeCosts[LockTypeCount] = {0}; // c 语言的数组
int TimeCount = 0;
其中一个锁的跑分代码
{
OSSpinLock lock = OS_SPINLOCK_INIT;
begin = CACurrentMediaTime();// 开机后设备一共运行了(设备休眠不统计在内)多少秒
NSLog(@"begin : %f s", begin);
for (int i = 0; i < count; i++) {
OSSpinLockLock(&lock);
OSSpinLockUnlock(&lock);
}
end = CACurrentMediaTime();
NSLog(@"end : %f s", end);
TimeCosts[LockTypeOSSpinLock] += end - begin;
printf("OSSpinLock: %8.2f ms\n", (end - begin) * 1000);
// %8.2f\n 输出格式,按 float 定点格式,数据占8位(包括符号,小数点),小数部分两位。
// 1 秒等于 1000 毫秒
}
我看代码遇到的问题
- 第一行代码就蒙了,
NSTimeInterval TimeCosts[LockTypeCount] = {0};,好吧,这是一个 c 语言数组。博客签名得改名字了。 CACurrentMediaTime();是开机后设备一共运行了(设备休眠不统计在内)多少秒TimeCosts[LockTypeOSSpinLock] += end - begin;先算end - begin- %8.2f\n 输出格式,按 float 定点格式,数据占8位(包括符号,小数点),小数部分两位。
- 1 秒等于 1000 毫秒
结论
跑分打印结果,循环1千次
OSSpinLock: 0.30 ms
dispatch_semaphore: 0.04 ms
pthread_mutex: 0.04 ms
NSCondition: 0.02 ms
NSLock: 0.03 ms
pthread_mutex(recursive): 0.04 ms
NSRecursiveLock: 0.08 ms
NSConditionLock: 0.08 ms
@synchronized: 0.13 ms
---- fin (1000) ----
循环1千万次
OSSpinLock: 80.53 ms
dispatch_semaphore: 138.04 ms
pthread_mutex: 194.33 ms
NSCondition: 195.77 ms
NSLock: 200.37 ms
pthread_mutex(recursive): 312.55 ms
NSRecursiveLock: 399.90 ms
NSConditionLock: 630.98 ms
@synchronized: 1009.31 ms
---- fin (10000000) ----
- 循环次数越多
OSSpinLock性能越好 - 性能排行榜:OSSpinLock > dispatch_semaphore > pthread_mutex > NSCondition > NSLock > pthread_mutex(recursive) > NSRecursiveLock > NSConditionLock > @synchronized 。同步锁垫底了。
OSSpinLock会出行优先级反转问题。OSSpinLock 是自旋锁(忙等),如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放。- 还是用信号量吧