美文网首页iOS开发技能iOS Developer
多用派发队列 少用同步锁

多用派发队列 少用同步锁

作者: AFWater | 来源:发表于2018-01-28 13:23 被阅读8次

    今天重温了 《Effective Objective-C 2.0》,里面有一个章节 多用派发队列,少用同步锁 以前被忽视了,写出来备份下,以下内容为该章节内容抄录和总结。

    在Objective-C中,如果有多个线程要执行同一份代码,那么有时可能会出问题,这种情况一般有三种办法:

    • 同步块

          @synchronized (self) {
          }
      
    • 使用 NSLock 或 NSRecursiveLock 等锁对象

    • 使用GCD

    相对来说,GCD更加简单而高效。

    举个例子,要保证对某一个属性的线程安全,此时使用GCD有两种做法

    使用串行队列

    _syncqueue = dispatch_queue_create("com.test.gcd", NULL);
    
    - (NSString *)something{
        __block NSString *localSomething = nil;
        dispatch_sync(_syncqueue, ^{
            localSomething = _something;
        });
        return localSomething;
    }
    
    - (void)setSomething:(NSString *)something{
        dispatch_sync(_syncqueue, ^{
            _something = something;
        });
    }
    

    此模式把设置操作和读取操作都放到串行队列里执行,所有对属性的访问就都同步了。

    使用并发队列

    其实,对于属性来说,多个get方法是可以并发执行的,而get方法和set方法之间不能并发执行。而且set方法可以是异步的,因为set方法不需要返回值。

    按照这个思路,把队列改成并发队列,,并使用 dispatch_barrier_async 函数,使 get 方法和 set方法 不并发执行。

    _syncqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    - (NSString *)something{
        __block NSString *localSomething = nil;
        dispatch_sync(_syncqueue, ^{
            localSomething = _something;
        });
        return localSomething;
    }
    
    - (void)setSomething:(NSString *)something{
        dispatch_barrier_async(_syncqueue, ^{
            _something = something;
        });
    }
    

    由于set方法中使用了栅栏块,一旦有写入操作时,就会等所有读取的操作全部执行完才会执行写入操作。

    同时注意set方法 dispatch_barrier_async为异步,因为set方法不需要同步,从调用者的角度来讲使用异步会加快执行速度。但是这么做有一个坏处:执行异步派发时,需要拷贝块,如果拷贝快的时间明显超过执行快的所花的时间,则这种做法比使用同步会更慢,但是如果块要执行的为更繁重的任务,那么可以考虑使用异步。对于本文中的例子,只是简单的set,则不需要使用异步派发。

    不过这个示例还有点问题,因为使用了全局并发队列,可能会阻塞系统的队列,所以最好使用自定义并发队列。

    _syncqueue = dispatch_queue_create("com.test.concurrent", DISPATCH_QUEUE_CONCURRENT);
    
    - (NSString *)something{
        __block NSString *localSomething = nil;
        dispatch_sync(_syncqueue, ^{
            localSomething = _something;
        });
        return localSomething;
    }
    
    - (void)setSomething:(NSString *)something{
        dispatch_barrier_async(_syncqueue, ^{
            _something = something;
        });
    }
    

    相关文章

      网友评论

        本文标题:多用派发队列 少用同步锁

        本文链接:https://www.haomeiwen.com/subject/bbgaaxtx.html