美文网首页
AFNetworking 中 GCD 的使用(4)

AFNetworking 中 GCD 的使用(4)

作者: 老猫_2017 | 来源:发表于2020-01-15 13:51 被阅读0次

    GCD in AFNetworking 的使用

    AFAutoPurgingImageCache 处理图片缓存

    1. 创建并发队列
    - (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity {
        if (self = [super init]) {
            ...
            NSString *queueName = [NSString stringWithFormat:@"com.alamofire.autopurgingimagecache-%@", [[NSUUID UUID] UUIDString]];
            self.synchronizationQueue = dispatch_queue_create([queueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);
                    ...
    
        }
        return self;
    }
    
    1. 并发读操作, 此处只是并发读,同步在当前操作线程
    - (UInt64)memoryUsage {
        __block UInt64 result = 0;
        dispatch_sync(self.synchronizationQueue, ^{
            result = self.currentMemoryUsage;
        });
        return result;
    }
    
    // dispatch_sync 在此处时同步等待block 执行完毕
    - (nullable UIImage *)imageWithIdentifier:(NSString *)identifier {
        __block UIImage *image = nil;
        dispatch_sync(self.synchronizationQueue, ^{
            AFCachedImage *cachedImage = self.cachedImages[identifier];
            image = [cachedImage accessImage];
        });
        return image;
    }
    
    1. 异步并行屏障写操作,保证,写时操作唯一,
    - (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier {
        dispatch_barrier_async(self.synchronizationQueue, ^{
            // 更新访问时间 如果已存在
            AFCachedImage *cacheImage = [[AFCachedImage alloc] initWithImage:image identifier:identifier];
    
            AFCachedImage *previousCachedImage = self.cachedImages[identifier];
            if (previousCachedImage != nil) {
                self.currentMemoryUsage -= previousCachedImage.totalBytes;
            }
    
            self.cachedImages[identifier] = cacheImage;
            self.currentMemoryUsage += cacheImage.totalBytes;
        });
    
        dispatch_barrier_async(self.synchronizationQueue, ^{
          // 如果满容量,清理
            if (self.currentMemoryUsage > self.memoryCapacity) {
                UInt64 bytesToPurge = self.currentMemoryUsage - self.preferredMemoryUsageAfterPurge;
                NSMutableArray <AFCachedImage*> *sortedImages = [NSMutableArray arrayWithArray:self.cachedImages.allValues];
                NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastAccessDate"
                                                                               ascending:YES];
                [sortedImages sortUsingDescriptors:@[sortDescriptor]];
    
                UInt64 bytesPurged = 0;
    
                for (AFCachedImage *cachedImage in sortedImages) {
                    [self.cachedImages removeObjectForKey:cachedImage.identifier];
                    bytesPurged += cachedImage.totalBytes;
                    if (bytesPurged >= bytesToPurge) {
                        break;
                    }
                }
                self.currentMemoryUsage -= bytesPurged;
            }
        });
    }
    
    
    
    1. 同步屏障写操作
    - (BOOL)removeImageWithIdentifier:(NSString *)identifier {
        __block BOOL removed = NO;
        dispatch_barrier_sync(self.synchronizationQueue, ^{
            AFCachedImage *cachedImage = self.cachedImages[identifier];
            if (cachedImage != nil) {
                [self.cachedImages removeObjectForKey:identifier];
                self.currentMemoryUsage -= cachedImage.totalBytes;
                removed = YES;
            }
        });
        return removed;
    }
    
    //dispatch_barrier_sync 的含义,会阻塞并发,之前的已执行完毕,等待我执行完毕,后面在开始其他提交到 queue里的操作
    - (BOOL)removeAllImages {
        __block BOOL removed = NO;
        dispatch_barrier_sync(self.synchronizationQueue, ^{
            if (self.cachedImages.count > 0) {
                [self.cachedImages removeAllObjects];
                self.currentMemoryUsage = 0;
                removed = YES;
            }
        });
        return removed;
    }
    
    
    1. dispatch_barrier_sync` 同步屏障,依然在当前线程,但是保证独一操作。
        dispatch_queue_t concurrentQueue = dispatch_queue_create("current", DISPATCH_QUEUE_CONCURRENT);
        NSLog(@"0 %@", NSThread.currentThread);
        dispatch_async(concurrentQueue, ^{
           NSLog(@"1 %@", NSThread.currentThread);
        });
        
        dispatch_async(concurrentQueue, ^{
            for (int i = 0; i< 10000; i++) {
                ;
            }
            NSLog(@"2 %@", NSThread.currentThread);
        });
        
        dispatch_async(concurrentQueue, ^{
            for (int i = 0; i< 1000; i++) {
                ;
            }
            NSLog(@"3 %@", NSThread.currentThread);
        });
        NSLog(@"4.0 %@", NSThread.currentThread);
    
        dispatch_barrier_sync(concurrentQueue, ^{
            NSLog(@"4 %@", NSThread.currentThread);
        });
        
        NSLog(@"4.1 %@", NSThread.currentThread);
    
        dispatch_async(concurrentQueue, ^{
            for (int i = 0; i< 100000; i++) {
                ;
            }
            NSLog(@"5 %@", NSThread.currentThread);
        });
        
        dispatch_async(concurrentQueue, ^{
            for (int i = 0; i< 10; i++) {
                ;
            }
            NSLog(@"6 %@", NSThread.currentThread);
        });
        
        dispatch_async(concurrentQueue, ^{
            NSLog(@"7 %@", NSThread.currentThread);
        });
        
        dispatch_barrier_async(concurrentQueue, ^{
            NSLog(@"8 %@", NSThread.currentThread);
        });
        
        NSLog(@"9 %@", NSThread.currentThread);
    
    // 输出如下,不能保证每次都如下,
    2020-01-15 13:29:51.449188+0800 QueueDemo[66791:2112131] 0 <NSThread: 0x600000426240>{number = 1, name = main}
    2020-01-15 13:29:51.449729+0800 QueueDemo[66791:2112131] 4.0 <NSThread: 0x600000426240>{number = 1, name = main}
    2020-01-15 13:29:51.449750+0800 QueueDemo[66791:2112204] 2 <NSThread: 0x600000441080>{number = 4, name = (null)}
    2020-01-15 13:29:51.449773+0800 QueueDemo[66791:2112206] 1 <NSThread: 0x60000046cd40>{number = 3, name = (null)}
    2020-01-15 13:29:51.449815+0800 QueueDemo[66791:2112205] 3 <NSThread: 0x60000046eec0>{number = 5, name = (null)}
    2020-01-15 13:29:51.451601+0800 QueueDemo[66791:2112131] 4 <NSThread: 0x600000426240>{number = 1, name = main}
    2020-01-15 13:29:51.451799+0800 QueueDemo[66791:2112131] 4.1 <NSThread: 0x600000426240>{number = 1, name = main}
    2020-01-15 13:29:51.452183+0800 QueueDemo[66791:2112131] 9 <NSThread: 0x600000426240>{number = 1, name = main}
    2020-01-15 13:29:51.452277+0800 QueueDemo[66791:2112203] 7 <NSThread: 0x6000004646c0>{number = 6, name = (null)}
    2020-01-15 13:29:51.452347+0800 QueueDemo[66791:2112206] 6 <NSThread: 0x60000046cd40>{number = 3, name = (null)}
    2020-01-15 13:29:51.452456+0800 QueueDemo[66791:2112205] 5 <NSThread: 0x60000046eec0>{number = 5, name = (null)}
    2020-01-15 13:29:51.453771+0800 QueueDemo[66791:2112205] 8 <NSThread: 0x60000046eec0>{number = 5, name = (null)}
    
    

    总结:

    1. dispatch_sync vs dispatch_barrier_sync 都会同步等待当前线程执行完毕 block,dispatch_barrier_sync 支持单一路径,之前的完毕,之后的要等它执行完毕之后,才能开始
    2. dispatch_sync 只是同步执行,多读
    3. dispatch_barrier_sync 的多读性能要稍微差一点,阻塞多并发
    4. dispatch_barrier_async的也一样,写时单一执行。阻塞多写操作,同时进行。
    5. 最后一个示例,可以看出 sync 的同步,都优化保证在当前线程执行。

    相关文章

      网友评论

          本文标题:AFNetworking 中 GCD 的使用(4)

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