美文网首页
GCD下的几种实现同步的方式

GCD下的几种实现同步的方式

作者: 三岁就很乖 | 来源:发表于2016-05-11 22:08 被阅读113次

GCD下的几种实现同步的方式

1.串行队列 2.并行队列 3.分组 4.信号量

今天有一个需求,就是网络请求完,有一个逻辑判断,然后更新界面。而我的网络请求,还有一个返回执行的方法,返回的数据不是在block中。这样我都是先进行网络请求之后的方法,然后才执行网络请求之后的返回方法。这样是错误的。
我的网络请求方法。如下:

解决:把网络请求的返回数据包装在block中,并且网络请求与需要紧跟在网络请求之后执行的方法用GCD实现同步。

实例:网络下载图片并展示在视图上,实现这个需求,可以拆分成两个任务,一个是去网上获取图片,一个是展示在视图上。 这两个任务是有关联的,所以需要同步处理。

下面看这几种方式如何实现:

一、

1.串行队列

1.1GCD相关知识:


(1)GCD下的dispatch_queue队列都是FIFO队列,都会按照提交到队列的顺序执行.
 
只是根据队列的性质,分为<1>串行队列:用户队列、主线程队列 <2>并行队列. 
 
(2)同步(dispatch_sync)、异步方式(dispatch_async). 配合串行队列和并行队列使用.

1.2
(1).并行队列

采用并行队列的时候,可以采用同步的方式把任务提交到队列里面去,即可以实现同步的方式。


//新建一个队列
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //记时
    NSDate *startTime = [NSDate date];
    
    //加入队列
    dispatch_async(concurrentQueue, ^{
        __block UIImage *image = nil;
        
        //1.先去网上下载图片
        dispatch_sync(concurrentQueue, ^{
            NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
            NSURL *url = [NSURL URLWithString:urlAsString];
            
            NSError *downloadError = nil;
            
            NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&downloadError];
            
            if (downloadError == nil && imageData != nil) {
                image = [UIImage imageWithData:imageData];
            }
            else if(downloadError != nil){
                NSLog(@"error happened = %@", downloadError);
            }
            else{
                NSLog(@"No data download");
            }
        });
        
        //2.在主线程展示到界面里
        dispatch_sync(dispatch_get_main_queue(), ^{
            if (image != nil) {
                UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
                [imageView setImage:image];
                
                [imageView setContentMode:UIViewContentModeScaleAspectFit];
                [self.view addSubview:imageView];
                [imageView release];
                
                NSDate *endTime = [NSDate date];
                NSLog(@"并行同步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
            }
            else{
                NSLog(@"image isn't downloaded, nothing to display");
            }
        });
    });


(2).串步队列直接提交两个任务就可以


