IOS开发 GCD多线程编程技术(一)

一、 概念

         

        GCD技术全称 Grand Central Dispatch 译为中央调度,是一种更简单、更高效的多线程编程解决方案,在mac 10.6雪豹及IOS 4以上版本使用。它能替代NSThread类,在应用程序中完成多线程开发,GCD技术还可以完全解决线程死锁、资源泄露等多线程编程中的复杂问题,实际上GCD技术在多核处理器下有效提高了处理器的多个核心的利用率,而不是提高处理器的单个核心的时钟速度。


二、 为什么用它

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT),^{  
  2.      NSLog(@”这是一个异步执行的代码块”);  
  3. });  

        上面的代码创建了一个新的线程,该线程打印了一句话,^{}中的代码就属于一个block(块)代码,如果用NSThread来实现同样的功能,会相对麻烦不少。好处还不止这些。GCD技术基本上可以完全取代NSThread来进行多线程编程,而且因为它是基于block(块编程)所以使用方便,并且更容易控制线程的中断、挂起、返回,更方便的处理多线程编程中可能遇到的复杂的线程安全问题。同时块编程会让代码看起来更集中,更整洁。GCD技术是在全局层面上由系统统一分配处理器资源的,因此会更充分的利用多核处理器的计算能力,使得代码运行更快。

        GCD技术的核心思想就是队列和"块",“块”是指代码块,如^{....代码}就是一个块,GCD提交“块”到队列,提交到主队列就在主线程中运行,提交到并发线程队列,就是创建新线程执行“块”代码。


三、 GCD的三种队列类型


1、themain queue 主线程队列


提交至mainqueue队列中的任务会在主线程中执行,可以使用dispatch_get_main_queue()获取该队列


2、globalqueues 全局队列


全局队列是并行队列,提交至此队列的任务会被并发执行,提交时可以设置任务的优先级:

#define DISPATCH_QUEUE_PRIORITY_HIGH 2

#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0

#define DISPATCH_QUEUE_PRIORITY_LOW (-2)

#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN


3、用户队列


        除了获取队列,我们还可以创建队列,使用dispatch_queue_create方法来创建队列,这是一个串行队列,用处如下,我们创建了N个并发的线程,但这些线程在处理共享数据的时候有可能造成数据不同步,怎么同步呢,就是把所有处理共享数据的代码块都加入到我们自己创建好的队列中,因为这些代码块在队列中是同步执行,所以就解决了多线程编程中的数据异步的问题了。dispatch_queue_create函数有2个参数,第一个可以输入任意字符串,打印日志所用,第2个还不支持传入NULL就行。


四、提交到队列


        使用 dispatch_async或dispatch_sync 向队列中提交代码块,有2个参数,一个是队列queue,一个是代码块block。dispatch_async与dispatch_sync的区别在于 dispatch_async 会立即返回,不存在阻塞,而dispatch_sync会等待块代码执行完毕才会继续执行下面的代码,也正是因为其阻塞特性,在使用不当时很容易造成死锁。如下面代码


[objc]  view plain copy
  1. dispatch_queue_t myqueue = dispatch_queue_create("com.example.MyQueue"NULL);  
  2. dispatch_sync(myqueue, ^{  
  3.           
  4.     dispatch_sync(myqueue, ^{  
  5.               
  6.     });  
  7.           
  8.  });  

myqueue是同步队列,也就是说先进入的任务会先执行,第一个dispatch_sync提交了一个任务,这个任务就是^{}里面的代码,执行完该任务之后才会执行第2个提交到myqueue中的任务,在第一个任务执行过程中,第二个dispatch_sync提交了第二个任务,这个任务不会执行的,因为myqueue还没有执行完第一个任务呢,而dispatch_sync又是阻塞的,所以第二个dispatch_sync一直等着自己的代码被执行,阻塞在这里,第一个dispatch_sync因为第二个dispatch_sync阻塞而无法完成自己提交到myqueue的任务,死锁就这么形成了。总之在使用dispatch_sync的时候一定要小心,避免出现嵌套提交任务到同一个同步队列中,下面代码示意了何时使用dispatch_sync最为合适。

[objc]  view plain copy
  1. -(void)updateDB:(NSString *) sqlstr{  
  2.       
  3.     dispatch_queue_t myqueue = dispatch_queue_create("com.example.MyQueue"NULL);  
  4.     dispatch_sync(myqueue, ^{  
  5.         //操作数据库  
  6.     });  
  7.       
  8. }  

这是一个数据同步的示例,以往我们使用锁来实现,现在不需要了,我们将操作数据的代码添加到了一个同步队列中,任何线程操作数据的时候都要排队,按顺序来,保证了线程安全,而使用dispatch_sync保证这个过程真正完成后才继续执行其他代码。dispatch_async是非阻塞式的提交队列,使用时不会阻塞当前线程,嵌套使用还可以在线程结束时通知主线程,代码如下。


