iOS开发多线程网络———多线程概念及GCD

 iOS开发多线程网络———多线程概念及GCD

一.多线程的概念

1.什么是进程? 

     a.正在进行中的程序被称为进程,负责程序运行的内存分配

     b.每一个进程都有自己独立的虚拟内存空间 

2.什么是线程?

     a.线程是进程中一个独立的执行路径(控制单元)

     b.一个进程中至少包含一条线程,即主线程

      (在iOS中主线程在栈区中区区只占1M,而子线程只有512k) 

     c. 线程可以将耗时的执行路径(如:网络请求)放在其他线程中执行被称为子线程

      (注意:子线程运行完毕被主线程回收了,是杀不掉的,但是可以暂停或休眠)

     d.创建线程的目的就是为了开启一条新的执行路径,运行指定的代码,与主线程中的代码实现同时运行 

        就是为了在一个CPU上实现快速切换! 

3.多任务系统调度 

          当运行多个程序时,每个应用程序都是由操作系统分配短暂的时间片(Timeslice)轮流使用CPU,由于 CPU对每个

      时间片的处理速度非常快(以微秒来计算的),因此用户看起来好像这些任务在同时执行的,但是在任意一个时刻点上,

      CPU只会处理一个任务

4.使用多线程的利弊 

       当了解了多线程的概念之后,我们来看看有多线程都有哪些优势和弊端

      A.优势 

          a.充分发挥多核处理优势,将不同线程任务分配给不同的处理器,真正进入"并行运算"状态

          b.将耗时的任务分配到其他线程执行,由主线程负责统一更新界面回使应用程序更加流畅,用户体验更好

          c.当硬件处理器的数量增加,程序会运行更快,而程序无需做任何调整

     B.弊端

          新建线程会消耗内存空间和CPU时间,线程太多会降低系统的运行性能

     C.误区

         多线程技术是为了并发执行多项任务,不会提高单个算法本身的执行效率 (并发:指两个或多个任务在同一时间间隔内发生)

 

iOS多线程技术有三种,分别是: GCD 、NSThread 、NSOperation/NSOperationQueue

  

 二.GCD

1.什么是GCD

       GCD为Grand Central Dispatch的缩写,简单的说就是是Apple在iOS4.0开发的一个多核编程较新的解决方法,用来优化应

     用程序以支持多核处理器。它是基于C语言的底层API,用Block定义任务,使用起来非常灵活便捷,提供了更多的控制能力以及操作

     队列中所不能使用的底层函数 

2.GCD的核心思想 

   (1) GCD 的核心思想就是将操作放到队列中去执行

           a.操作使用Blocks定义

           b.队列负责调度热舞执行所在的线程以及具体的执行时间

           c.队列的特点是先进先出(FIFO)的,新添加队列的操作都会排在队尾

   (2)提示:GCD的函数都是以dispatch(分派、调度)开头的

   (3)队列 (dispatch_queue_t)

           a. 串行队列:队列中的任务只会顺序执行

           b. 并行队列:队列中的任务通常会并发执行

          (注意:队列不是线程,也不表示对应的CPU  队列就是负责调度!谁空闲,就把任务给谁!) 

   (4)操作

           a.dispatch_async 异步操作,会并发执行,无法确定任务的执行顺序

           b.dispatch_sync   同步操作,会依次顺序执行,能够决定任务的执行顺序 

     2.1 串行队列:队列中的任务只会顺序执行

      串行队列的同步和异步任务代码演示

  1 #import "LDViewController.h"

 2 
 3 @interface LDViewController ()
 4 
 5 @end
 6 
 7 @implementation LDViewController
 8 
 9 - (void)viewDidLoad
