对于声明为atomic而且又自己手动实现getter或者setter的属性,也可以用barrier来改进:
- @property (atomic, copy) NSString *someString;
-
- - (NSString *)someString {
- __block NSString *tempString;
- dispatch_sync(_syncQueue, ^{
- tempString = _someString;
- });
- return tempString;
- }
-
- - (void)setSomeString :(NSString *)someString {
- dispatch_barrier_async(_syncQueue, ^{
- _someString = someString
- ...
- }
- }
在做到atomic的同时,getter之间还可以并发执行,比直接把setter和getter都放到串行队列或者加普通锁要更高效。
读者写者锁能提升多少效率?
使用读者写者锁一定比所有读写都加锁以及使用串行队列要快,但是到底能快多少呢?Dmytro Anokhin在[3]中做了实验对比,测出了分别使用NSLock、GCD barrier和pthread_rwlock时获取锁所需要的平均时间,实验样本数在100到1000之间,去掉最高和最低的10%,结果如下列图表所示:

3 writers / 10 readers

1 writer / 10 readers

5 writers / 5 readers

10 writers / 1 reader
分析可知:
- 使用读者写者锁(GCD barrier、pthread_rwlock),相比单纯使用普通锁(NSLock),效率有显著提升;
- 读者数量越多,写者数量越少,使用读者写者锁的效率优势越明显;
- 使用GCD barrier和使用pthread_rwlock的效率差异不大。
由于pthread_rwlock不易使用且容易出错,而且GCD barrier和pthread_rwlock对比性能相当,建议使用GCD barrier来解决iOS开发中遇到的读者写者问题。另外,使用GCD还有个潜在优势:GCD面向队列而非线程,dispatch至某一队列的任务,可能在任一线程上执行,这些对开发者是透明的,这样设计的好处显而易见,GCD可以根据实际情况从自己管理的线程池中挑选出开销最小的线程来执行任务,最大程度减小context切换次数。

何时使用读者写者锁
需要注意的是,并非所有的多线程读写场景都一定是读者写者问题,使用时要注意辨别。例如以下YYCache的代码:
- //读cache
- - (id)objectForKey:(id)key {
- if (!key) return nil;
- pthread_mutex_lock(&_lock);
- _YYLinkedMapNode *node = CFDictionaryGetValue(_lru->_dic, (__bridge const void *)(key));
- if (node) {
- node->_time = CACurrentMediaTime();
- [_lru bringNodeToHead:node];
- }
- pthread_mutex_unlock(&_lock);
- return node ? node->_value : nil;
- }
- //写cache
- - (void)setObject:(id)object forKey:(id)key withCost:(NSUInteger)cost {
- if (!key) return;
- if (!object) {
- [self removeObjectForKey:key];
- return;
- }
- pthread_mutex_lock(&_lock);
- _YYLinkedMapNode *node = CFDictionaryGetValue(_lru->_dic, (__bridge const void *)(key));
- NSTimeInterval now = CACurrentMediaTime();
- if (node) {
- _lru->_totalCost -= node->_cost;
- _lru->_totalCost += cost;
- node->_cost = cost;
- node->_time = now;
- node->_value = object;
- [_lru bringNodeToHead:node];
- } else {
- node = [_YYLinkedMapNode new];
- node->_cost = cost;
- node->_time = now;
- node->_key = key;
- node->_value = object;
- [_lru insertNodeAtHead:node];
- }
- if (_lru->_totalCost > _costLimit) {
- dispatch_async(_queue, ^{
- [self trimToCost:_costLimit];
- });
- }
- if (_lru->_totalCount > _countLimit) {
- _YYLinkedMapNode *node = [_lru removeTailNode];
- if (_lru->_releaseAsynchronously) {
- dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
- dispatch_async(queue, ^{
- [node class]; //hold and release in queue
- });
- } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [node class]; //hold and release in queue
- });
- }
- }
- pthread_mutex_unlock(&_lock);
- }
(编辑:PHP编程网 - 黄冈站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|