參考自:http://perpendiculo.us/2009/09/synchronized-nslock-pthread-osspinlock-showdown-done-right/,尊重原創!html
蘋果多線程 鎖的文檔 https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.htmlios
常見的幾種鎖有: synchronized 、 NSLock、 pthread_mutex 、OSSpinLock多線程
另外還有:NSRecursiveLock、NSConditionLock、NSDistributedLock 等app
1、用法以下:less
1 /* 2 功能:一個售票程序 3 後臺共有票數,窗口數 4 5 結構:窗口之間並行 每一個窗口內部串行 6 */ 7 #import "SaleViewController.h" 8 #import "pthread/pthread.h" 9 #import "libkern/OSAtomic.h" 10 11 12 @interface SaleViewController () 13 { 14 long long _ticketsCount; 15 int salesGirls; 16 NSLock *_myLock; 17 OSSpinLock _spinLock; 18 } 19 @end 20 21 static pthread_mutex_t sDefaultMutex = PTHREAD_MUTEX_INITIALIZER; 22 23 @implementation SaleViewController 24 25 - (id)init 26 { 27 if(self = [super init]){ 28 _ticketsCount = 30; 29 salesGirls = 6; 30 _myLock = [NSLock new]; 31 _spinLock = OS_SPINLOCK_INIT; 32 } 33 return self; 34 } 35 36 - (void)viewDidLoad { 37 [super viewDidLoad]; 38 UIButton *testConcurrentButton = [[UIButton alloc]initWithFrame:CGRectMake(10, 70, 145, 30)]; 39 [testConcurrentButton setTitle:@"開始售票" forState:UIControlStateNormal]; 40 [testConcurrentButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 41 testConcurrentButton.backgroundColor = [UIColor yellowColor]; 42 [testConcurrentButton addTarget:self action:@selector(startSale) forControlEvents:UIControlEventTouchUpInside]; 43 [self.view addSubview:testConcurrentButton]; 44 } 45 46 - (void)didReceiveMemoryWarning { 47 [super didReceiveMemoryWarning]; 48 } 49 50 //一個窗口售票 51 - (void)saleATicket:(const char *)cStr atWindow:(int)w 52 { 53 dispatch_queue_t queue = dispatch_queue_create(cStr, DISPATCH_QUEUE_CONCURRENT); 54 dispatch_async(queue, ^{ 55 while (_ticketsCount > 0) { 56 57 @synchronized(self) { 58 _ticketsCount -- ; 59 NSLog(@"這次出票成功,還有%lld張餘票,售票處%d",_ticketsCount,w); 60 } 61 62 // [_myLock lock]; 63 // _ticketsCount -- ; 64 // NSLog(@"這次出票成功,還有%lld張餘票,售票處%d",_ticketsCount,w); 65 // [_myLock unlock]; 66 // 67 // pthread_mutex_lock(&sDefaultMutex); 68 // _ticketsCount -- ; 69 // NSLog(@"這次出票成功,還有%lld張餘票,售票處%d",_ticketsCount,w); 70 // pthread_mutex_unlock(&sDefaultMutex); 71 // 72 // OSSpinLockLock(&_spinLock); 73 // _ticketsCount -- ; 74 // NSLog(@"這次出票成功,還有%lld張餘票,售票處%d",_ticketsCount,w); 75 // OSSpinLockUnlock(&_spinLock); 76 77 //下一個顧客,暫停500ms 78 sleep(2); 79 } 80 81 if (_ticketsCount <= 0) { 82 NSLog(@"票已售完"); 83 } 84 }); 85 } 86 87 - (void)startSale 88 { 89 90 for (int i = 0; i < salesGirls; i++) { 91 NSString *str = [NSString stringWithFormat:@"com.sale.%d%d",i,i]; 92 [self saleATicket:[str UTF8String] atWindow:i]; 93 } 94 } 95 @end
2、性能測試:async
1 -(void)testPerformance 2 { 3 CFAbsoluteTime startTime,endTime; 4 int i = 0; 5 6 startTime = CFAbsoluteTimeGetCurrent(); 7 for (i = 0 ; i < RUNCOUNT; i++) { 8 @synchronized(self) { 9 10 } 11 } 12 endTime = CFAbsoluteTimeGetCurrent(); 13 NSLog(@"totalTime synchronized = %f sec", endTime - startTime); 14 15 16 NSLock *myL = [NSLock new]; 17 startTime = CFAbsoluteTimeGetCurrent(); 18 for(i= 0;i <RUNCOUNT ;i++){ 19 [myL lock]; 20 [myL unlock]; 21 } 22 endTime = CFAbsoluteTimeGetCurrent(); 23 NSLog(@"totalTime NSLock = %f sec", endTime - startTime); 24 25 26 startTime = CFAbsoluteTimeGetCurrent(); 27 for(i= 0;i <RUNCOUNT ;i++){ 28 pthread_mutex_lock(&sDefaultMutex); 29 pthread_mutex_unlock(&sDefaultMutex); 30 } 31 endTime = CFAbsoluteTimeGetCurrent(); 32 NSLog(@"totalTime pthread = %f sec", endTime - startTime); 33 34 35 startTime = CFAbsoluteTimeGetCurrent(); 36 for(i= 0;i <RUNCOUNT ;i++){ 37 OSSpinLockLock(&_spinLock); 38 OSSpinLockUnlock(&_spinLock); 39 } 40 endTime = CFAbsoluteTimeGetCurrent(); 41 NSLog(@"totalTime OSSpinLock = %f sec", endTime - startTime); 42 }
執行1024*1024*1024次空鎖的時間是:ide
執行1024*1024*32次空鎖的時間是:性能
能夠看出,幾種鎖性能相差較大,性能 OSSpinLock > pthread > NSLock >synchronized 測試
3、性能分析ui
爲何幾種鎖的性能有如此明顯的差別,它們的實現方式有何差異?
So, what makes @sychronized and SpinLock so different from the others?
@synchronized is very heavy weight because it has to set up an exception handler, and it actually ends up taking a few internal locks on its way there. So instead of a simple cheap lock, you’re paying for a couple locks/unlocks just to acquire your measly lock. Those take time.
OSSpinLock, on the other hand, doesn’t even enter the kernel — it just keeps reloading the lock, hoping that it’s unlocked. This is terribly inefficient if locks are held for more than a few nanoseconds, but it saves a costly system call and a couple context switches. Pthread mutexes actually use an OSSpinLock first, to keep things running smoothly where there’s no contention. When there is, it resorts to heavier, kernel-level locking/tasking stuff.
So, if you’ve got hotly-contested locks, OSSpinLock probably isn’t for you (unless your critical sections are _Really_ _Fast_). Pthread mutexes are a tiny bit more expensive, but they avoid the power-wasting effects of OSSpinLock.
NSLock is a pretty wrapper on pthread mutexes. They don’t provide much else, so there’s not much point in using them over pthread mutexes.
Of course, standard optimization disclaimers apply: don’t do it until you’re sure you’ve chosen the correct algorithms, have profiled to find hotspots, and have found locking to be one of those hot items. Otherwise, you’re wasting your time on something that’s likely to provide minimal benefits.