10 {
11     [super viewDidLoad];
12     
13     NSLog(@"%@",[NSThread currentThread]);
14     
15     [self gcdDemo1];
16 }
17 
18 #pragma mark - GCD方法
19 #pragma mark - 串行(一个接一个,排队跑步,保持队形)队列
20 - (void)gcdDemo1
21 {
22     //将操作放在队列中
23     //在C语言函数中,定义类型,绝大多数的结尾是_t 或者ref
24     //使用串行队列的异步任务非常有用!新建子线程是有开销的,不能无休止新建线程
25     //即可以保证效率 (新建一个子线程) , 又能够实现并发
26     
27     //应用案例
28     
29     //1>从网络上下载图片
30     //2>滤镜(高光,红眼……)
31     
32     dispatch_queue_t LD = dispatch_queue_create("liudeng", DISPATCH_QUEUE_SERIAL);
33 
34     
35     //串行队列的同步任务,同样会在主线程上运行
36     
37     for (int i = 0 ; i < 6; ++i) {
38         //同步任务:顺序执行
39         dispatch_sync(LD, ^{
40             NSLog(@"%@ %d", [NSThread currentThread],i);
41         });
42     }
43     
44     for (int i = 0; i < 7; ++i) {
45         //异步任务 :并发执行,但是如果在串行队列中,仍然会依次顺序执行
46         dispatch_async(LD, ^{
47             //[NSThread currentThread]  可以在开发中,跟踪当前线程
48             //num = 1, 表示主线程
49             //num = 2, 表示第2个子线程……
50             NSLog(@"%@ %d",[NSThread currentThread], i);
51         });
52     }
53     
54 }
55 
56 
57 @end

     运行结果及总结:

       a.在串行队列中,分别运行同步任务和异步任务时,结果都为下面有序结果可以看出异步任务在串行队列中也是有顺序的)

