我在争论是否要转向基于GCD的多线程访问器模式。我多年来一直在访问器中使用基于锁的自定义同步,但我发现了一些信息(Intro to GCD),并且似乎有基于GCD的方法的优点。我希望在这里开始一个对话,以帮助自己和其他人权衡决定。
模式如下:
- (id)something
{
__block id localSomething;
dispatch_sync(queue, ^{
localSomething = [something retain];
});
return [localSomething autorelease];
}
- (void)setSomething:(id)newSomething
{
dispatch_async(queue, ^{
if(newSomething != something)
{
[something release];
something = [newSomething retain];
[self updateSomethingCaches];
}
});
}
在专业方面:您可能获得非阻塞写访问的好处;比锁更低的开销(可能?);从关键代码部分返回之前忘记解锁的安全性;其他
缺点:异常处理不存在,因此您必须将其编码到您可能需要它的每个块中。
这种模式是否可能是编写多线程访问器的推荐方法?
是否有为此目的创建调度队列的标准方法?换句话说,用于权衡粒度的最佳实践?例如,使用锁定,锁定每个属性比锁定整个对象更精细。使用调度队列,我可以想象为所有对象创建单个队列会产生性能瓶颈,因此每个对象队列是否合适?显然,答案很大程度上取决于具体的应用,但是有一些已知的性能权衡来帮助衡量该方法的可行性。
任何信息/见解都将受到赞赏。
答案 0 :(得分:8)
这种模式是否可能是推荐的写作方法 多线程访问器?
我猜你写的是一个串行队列,但没有理由。考虑一下:
dispatch_queue_t queue = dispatch_queue_create("com.example", DISPATCH_QUEUE_CONCURRENT);
// same thing as your example
- (NSString*)something {
__block NSString *localSomething;
dispatch_sync(queue, ^{
localSomething = _something;
});
return localSomething;
}
- (void)setSomething:(NSString*)something {
dispatch_barrier_async(queue, ^{
_something = something;
});
}
它同时读取但在发生写入时使用调度屏障来禁用并发。 GCD的一大优势是允许并发读取而不是像@property(atomic)那样锁定整个对象。
从客户端的角度来看,asyncs(dispatch_async,dispatch_barrier_async)都比较快,但执行速度比同步要慢,因为他们必须复制块,并且让块执行这么小的任务,复制所需的时间就变成了有意义的。我宁愿让客户快速回来,所以我很好。