关于多线程之GCD的一些学习要点

GCD是当前多线程使用最方便的,也是使用比较多的。

学习GCD主要集中在一下几点:

一、队列,同步,异步

1.主队列:dispatch_get_main_queue();

2.串行队列:dispatch_queue_create("queue", 0);

3.并行队列:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

4.同步,异步就不需要再多说什么。

 

对上面关键词的一些解释:

主队列:主队列只能使用异步来执行队列中的任务,使用同步的话会造成死循环。同时执行任务的时候是在主线程中执行的。

串行队列:(1)、添加到串行队列中的任务是一个接着一个执行的,也就是当上一个任务执行完之后才开始下一个任务;

                        但是可以创建多个串行队列,每个串行队列之间是相互独立的,可以并发执行。

              (2)、如果用同步执行的话就是在当前线程上执行;

              (3)、如果用异步执行的话就是新开辟一个线程执行。

并行队列:(1)、添加到并行队列中的任务可以并发启动,启动顺序仍然是一个接着一个,但是后者可以不等前者执行完就可以开始执行。

                        并行队列也可以创建多个,各个之间也是相互独立,并发执行的。

              (2)、如果用同步执行的话就是在当前线程上执行;

              (3)、如果用异步执行的话就是新开辟一个线程执行。

            

二、经常用到的地方

1.任务执行完毕之后再进行一些操作

2.只执行一次

3.延时操作

 

对上面用处的一些解释:

(1)、任务执行完毕之后再进行一些操作,如果是一些简单的操作可以直接使用串行队列实现。但是一些比较费时的操作就需要用到队列组了。

    //1.创建一个队列组
        dispatch_group_t group = dispatch_group_create();
    
    //2.开启一个任务1
    dispatch_group_async(group, global_quque, ^{
 
    });
    
    //3.开启一个任务2
    dispatch_group_async(group, global_quque, ^{


       });
    
   //4.等group中的所有任务都执行完毕, 再回到主线程执行其他操作
    dispatch_group_notify(group,main_queue, ^{
     });
    

 

(2)、只执行一次

          static dispatch_once_t onceToken;

          dispatch_once(&onceToken, ^{

          // 只执行1次的代码(这里面默认是线程安全的)

});

 

(3)、延时操作

          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

          //延迟执行的方法

    });

 

(4)、暂停和恢复队列中的任务

dispatch_suspend和dispatch_resume

我们知道NSOperationQueue有暂停(suspend)和恢复(resume)。其实GCD中的队列也有类似的功能。用法也非常简单:

dispatch_suspend(queue) //暂停某个队列  

dispatch_resume(queue)  //恢复某个队列  

这些函数不会影响到队列中已经执行的任务,队列暂停后,已经添加到队列中但还没有执行的任务不会执行,直到队列被恢复。

 

(5)、承上启下

dispatch_async(queue, block1_for_reading)  

dispatch_async(queue, block2_for_reading)

 

dispatch_barrier_async(queue, block_for_writing)

 

dispatch_async(queue, block3_for_reading)  

dispatch_async(queue, block4_for_reading)  

dispatch_barrier_async 会把并行队列的运行周期分为这三个过程:

  1. 首先等目前追加到并行队列中所有任务都执行完成
  2. 开始执行 dispatch_barrier_async 中的任务,这时候即使向并行队列提交任务,也不会执行
  3. dispatch_barrier_async 中的任务执行完成后,并行队列恢复正常。

总的来说,dispatch_barrier_async 起到了“承上启下”的作用。它保证此前的任务都先于自己执行,此后的任务也迟于自己执行。正如barrier的含义一样,它起到了一个栅栏、或是分水岭的作用。

这样一来,使用并行队列和 dispatc_barrier_async 方法,就可以高效的进行数据和文件读写了。

 

(6)、信号量

dispatch_semaphore

首先介绍一下信号量(semaphore)的概念。信号量是持有计数的信号,不过这么解释等于没解释。我们举个生活中的例子来看看。

假设有一个房子,它对应进程的概念,房子里的人就对应着线程。一个进程可以包括多个线程。这个房子(进程)有很多资源,比如花园、客厅等,是所有人(线程)共享的。

但是有些地方,比如卧室,最多只有两个人能进去睡觉。怎么办呢,在卧室门口挂上两把钥匙。进去的人(线程)拿着钥匙进去,没有钥匙就不能进去,出来的时候把钥匙放回门口。

这时候,门口的钥匙数量就称为信号量(Semaphore)。很明显,信号量为0时需要等待,信号量不为零时,减去1而且不等待。

在GCD中,创建信号量的语法如下:

var semaphore = dispatch_semaphore_create(2)  

这句代码通过 dispatch_semaphore_create 方法创建一个信号量并设置初始值为 2。然后就可以调用 dispatch_semaphore_wait 方法了。

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)  

dispatch_semaphore_wait 方法表示一直等待直到信号量的值大于等于 1,当这个方法执行后,会把第一个信号量参数的值减 1。

第二个参数是一个 dispatch_time_t 类型的时间,它表示这个方法最大的等待时间。这在第一章中已经讲过,比如 DISPATCH_TIME_FOREVER 表示永久等待。

返回值也和 dispatch_group_wait 方法一样,返回 0 表示在规定的等待时间内第一个参数信号量的值已经大于等于 1,否则表示已超过规定等待时间,但信号量的值还是 0。

dispatch_semaphore_wait 方法返回 0,因为此时的信号量的值大于等于一,任务获得了可以执行的权限。这时候我们就可以安全的执行需要进行排他控制的任务了。

任务结束时还需要调用 dispatch_semaphore_signal() 方法,将信号量的值加 1。这类似于之前所说的,从卧室出来要把锁放回门上,否则后来的人就无法进入了。

