• GCD常用知识


    GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。

    一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。

    GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行。

    dispatch queue分为下面三种:

    Serial
    又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。

    Concurrent
    又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。

    Main dispatch queue
    它是全局可用的serial queue,它是在应用程序主线程上执行任务的。

    用GCD实现这个流程的操作比前面介绍的NSThread NSOperation的方法都要简单。代码框架结构如下:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   
        // 耗时的操作   
        dispatch_async(dispatch_get_main_queue(), ^{   
            // 更新界面   
        });   
    });

    下载图片的例子

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   
        NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];   
        NSData * data = [[NSData alloc]initWithContentsOfURL:url];   
        UIImage *image = [[UIImage alloc]initWithData:data];   
        if (data != nil) {   
            dispatch_async(dispatch_get_main_queue(), ^{   
                self.imageView.image = image;   
             });   
        }   
    });

    系统给每一个应用程序提供了三个concurrent dispatch queues。这三个并发调度队列是全局的,它们只有优先级的不同。因为是全局的,我们不需要去创建。我们只需要通过使用函数dispath_get_global_queue去得到队列,如下:

    dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    2、dispatch_group_async的使用
    dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);   
    dispatch_group_t group = dispatch_group_create();   
    dispatch_group_async(group, queue, ^{   
        [NSThread sleepForTimeInterval:1];   
        NSLog(@"group1");   
    });   
    dispatch_group_async(group, queue, ^{   
        [NSThread sleepForTimeInterval:2];   
        NSLog(@"group2");   
    });   
    dispatch_group_async(group, queue, ^{   
        [NSThread sleepForTimeInterval:3];   
        NSLog(@"group3");   
    });   
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{   
        NSLog(@"updateUi");   
    });   
    dispatch_release(group);

    dispatch_group_async是异步的方法,运行后可以看到打印结果:
    2012-09-25 16:04:16.737 gcdTest[43328:11303] group1
    2012-09-25 16:04:17.738 gcdTest[43328:12a1b] group2
    2012-09-25 16:04:18.738 gcdTest[43328:13003] group3
    2012-09-25 16:04:18.739 gcdTest[43328:f803] updateUi

    3、dispatch_barrier_async的使用
    dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

    dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);   
    dispatch_async(queue, ^{   
        [NSThread sleepForTimeInterval:2];   
        NSLog(@"dispatch_async1");   
    });   
    dispatch_async(queue, ^{   
        [NSThread sleepForTimeInterval:4];   
        NSLog(@"dispatch_async2");   
    });   
    dispatch_barrier_async(queue, ^{   
        NSLog(@"dispatch_barrier_async");   
        [NSThread sleepForTimeInterval:4];   
     
    });   
    dispatch_async(queue, ^{   
        [NSThread sleepForTimeInterval:1];   
        NSLog(@"dispatch_async3");   
    });

    打印结果:

    2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1
    2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2
    2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async
    2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3

    4、dispatch_apply 
    执行某个代码片段N次。

    dispatch_apply(5, globalQ, ^(size_t index) { 
        // 执行5次 
    });

    转自: http://blog.jobbole.com/69019/

    //  后台执行:
     dispatch_async(dispatch_get_global_queue(0, 0), ^{
          // something
     });
    
     // 主线程执行:
     dispatch_async(dispatch_get_main_queue(), ^{
          // something
     });
    
     // 一次性执行:
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         // code to be executed once
     });
    
     // 延迟2秒执行:
     double delayInSeconds = 2.0;
     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
     dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
         // code to be executed on the main queue after delay
     });
    
     // 自定义dispatch_queue_t
     dispatch_queue_t urls_queue = dispatch_queue_create("blog.devtang.com", NULL);
     dispatch_async(urls_queue, ^{  
       // your code 
     });
     dispatch_release(urls_queue);
    
     // 合并汇总结果
     dispatch_group_t group = dispatch_group_create();
     dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
          // 并行执行的线程一
     });
     dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
          // 并行执行的线程二
     });
     dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
          // 汇总结果
     });

     扩展阅读:

    http://blog.csdn.net/justinjing0612/article/details/45539911

    dispatch_group_t group = dispatch_group_create();
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i = 0; i < 100; i++)
    {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            dispatch_group_async(group, queue, ^{
            NSLog(@"%i",i);
            sleep(2);
            dispatch_semaphore_signal(semaphore);
        });
    }
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_release(group);
    dispatch_release(semaphore);

    简单的介绍一下这一段代码,创建了一个初使值为10的semaphore,每一次for循环都会创建一个新的线程,线程结束的时候会发送一个信号,线程创建之前会信号等待,所以当同时创建了10个线程之后,for循环就会阻塞,等待有线程结束之后会增加一个信号才继续执行,如此就形成了对并发的控制,如上就是一个并发数为10的一个线程队列。
    我已经根据GCD,封装了一个简单的THOperationQueue,作为THWebService框架中的一个功能,关于THWebService请参见本小站另一文章:
    轻量级的网络访问管理类THWebService

    转自:http://www.cocoachina.com/bbs/read.php?tid=286536

  • 相关阅读:
    转载:SSH无法连接error:couldnotloadhostkey:/etc/ssh/ssh_host_dsa_key
    docker修改运行中的容器端口映射
    查看iis进程(w3wp)所对应的程序池名称 / 端口使用情况
    jenkins+sonar+钉钉 发布.net
    windows使用jenkins 搭建 .net 自动发布IIS站点平台
    Redis
    20191209---自定义异常类--转载
    借助pywinauto实现本地文件上传--转载
    python虚拟环境搭建,虚拟环境迁移,三方库安装
    python 在不同层级目录import 模块的方法
  • 原文地址:https://www.cnblogs.com/tomblogblog/p/4503866.html
Copyright © 2020-2023  润新知