@interface ViewController ()
@property (nonatomic, strong) NSString *someString;
@end
@implementation ViewController
@synthesize someString = _someString;
- (NSString *)someString {
__block NSString *tmp;
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
tmp = _someString;
});
return tmp;
}
- (void)setSomeString:(NSString *)someString {
__block NSString *tmp;
dispatch_barrier_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
tmp = someString;
});
_someString = tmp;
}
@end
有人说这比@synchronized
因为所有的锁定都是在 GCD 中处理的。
首先,您的设置器根本没有任何意义,并且使用默认并发队列也可能不是您想要的。您的代码可能应该看起来更像:
@interface ViewController ()
@property (nonatomic, copy) NSString *someString;
@end
@implementation ViewController
{
dispatch_queue_t _stateGuardQueue;
}
- (instancetype)init
{
if (self = [super init])
{
_stateGuardQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
@synthesize someString = _someString;
- (NSString *)someString {
__block NSString *tmp;
dispatch_sync(_stateGuardQueue, ^{
tmp = _someString;
});
return tmp;
}
- (void)setSomeString:(NSString *)someString {
NSString* tmp = [someString copy];
dispatch_barrier_async(_stateGuardQueue, ^{
_someString = tmp;
});
}
@end
我所做的改变:
- 让 setter 实际上在关键部分内进行突变
- 使用私有的、每个实例的并发队列,而不是全局默认的并发队列;将屏障块提交到默认并发队列不会执行您认为的操作。 (参见docs https://developer.apple.com/library/prerelease/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/c/func/dispatch_barrier_sync)
- Change
dispatch_barrier_sync
to dispatch_barrier_async
同步等待 setter 块返回是没有意义的,因为没有办法在当前线程上获取过时的读取。
- 将属性更改为具有
copy
语义,这始终是值语义类型的良好实践(NSString
等)这在可能从多个线程同时读取属性的情况下尤其重要。
要知道的是,孤立地看,这种模式并不提供比原子属性更多的“安全性”,因此您应该只使用这些属性(更少的代码等)。至于性能问题,是的,对于这种特殊用途,GCD 肯定会优于@synchronized
。其一,它允许并发读取,其中@synchronized
将串行化并发读取。如果不进行测试,我预计原子属性的性能会优于两者。也就是说,原子属性以及一般以这种方式保护单个操作是rarely足够的并发策略。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)