Effective Objective-C 2.0 读书笔记——大中枢派发
多用派发队列,少用同步锁
说到同步锁,我们不难想起我们前面在学习线程之中的内容时学习到的关键字@synchronized,使用这个同步块可以让我们这段程序实现加锁的操作,即在不同线程之中这个关键字的内容只能有一条线程运行。自动创建一个锁,并等待块中的代码执行完毕。执行到这段代码结尾处,锁就释放了。以下是例子
-(void) synchronizedMethod {
@synchronized (self) {
///Safe
}
}
但是滥用@synchronized (self)会很危险,因为所有同步块都会彼此抢夺同一个锁。要是有很多个属性都这么写的话,那么每个属性的同步块都要等其他所有同步块执行完 毕才能执行,这也许并不是开发者想要的效果。我们只是想令每个属性各自独立地同步。
替代方案就是使用 GCD,它能以更简单、更高效的形式为代码加锁。比方说,属性就是开发者经常需要同步的地方,这种属性需要做成“原子的”。
初步代码
有种简单而高效的办法可以代替同步块或锁对象,那就是使用“ 串行同步队列” (serial synchronization queue)。将读取操作及写入操作都安排在同一个队列里,即可保证数据同步。 其用法如下:
// 创建同步队列(通常在初始化方法中创建)
_syncQueue = dispatch_queue_create("com.effectiveobjectivec.syncQueue", NULL);
- (NSString *)someString {
__block NSString *localSomeString;
dispatch_sync(_syncQueue, ^{
localSomeString = _someString;
});
return localSomeString;
}
- (void)setSomeString:(NSString *)someString {
dispatch_sync(_syncQueue, ^{
_someString = someString;
});
}
由于写操作(setter)不需要返回值,所以可以考虑使用 异步派发(dispatch_async) 替代同步派发,这样调用者就不必等待写操作完成,从而可能提升设置方法的执行速度。
异步写入
- (void)setSomeString:(NSString *)someString {
// 异步派发写操作,调用者不会被阻塞
dispatch_async(_syncQueue, ^{
_someString = someString;
});
}
优点:
- 调用者性能提升:因为写操作是异步执行的,调用者立即返回,不需要等待 block 执行完毕。
缺点:
- Block 拷贝开销:dispatch_async 会拷贝 block。如果拷贝 block 的成本超过 block 实际执行的时间,在简单的例子中可能会导致整体性能反而变慢。
- 适用场景:对于比较轻量的操作,异步写可能没有明显优势,但如果 block 内执行的任务较重或耗时,那么异步方式能使得调用者更快返回,提升整体效率。
用栅栏函数再优化
我们先前使用的就是串行队列,我们知道如果我们使用并行队列,那么性能将会更好,但是如果使用并行队列似乎就没办法完成安全读写这个点,于是我们就想起我们之前学习过的栅栏函数,将读写两个操作分开
// 创建一个并发队列,使用 barrier 确保写操作的独占性
_syncQueue = dispatch_queue_create("com.example.syncQueue", DISPATCH_QUEUE_CONCURRENT);
- (NSString *)someString {
__block NSString *localSomeString;
// 使用同步派发保证读取时数据一致
dispatch_sync(_syncQueue, ^{
localSomeString = _someString;
});
return localSomeString

最低0.47元/天 解锁文章
574

被折叠的 条评论
为什么被折叠?