我们来看一个完整的例子:

var semaphore = dispatch_semaphore_create(1)  

let queue = dispatch_queue_create("com.gcd.kt", DISPATCH_QUEUE_CONCURRENT)  

var array: [Int] = []

 

for i in 1...100000 {  

    dispatch_async(queue, { () -> Void in

        /*

            某个线程执行到这里,如果信号量值为1,那么wait方法返回1,开始执行接下来的操作。

            与此同时,因为信号量变为0,其它执行到这里的线程都必须等待

        */

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)

 

        /*

            执行了wait方法后,信号量的值变成了0。可以进行接下来的操作。

            这时候其它线程都得等待wait方法返回。

            可以对array修改的线程在任意时刻都只有一个,可以安全的修改array

        */

        array.append(i)

 

        /*

            排他操作执行结束,记得要调用signal方法,把信号量的值加1。

            这样,如果有别的线程在等待wait函数返回,就由最先等待的线程执行。

        */

        dispatch_semaphore_signal(semaphore)

    })

}

 

总结:

1、常用的延时操作:

    (1)    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

          //延迟执行的方法

    });

    (2)   [self performSelector:@selector(test) withObject:nil afterDelay:1.0];

2、回到主线程的操作:

    (1)    dispatch_async(dispatch_get_main_queue(), ^{

               // 回到主线程,执⾏UI刷新操作 });

    (2)    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];

 

转载于:https://www.cnblogs.com/danMing-love/p/5598361.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/418387.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端学习(1980)vue之电商管理系统电商系统之实现文本框和按钮的切换

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

C#基础系列 - 抽象类及其方法的学习

在C#中使用关键字 abstract 来定义抽象类和抽象方法。 不能初始化的类被叫做抽象类,它们只提供部分实现,但是另一个类可以继承它并且能创建它们的实例。 "一个包含一个或多个纯虚函数的类叫抽象类,抽象类不能被实例化,进一步…

前端学习(1977)vue之电商管理系统电商系统之按钮与文本框的切换

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

protobuf 数据解析的2种方法

方法1&#xff1a; message person{required int32 age 1;required int32 userid 2;optional string name 3;} message test{required int32 time 1;required int32 userid 2;required float price 3;optional string desc 4;} 1 #include <string>2 #include <…

前端学习(1978)vue之电商管理系统电商系统之为每一行数据提供单独的value

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

软工学习笔记——代码规范

上大学以来写了这几年的代码&#xff0c;却一直没怎么关注过代码规范相关的问题&#xff0c;直到软工课上讲了之后&#xff0c;才开始有所顾及。上课的时候回头看看自己写过的那些代码&#xff0c;真是丑死了&#xff0c;几个月前自己写的代码现在就已经读不懂了。 看了书上的相…

前端学习(1981)vue之电商管理系统电商系统之完成可选项的添加操作

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

ext4文件系统的delalloc选项造成单次写延迟增加的分析

最近我们的服务进程遇到kill -15后处于Z的状态&#xff0c;变为了僵尸进程&#xff0c;经过/proc/{thread_id}/stack查看其上线程的栈&#xff0c;发现是卡在了fwrite的过程中&#xff0c;而我们的系统中所有文件系统挂载参数都使用了delalloc参数&#xff0c;怀疑是这个原因&a…

前端学习(1982)vue之电商管理系统电商系统之删除参数的操作

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

前端学习(1983)vue之电商管理系统电商系统之清空表格数据

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

python 进程和线程

python中的进程、线程&#xff08;threading、multiprocessing、Queue、subprocess&#xff09; Python中的进程与线程 学习知识&#xff0c;我们不但要知其然&#xff0c;还是知其所以然。你做到了你就比别人NB。 我们先了解一下什么是进程和线程。 进程与线程的历史 我们都知…

NYU Hand Pose Dataset

http://cims.nyu.edu/~tompson/NYU_Hand_Pose_Dataset.htm#overview 转载于:https://www.cnblogs.com/guochen/p/5610681.html

前端学习(1984)vue之电商管理系统电商系统之完成静态属性

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

java实现文件在线预览

RequestMapping("/preview1") public void er(HttpServletResponse response){File file new File("G:\\桌面\\Thymeleaf3.0中文翻译文档www.java1234.com.pdf");if (file.exists()){byte[] data null;try {FileInputStream input new FileInputStream(…

Python 运维(三):使用 zipapp 将 Python 程序打包成单个可执行文件

大家好&#xff0c;我是水滴~~ 在 Python 开发中&#xff0c;我们经常需要将应用程序打包成可执行文件&#xff0c;以便在不具备 Python 环境的计算机上运行。Python 提供了多种打包工具&#xff0c;其中之一就是 zipapp。zipapp 可以将 Python 应用程序及其依赖打包成一个单独…

FreeMarker 集合遍历

freemarker list (长度,遍历,下标,嵌套,排序) 1. freemarker获取list的size &#xff1a; Java ArrayList<String> list new ArrayList<String>(); Freemaker ${list?size} 2. list的遍历&#xff1a; <#list animals as being> <tr> <td>${be…

java 返回文件的二进制字符串给前端

RequestMapping(value "/fileToStream", method RequestMethod.GET)ApiOperation("将文件转成流传给前端")public WebResponse fileToStream(HttpServletResponse response, HttpServletRequest request){ // // 自动判断下载文件类型 // response.set…

【BZOJ-3033】太鼓达人 欧拉图 + 暴搜

3033: 太鼓达人 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 204 Solved: 154[Submit][Status][Discuss]Description 七夕祭上&#xff0c;Vani牵着cl的手&#xff0c;在明亮的灯光和欢乐的气氛中愉快地穿行。这时&#xff0c;在前面忽然出现了一台太鼓达人机台&#xff…