[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{  
  2.           
  3.          //do something....  
  4.         dispatch_async(dispatch_get_main_queue(), ^{  
  5.                 //通知界面  
  6.         });  
  7.           
  8.  });  


创建线程时提交至dispatch_get_global_queue并行队列,结束时提交至main queue,轻松的完成了线程的回调。内层的dispatch_async也可以用dispatch_sync代替,看需要而定。


五、GCD并行迭代


1、dispatch_apply 可以让迭代并行执行

    int i ;
    for (i = 0; i<100; i++) {
        NSLog(@"索引:%i",i);
    }
    dispatch_queue_t myqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
    dispatch_apply(100, myqueue, ^(size_t index){
        NSLog(@"索引:%zu",index);
    });

      第1段代码,执行100次输出操作,第2段代码完成了相同的功能,不同的是执行方式,for是逐次执行,dispatch_apply是并行,但一次并行多少不能确定,根据系统资源来决定。dispatch_apply使用时有3个参数:迭代次数、异步队列、size_t类型参数的block。因为dispatch_apply是并行执行迭代的,所以无法保证执行顺序。另外使用它也是有开销的,你需要根据实际情况来使用这项技术,因为dispatch queue的开销虽然非常小,但仍然存在,你的循环代码必须拥有足够的工作量,才能忽略掉dispatch queue的这些开销。 另外dispatch_apply在并发执行迭代的过程会一直处于阻塞状态,直到所有迭代均已执行完毕。如果你想让它异步执行,可以利用前面的dispatch_async封装整个迭代。

2、dispatch group 同样可以并行迭代,并且更容易控制细节

除了dispatch_apply,我们还有几个替代方案,在循环中异步执行。

dispatch_queue_t myqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
    int i ;
    for (i = 0; i<100; i++) {
        dispatch_async(myqueue, ^{
            NSLog(@"索引:%i",i);
        });
    }

在循环中使用dispatch_async异步执行本次迭代,在本例中输入字符串实在是用不着这么做,但如果是耗时的操作,优势就很明显了。不过要注意dispatch_async是非阻塞的,不管各线程中的代码块是否执行完毕,for循环在执行了最后一个dispatch_async后就跳出循环了。如果我们需要所有迭代都执行完毕才会执行其他代码的话,这么做显然是不行的。为了更好的控制这些细节,我们可以使用dispatch group。

 dispatch_queue_t myqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
    dispatch_group_t group = dispatch_group_create();
    for(i = 0;i<100;i++){
        dispatch_group_async(group, myqueue, ^{
            NSLog(@"索引:%i",i);
        });
    }
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

dispatch group 通过dispatch_group_create()函数创建,通过dispatch_group_async添加到一个异步队列,很显然这些代码块被添加到异步队列也都在我们创建的那个组中,dispatch_group_async是非阻塞式的,所有迭代都执行完毕后for循环结束,执行dispatch_group_wait函数,这个函数的作用是等待,第一个参数表示要等待的组,第二个参数等待时间,DISPATCH_TIME_FOREVER表示永远等待,直到group中所有的代码块都执行完毕才返回。也可以自己设定时间,规定时间内group内执行完毕返回0,否则非0。dispatch_group_wait函数扮演的角色就是监听所有异步线程的执行状态,帮助我们更好的控制并行迭代的过程。我们还有另外一种方案来代替dispatch_group_wait函数 —— dispatch_group_notify。

    dispatch_queue_t myqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
    dispatch_group_t group = dispatch_group_create();
    for(i = 0;i<100;i++){
        dispatch_group_async(group, myqueue, ^{
            NSLog(@"索引:%i",i);
        });
    }
    dispatch_group_notify(group, myqueue, ^{
        NSLog(@"所有并行迭代都执行完毕");
    });

其他都没变,只是用dispatch_group_notify函数代替了dispatch_group_wait函数,它的作用是再追加一个代码块到并行队列中,并且同样属于group组,这样当属于group组的所有并行代码段都执行完毕后,就会执行它。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
疫情居家办公系统管理系统按照操作主体分为管理员和用户。管理员的功能包括办公设备管理、部门信息管理、字典管理、公告信息管理、请假信息管理、签到信息管理、留言管理、外出报备管理、薪资管理、用户管理、公司资料管理、管理员管理。用户的功能等。该系统采用了MySQL数据库,Java语言,Spring Boot框架等技术进行编程实现。 疫情居家办公系统管理系统可以提高疫情居家办公系统信息管理问题的解决效率,优化疫情居家办公系统信息处理流程,保证疫情居家办公系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理疫情居家办公系统信息,包括外出报备管理,培训管理,签到管理,薪资管理等,可以管理公告。 外出报备管理界面,管理员在外出报备管理界面中可以对界面中显示,可以对外出报备信息的外出报备状态进行查看,可以添加新的外出报备信息等。签到管理界面,管理员在签到管理界面中查看签到种类信息,签到描述信息,新增签到信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值