// 串形队列
    dispatch_queue_t serilQueue = dispatch_queue_create("com.quains.myQueue", 0);
    
    //开始时间
    NSDate *startTime = [NSDate date];
    
    
    __block UIImage *image = nil;
    
    //1.先去网上下载图片
    dispatch_async(serilQueue, ^{
        NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
        NSURL *url = [NSURL URLWithString:urlAsString];
        
        NSError *downloadError = nil;
        
        NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&downloadError];
        
        if (downloadError == nil && imageData != nil) {
            image = [[UIImage imageWithData:imageData] retain];
        }
        else if(downloadError != nil){
            NSLog(@"error happened = %@", downloadError);
        }
        else{
            NSLog(@"No data download");
        }
    });
    
    //2.在主线程展示到界面里
    dispatch_async(serilQueue, ^{
        
        NSLog(@"%@",[NSThread currentThread]);
        
        // 在主线程展示
        dispatch_async(dispatch_get_main_queue(), ^{
        if (image != nil) {
            
            UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
            
            [imageView setImage:image];
            
            [imageView setContentMode:UIViewContentModeScaleAspectFit];
            [self.view addSubview:imageView];
            [imageView release];
            
            NSDate *endTime = [NSDate date];
            NSLog(@"串行异步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
        }
        else{
            NSLog(@"image isn't downloaded, nothing to display");
        }
        });
        
    });
    
    //3.清理
    dispatch_release(serilQueue);
    [image release];

注意:
(1) __block变量分配在栈,retain下,防止被回收.

(2)dispatch要手动create和release.

(3)提交到主线程队列的时候,慎用同步dispatch_sync方法,有可能造成死锁. 因为主线程队列是串行队列,要等队列里的任务一个一个执行.所以提交一个任务到队列,如果用同步方法就会阻塞住主线程,而主线程又要等主线程队列里的任务都执行完才能执行那个刚提交的,所以主线程队列里还有其他的任务的话,但他已经被阻塞住了,没法先完成队列里的其他任务,即,最后一个任务也没机会执行到,于是造成死锁.

(4)提交到串行队列可以用同步方式,也可以用异步方式.


dispatch_group_t group = dispatch_group_create();
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    NSDate *startTime = [NSDate date];
    
    __block UIImage *image = nil;
    
    dispatch_group_async(group, queue, ^{
        
        //1.先去网上下载图片
            NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
            NSURL *url = [NSURL URLWithString:urlAsString];
            
            NSError *downloadError = nil;
            
            NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&downloadError];
            
            if (downloadError == nil && imageData != nil) {
                image = [[UIImage imageWithData:imageData] retain];
            }
            else if(downloadError != nil){
                NSLog(@"error happened = %@", downloadError);
            }
            else{
                NSLog(@"No data download");
            }
        
        });
    
    // 2.等下载好了再在刷新主线程
    dispatch_group_notify(group, queue, ^{
        
        //在主线程展示到界面里
        dispatch_async(dispatch_get_main_queue(), ^{
            if (image != nil) {
                UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
                [imageView setImage:image];
                [image release];
                
                [imageView setContentMode:UIViewContentModeScaleAspectFit];
                [self.view addSubview:imageView];
                [imageView release];
                
                NSDate *endTime = [NSDate date];
                NSLog(@"分组同步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
            }
            else{
                NSLog(@"image isn't downloaded, nothing to display");
            }
        });
        
    });
    
    // 释放掉
    dispatch_release(group);

dispatch_group 也要手动创建和释放.

dispatch_notify()提供了一个知道group什么时候结束的点. 当然也可以使用dispatch_wait()去阻塞。


// 信号量初始化为1
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    NSDate *startTime = [NSDate date];
    
    __block UIImage *image = nil;
    
    
    //1.先去网上下载图片
    dispatch_async(queue, ^{
        
        // wait操作-1
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        // 开始下载
        NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
        NSURL *url = [NSURL URLWithString:urlAsString];
        
        NSError *downloadError = nil;
        
        NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&downloadError];
        
        if (downloadError == nil && imageData != nil) {

            image = [[UIImage imageWithData:imageData] retain];
            //NSLog(@"heap %@", image);
            //NSLog(@"%d",[image retainCount]);
        }
        else if(downloadError != nil){
            NSLog(@"error happened = %@", downloadError);
        }
        else{
            NSLog(@"No data download");
        }

        // signal操作+1
        dispatch_semaphore_signal(semaphore);
    });
    
  
    // 2.等下载好了再在刷新主线程
    dispatch_async(dispatch_get_main_queue(), ^{
        
        // wait操作-1
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        if (image != nil) {
            
            UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
            
            [imageView setImage:image];
            NSLog(@"%d",[image retainCount]);
            [image release];
            
            [imageView setContentMode:UIViewContentModeScaleAspectFit];
            [self.view addSubview:imageView];
            [imageView release];
            
            NSDate *endTime = [NSDate date];
            NSLog(@"信号量同步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
        }
        else{
            NSLog(@"image isn't downloaded, nothing to display");
        }
        
        // signal操作+1
        dispatch_semaphore_signal(semaphore);
    });

dispatch_wait会阻塞线程并且检测信号量的值,直到信号量值大于0才会开始往下执行,同时对信号量执行-1操作。

dispatch_signal则是+1操作。

二、

以上几种方式,都是通过阻塞线程的方式去实现同步。

相关文章

  • GCD下的几种实现同步的方式

    GCD下的几种实现同步的方式 1.串行队列 2.并行队列 3.分组 4.信号量 今天有一个需求,就是网络请求完,有...

  • 多线程

    iOS中的几种多线程GCD1、GCD分为任务和队列,任务(同步,异步)队列(串行,并发),同步串行,同步主队列的情...

  • Java中实现异步转同步的几种方式

    Java中实现异步转同步的几种方式 Android常见的异步转同步的方式是通过Callback + Handler...

  • 关于iOS多线程--这些是你必须知道的

    pthread NSThread GCD1. 同步、异步、并发、串行讲解2. 创建队列的几种方式3. 栅栏函数4...

  • GCD的学习笔记(One)

    并行和并发 GCD简介 GCD的任务 GCD的队列 GCD创建队列或获取队列的方法 任务的执行方式:同步执行(同步...

  • iOS多线程知识点梳理

    iOS多线程实现方式 pthread NSThread (三种方式创建) GCD 同步&异步针对的主体是任务,以t...

  • 搭建IM服务 so easy

    数据同步方式 在Web应用上实现数据同步,有"推"、"拉" 两种思路,具体有以下几种方式: 使用HTTP轮循方式说...

  • iOS 模块分解—「Thread 多线程」

    引导 谈到多线程,想必大家第一反应就是多线程常用的几种实现方式。其中 NSThread、GCD、NSOperati...

  • 57 - 观察者模式实战

    上文中,讲了观察者模式的原理、实现、应用场景,重点介绍了不同应用场景下,几种不同的实现方式,包括:同步阻塞、异步非...

  • Java实现线程同步的几种方式

    为何要使用同步? java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),将会导...

网友评论

      本文标题:GCD下的几种实现同步的方式

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