2014-06-14 00:07:31.337 GCD演练[1346:60b] <NSThread: 0x10941c500>{name = (null), num = 1}
2014-06-14 00:07:31.339 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 20
2014-06-14 00:07:31.340 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 21
2014-06-14 00:07:31.341 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 22
2014-06-14 00:07:31.341 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 23
2014-06-14 00:07:31.342 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 24
2014-06-14 00:07:31.342 GCD演练[1346:1303] <NSThread: 0x1093045e0>{name = (null), num = 25

       b.在串行队列中,同步任务在上,异步任务在下

 1 2014-06-14 00:25:38.240 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 1}
 2 2014-06-14 00:25:38.242 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 10
 3 2014-06-14 00:25:38.242 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 11
 4 2014-06-14 00:25:38.243 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 12
 5 2014-06-14 00:25:38.243 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 13
 6 2014-06-14 00:25:38.244 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 14
 7 2014-06-14 00:25:38.244 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 15
 8 2014-06-14 00:25:38.245 GCD演练[1432:60b] <NSThread: 0x109506690>{name = (null), num = 16
 9 2014-06-14 00:25:38.245 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 20
10 2014-06-14 00:25:38.246 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 21
11 2014-06-14 00:25:38.246 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 22
12 2014-06-14 00:25:38.247 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 23
13 2014-06-14 00:25:38.248 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 24
14 2014-06-14 00:25:38.258 GCD演练[1432:1303] <NSThread: 0x1092799e0>{name = (null), num = 25

        c.在串行队列中,异步任务在上,同步任务在下 (可以看出队列的特点是先进先出(FIFO)的,新添加队列的操作都会排在队尾

 1 2014-06-14 00:23:43.751 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 1}
 2 2014-06-14 00:23:43.753 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 20
 3 2014-06-14 00:23:43.753 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 21
 4 2014-06-14 00:23:43.754 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 22
 5 2014-06-14 00:23:43.754 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 23
 6 2014-06-14 00:23:43.755 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 24
 7 2014-06-14 00:23:43.755 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 25
 8 2014-06-14 00:23:43.756 GCD演练[1414:1303] <NSThread: 0x1092694a0>{name = (null), num = 26
 9 2014-06-14 00:23:43.756 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 10
10 2014-06-14 00:23:43.757 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 11
11 2014-06-14 00:23:43.757 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 12
12 2014-06-14 00:23:43.758 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 13
13 2014-06-14 00:23:43.758 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 14
14 2014-06-14 00:23:43.760 GCD演练[1414:60b] <NSThread: 0x10931c500>{name = (null), num = 15


     2.2 并行队列:队列中的任务通常会并发执行 

     并行队列的同步和异步任务代码演示

 1 #import "LDViewController.h"
 2 
 3 @interface LDViewController ()
 4 
 5 @end
 6 
 7 @implementation LDViewController
 8 
 9 - (void)viewDidLoad
10 {
11     [super viewDidLoad];
12     
13     NSLog(@"%@",[NSThread currentThread]);
14     
15     [self gcdDemo2];
16 }
17 
18 #pragma mark - GCD方法
19 
20 #pragma mark - 并行 (并排跑,类似于赛跑)
21 - (void)gcdDemo2
22 {
23     //特点:没有队形,执行顺序程序员不能控制
24     //应用场景:并发执行任务,没有先后顺序
25     //并行队列容易出错!并行队列不能控制新建线程的数量!
26     dispatch_queue_t LD = dispatch_queue_create("liudeng", DISPATCH_QUEUE_CONCURRENT);
27 
28     for (int i = 0 ; i < 7; ++i) {
29         //同步任务:顺序执行
30         dispatch_sync(LD, ^{
31             NSLog(@"%@ %d", [NSThread currentThread],i);
32         });
33     }
34 
35     for (int i = 0; i < 6; ++i) {
36         //异步任务
37         dispatch_async(LD, ^{
38             //[NSThread currentThread]  可以在开发中,跟踪当前线程
39             //num = 1, 表示主线程
40             //num = 2, 表示第2个子线程……
41             NSLog(@"%@ %d",[NSThread currentThread], i);
42         });
43     }
44 }


    运行结果及总结:

       a.在并行队列中,单独运行同步任务结果 (可以看出同步任务在并行队列中是有顺序的)

1 2014-06-14 00:42:54.172 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 1}
2 2014-06-14 00:42:54.174 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 10
3 2014-06-14 00:42:54.175 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 11
4 2014-06-14 00:42:54.175 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 12
5 2014-06-14 00:42:54.176 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 13
6 2014-06-14 00:42:54.176 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 14
7 2014-06-14 00:42:54.177 GCD演练[1503:60b] <NSThread: 0x10921c630>{name = (null), num = 15

       b.在并行队列中,单独运行异步任务结果 (可以看出异步任务在并行队列中是没有顺序的

1 2014-06-14 00:45:51.925 GCD演练[1522:60b] <NSThread: 0x10930f2c0>{name = (null), num = 1}
2 2014-06-14 00:45:51.927 GCD演练[1522:3007] <NSThread: 0x109229b90>{name = (null), num = 51
3 2014-06-14 00:45:51.927 GCD演练[1522:3503] <NSThread: 0x1092081c0>{name = (null), num = 32
4 2014-06-14 00:45:51.927 GCD演练[1522:3603] <NSThread: 0x109420830>{name = (null), num = 43
5 2014-06-14 00:45:51.927 GCD演练[1522:1303] <NSThread: 0x10921c760>{name = (null), num = 20
6 2014-06-14 00:45:51.928 GCD演练[1522:3007] <NSThread: 0x109229b90>{name = (null), num = 54
7 2014-06-14 00:45:51.930 GCD演练[1522:3603] <NSThread: 0x109420830>{name = (null), num = 46

       c.在并行队列中,同步任务在上,异步任务在下结果  (同步任务是有序的,而且还是在主线程上执行,只有同步任务执行完毕之后,异步任务才开始工作)

 1 2014-06-14 00:48:50.231 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 1}
 2 2014-06-14 00:48:50.232 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 10
 3 2014-06-14 00:48:50.233 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 11
 4 2014-06-14 00:48:50.233 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 12
 5 2014-06-14 00:48:50.234 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 13
 6 2014-06-14 00:48:50.234 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 14
 7 2014-06-14 00:48:50.235 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 15
 8 2014-06-14 00:48:50.235 GCD演练[1541:60b] <NSThread: 0x10931c500>{name = (null), num = 16
 9 2014-06-14 00:48:50.236 GCD演练[1541:1303] <NSThread: 0x1092205c0>{name = (null), num = 20
10 2014-06-14 00:48:50.236 GCD演练[1541:3603] <NSThread: 0x109220730>{name = (null), num = 33
11 2014-06-14 00:48:50.236 GCD演练[1541:3403] <NSThread: 0x10934e550>{name = (null), num = 51
12 2014-06-14 00:48:50.236 GCD演练[1541:3503] <NSThread: 0x10934cc40>{name = (null), num = 42
13 2014-06-14 00:48:50.237 GCD演练[1541:1303] <NSThread: 0x1092205c0>{name = (null), num = 24
14 2014-06-14 00:48:50.237 GCD演练[1541:3403] <NSThread: 0x10934e550>{name = (null), num = 56

       d.在并行队列中,异步任务在上,同步任务在下结果  (没有队行,执行顺序程序员不能控制)

 1 2014-06-14 00:54:38.679 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 1}
 2 2014-06-14 00:54:38.680 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 10
 3 2014-06-14 00:54:38.681 GCD演练[1559:1303] <NSThread: 0x10937c290>{name = (null), num = 20
 4 2014-06-14 00:54:38.681 GCD演练[1559:3503] <NSThread: 0x109623b30>{name = (null), num = 42
 5 2014-06-14 00:54:38.681 GCD演练[1559:3403] <NSThread: 0x10cf04e00>{name = (null), num = 31
 6 2014-06-14 00:54:38.681 GCD演练[1559:3603] <NSThread: 0x10cf07580>{name = (null), num = 53
 7 2014-06-14 00:54:38.681 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 11
 8 2014-06-14 00:54:38.684 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 12
 9 2014-06-14 00:54:38.684 GCD演练[1559:3403] <NSThread: 0x10cf04e00>{name = (null), num = 36
10 2014-06-14 00:54:38.681 GCD演练[1559:3503] <NSThread: 0x109623b30>{name = (null), num = 45
11 2014-06-14 00:54:38.685 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 13
12 2014-06-14 00:54:38.681 GCD演练[1559:1303] <NSThread: 0x10937c290>{name = (null), num = 24
13 2014-06-14 00:54:38.685 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 14
14 2014-06-14 00:54:38.685 GCD演练[1559:60b] <NSThread: 0x10960f2c0>{name = (null), num = 15

      2.3 全局列:全局队列是系统的,直接通过(get)拿过来用就可以了

 1 #pragma mark - GCD方法
 2 
 3 #pragma mark - 全局队列 (苹果为了方便多线程的设计,提供一个全局队列,供所有的APP共同使用)
 4 - (void)gcdDemo3
 5 {
 6     dispatch_queue_t LD = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 7     for (int i = 0 ; i < 7; ++i) {
 8         //同步任务:顺序执行
 9         dispatch_sync(LD, ^{
10             NSLog(@"%@ %d", [NSThread currentThread],i);
11         });
12     }
13     
14     for (int i = 0; i < 7; ++i) {
15         //异步任务 :并发执行,但是如果在串行队列中,仍然会依次顺序执行
16         dispatch_async(LD, ^{
17             //[NSThread currentThread]  可以在开发中,跟踪当前线程
18             //num = 1, 表示主线程
19             //num = 2, 表示第2个子线程……
20             NSLog(@"%@ %d",[NSThread currentThread], i);
21         });
22     }

     全局队列和并行队列很类似,比较如下:

             a.全局队列不需要创建,直接get就能用 

             b.两个队列的执行效果相同

             c.全局队列没有名称,调试时,无法确认准确队列

       2.4 主(线程)列:

 1 #pragma mark - 主(线程)队列,保证操作在主线程上执行
 2 - (void)gcdDemo4
 3 {
 4     //每一个应用程序都只有一个主线程
 5     //为什么需要在主线程上工作?
 6     //在IOS开发中,所有UI的更新工作,都必须在主线程上执行!
 7     dispatch_queue_t LD = dispatch_get_main_queue();
 8     //主线程是一直工作的,除非将程序杀掉,否则主线程的工作永远不会结束
 9     //同步任务,主线程会阻塞
10 //    dispatch_sync(LD, ^{
11 //        NSLog(@"你好");
12 //    });
13     
14     for (int i = 0; i < 6; ++i) {
15         //异步任务,在主线程上运行,同时是保持队形的
16         dispatch_async(LD, ^{
17             NSLog(@"%@  %d", [NSThread currentThread], i);
18         });
19     }


      

3.GCD小结: 

            串行队列,同步任务,不需要新建线程

            串行队列,异步任务,需要一个子线程,线程的创建和回收不需要程序员参与! “是最安全的一种选择,串行队列是get不到的,只能创建”

            并行队列,同步任务,不需要创建线程

            并行队列,异步任务,有多少个任务,就开N个线程执行

      通过GCD,开发者不用再直接跟线程打交道,只需要向队列中添加代码块即可

      GCD在后端管理着一个线程池,GCD不仅决定着代码块将在哪个线程被执行,它还根据可用的系统资源对这些线程进行

管理,从而让开发者从线程管理的工作中解放出来,通过集中的管理线程,缓解大量线程被创建问题

      使用GCD,开发者可以将工作考虑为一个队列,而不是一堆线程,这种并行的抽象模型更容易掌握和使用 

    

 

 

 

 

iOS开发多线程网络———多线程概念及GCD,布布扣,bubuko.com

iOS开发多线程网络———多线程概念及GCD

上一篇:使用dx命令在cmd环境下执行的正确方法,我用的版本android4.4.2,jdk1.8


下一篇:jQuery对象入门级介绍