iOS开发之GCD使用总结
作者:网络转载 发布时间:[ 2014/7/31 11:23:47 ] 推荐标签:软件测试 ios
延迟执行任务
1 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
2 //...
3 });
这段代码将会在10秒后将任务插入RunLoop当中。
dispatch_asycn和dispatch_sync
先前已经有过一个使用dispatch_async执行异步任务的一个例子,下面来看一段代码:
1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2
3 dispatch_async(queue, ^{
4 NSLog(@"1");
5 });
6
7 NSLog(@"2");
这段代码首先获取了全局队列,也是说,dispatch_async当中的任务被丢到了另一个线程里去执行,async在这里的含义是,当当前线程给子线程分配了block当中的任务之后,当前线程会立即执行,并不会发生阻塞,也是异步的。那么,输出结果不是12是21,因为我们没法把控两个线程RunLoop里到底是怎么执行的。
类似的,还有一个“同步”方法dispatch_sync,代码如下:
1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2
3 dispatch_sync(queue, ^{
4 NSLog(@"1");
5 });
6
7 NSLog(@"2");
这意味着,当主线程将任务分给子线程后,主线程会等待子线程执行完毕,再继续执行自身的内容,那么结果显然是12了。
需要注意的一点是,这里用的是全局队列,那如果把dispatch_sync的队列换成主线程队列会怎么样呢:
1 dispatch_queue_t queue = dispatch_get_main_queue();
2 dispatch_sync(queue, ^{
3 NSLog(@"1");
4 });
这段代码会发生死锁,因为:
1.主线程通过dispatch_sync把block交给主队列后,会等待block里的任务结束再往下走自身的任务,
2.而队列是先进先出的,block里的任务也在等待主队列当中排在它之前的任务都执行完了再走自己。
这种循环等待形成了死锁。所以在主线程当中使用dispatch_sync将任务加到主队列是不可取的。
创建队列
我们可以使用系统提供的函数获取主串行队列和全局并行队列,当然也可以自己手动创建串行和并行队列,代码为:
1 dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.Steak.GCD", DISPATCH_QUEUE_SERIAL);
2 dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.Steak.GCD", DISPATCH_QUEUE_CONCURRENT);
在MRC下,手动创建的队列是需要释放的
1 dispatch_release(myConcurrentDispatchQueue);
手动创建的队列和默认优先级全局队列优先级等同,如果需要修改队列的优先级,需要:
1 dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.Steak.GCD", DISPATCH_QUEUE_CONCURRENT);
2 dispatch_queue_t targetQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
3 dispatch_set_target_queue(myConcurrentDispatchQueue, targetQueue);
上面的代码修改队列的优先级为后台级别,即与默认的后台优先级的全局队列等同。
串行、并行队列与读写安全性
在向串行队列(SerialDispatchQueue)当中加入多个block任务后,一次只能同时执行一个block,如果生成了n个串行队列,并且向每个队列当中都添加了任务,那么系统会启动n个线程来同时执行这些任务。
对于串行队列,正确的使用时机,是在需要解决数据/文件竞争问题时使用它。比如,我们可以令多个任务同时访问一块数据,这样会出现冲突,也可以把每个操作都加入到一个串行队列当中,因为串行队列一次只能执行一个线程的任务,所以不会出现冲突。
但是考虑到串行队列会因为上下文切换而拖慢系统性能,所以我们还是很期望采用并行队列的,来看下面的示例代码:
1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2 dispatch_async(queue, ^{
3 //数据读取
4 });
5 dispatch_async(queue, ^{
6 //数据读取2
7 });
8 dispatch_async(queue, ^{
9 //数据写入
10 });
11 dispatch_async(queue, ^{
12 //数据读取3
13 });
14 dispatch_async(queue, ^{
15 //数据读取4
16 });
显然,这5个操作的执行顺序是我们无法预期的,我们希望在读取1和读取2执行结束后,再执行写入,写入完成后再执行读取3和读取4。
为了实现这个效果,这里可以使用GCD的另一个API:
1 dispatch_barrier_async(queue, ^{
2 //数据写入
3 });
这样保证的写入操作的并发安全性。
对于没有数据竞争的并行操作,则可以使用并行队列(CONCURRENT)来实现。
$news 延迟执行任务
1 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
2 //...
3 });
这段代码将会在10秒后将任务插入RunLoop当中。
dispatch_asycn和dispatch_sync
先前已经有过一个使用dispatch_async执行异步任务的一个例子,下面来看一段代码:
1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2
3 dispatch_async(queue, ^{
4 NSLog(@"1");
5 });
6
7 NSLog(@"2");
这段代码首先获取了全局队列,也是说,dispatch_async当中的任务被丢到了另一个线程里去执行,async在这里的含义是,当当前线程给子线程分配了block当中的任务之后,当前线程会立即执行,并不会发生阻塞,也是异步的。那么,输出结果不是12是21,因为我们没法把控两个线程RunLoop里到底是怎么执行的。
类似的,还有一个“同步”方法dispatch_sync,代码如下:
1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2
3 dispatch_sync(queue, ^{
4 NSLog(@"1");
5 });
6
7 NSLog(@"2");
这意味着,当主线程将任务分给子线程后,主线程会等待子线程执行完毕,再继续执行自身的内容,那么结果显然是12了。
需要注意的一点是,这里用的是全局队列,那如果把dispatch_sync的队列换成主线程队列会怎么样呢:
1 dispatch_queue_t queue = dispatch_get_main_queue();
2 dispatch_sync(queue, ^{
3 NSLog(@"1");
4 });
这段代码会发生死锁,因为:
1.主线程通过dispatch_sync把block交给主队列后,会等待block里的任务结束再往下走自身的任务,
2.而队列是先进先出的,block里的任务也在等待主队列当中排在它之前的任务都执行完了再走自己。
这种循环等待形成了死锁。所以在主线程当中使用dispatch_sync将任务加到主队列是不可取的。
创建队列
我们可以使用系统提供的函数获取主串行队列和全局并行队列,当然也可以自己手动创建串行和并行队列,代码为:
1 dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.Steak.GCD", DISPATCH_QUEUE_SERIAL);
2 dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.Steak.GCD", DISPATCH_QUEUE_CONCURRENT);
在MRC下,手动创建的队列是需要释放的
1 dispatch_release(myConcurrentDispatchQueue);
手动创建的队列和默认优先级全局队列优先级等同,如果需要修改队列的优先级,需要:
1 dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.Steak.GCD", DISPATCH_QUEUE_CONCURRENT);
2 dispatch_queue_t targetQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
3 dispatch_set_target_queue(myConcurrentDispatchQueue, targetQueue);
上面的代码修改队列的优先级为后台级别,即与默认的后台优先级的全局队列等同。
串行、并行队列与读写安全性
在向串行队列(SerialDispatchQueue)当中加入多个block任务后,一次只能同时执行一个block,如果生成了n个串行队列,并且向每个队列当中都添加了任务,那么系统会启动n个线程来同时执行这些任务。
对于串行队列,正确的使用时机,是在需要解决数据/文件竞争问题时使用它。比如,我们可以令多个任务同时访问一块数据,这样会出现冲突,也可以把每个操作都加入到一个串行队列当中,因为串行队列一次只能执行一个线程的任务,所以不会出现冲突。
但是考虑到串行队列会因为上下文切换而拖慢系统性能,所以我们还是很期望采用并行队列的,来看下面的示例代码:
1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2 dispatch_async(queue, ^{
3 //数据读取
4 });
5 dispatch_async(queue, ^{
6 //数据读取2
7 });
8 dispatch_async(queue, ^{
9 //数据写入
10 });
11 dispatch_async(queue, ^{
12 //数据读取3
13 });
14 dispatch_async(queue, ^{
15 //数据读取4
16 });
显然,这5个操作的执行顺序是我们无法预期的,我们希望在读取1和读取2执行结束后,再执行写入,写入完成后再执行读取3和读取4。
为了实现这个效果,这里可以使用GCD的另一个API:
1 dispatch_barrier_async(queue, ^{
2 //数据写入
3 });
这样保证的写入操作的并发安全性。
对于没有数据竞争的并行操作,则可以使用并行队列(CONCURRENT)来实现。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11