GCD--我的理解

推荐:http://www.jianshu.com/p/0b0d9b1f1f19?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=qq

GCD:Grand Central Dispatch,它是苹果为多核的并行运算提出的解决方案,所以会自动合理地利用更多的CPU内核(比如双核、四核),最重要的是它会自动管理线程的生命周期(创建线程、调度任务、销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。同时它使用的也是 c语言,不过由于使用了 Block(Swift里叫做闭包),使得使用起来更加方便,而且灵活。

主要由两个重要概念:任务队列

需要掌握怎么创建队列和创建任务。

任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。任务有两种执行方式: 同步执行异步执行

同步(sync) 和 异步(async)主要区别在于会不会阻塞当前线程,直到 Block 中的任务执行完毕!
如果是 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。
如果是 异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。

队列:用于存放任务。一共有两种队列, 串行队列并行队列

串行队列 :串行队列中的任务会根据队列的定义 FIFO 的执行,一个接一个的先进先出的进行执行。放到串行队列的任务,GCD 会 FIFO(先进先出) 地取出来一个,执行一个,然后取下一个,这样一个一个的执行。
并行队列 :放到并行队列的任务,GCD 也会 FIFO的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。

分析一个常见的栗子来展开吧:

--栗子--
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSString* result = [self fetchResultFromWebWithParameter:parameter];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateUIWithResult:parameter];
    });
});

在栗子中:
dispatch_async(dispatch_sync)表示当前创建的任务是异步还是同步执行的(前面说了它们的区别主要在于会不会阻塞当前线程),也是通过它把相应的任务添加到的队列中去(一般都是在做dispatch_async异步的吧);

同步任务:会阻塞当前线程 (SYNC)
dispatch_sync(queue, ^{
      //code here
  });
  
异步任务:不会阻塞当前线程 (ASYNC)
dispatch_async(queue, ^{
      //code here
  });

-------------------------------------------------------------分割君-----------------------------------------------------------------
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 和 dispatch_get_main_queue()表示当前任务会被放在哪个队列里面,其中DISPATCH_QUEUE_PRIORITY_DEFAULT表示优先级,0 作为flag是保留字段备用(一般为0),
看看都有哪些队列了?
分为 Serial Dispatch Queue(串行队列)Concurrent Dispatch Queue(并行队列)
Serial Dispatch Queue – 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始。
Concurrent Dispatch Queue – 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行。
GCD的队列又分为:主队列(main_queue),全局队列(global_queue),用户创建队列(create)
主队列(main_queue)和 全局队列global_queue是系统默认就有的(也就是说程序创建好就有了,只需要去获取他们然后使用就好,真棒):

dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  //只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。
dispatch_queue_t mainQ = dispatch_get_main_queue();     		//它用于刷新 UI,任何需要刷新 UI 的工作都要在主队列执行,所以一般耗时的任务都要放到别的线程执行。	

其中main_queue是串行队列,global_queue是并行队列;
对于全局队列(global_queue),默认有四个,分为四个优先级
#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

DISPATCH_QUEUE_PRIORITY_HIGH:优先级最高,在default,和low之前执行
DISPATCH_QUEUE_PRIORITY_DEFAULT 默认优先级,在low之前,在high之后
DISPATCH_QUEUE_PRIORITY_LOW 在high和default后执行
DISPATCH_QUEUE_PRIORITY_BACKGROUND:提交到这个队列的任务会在high优先级的任务和已经提交到background队列的执行完后执行。

通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作,

除了系统的提供的队列,用户还可以自己创建自己的自定义队列:
dispatch_queue_t queue = dispatch_queue_create(“myQueue”, NULL);
使用还是一样的:

dispatch_async(queue, ^{
        printf("Do some work here.\n");
    });

dispatch_queue_t queue = dispatch_queue_create(“myQueue”, NULL);
上面这句代码中第一个参数(“myQueue”)是标识符,用于 DEBUG 的时候标识唯一的队列,可以为空第二个才是最重要的,第二个参数用来表示创建的队列是串行的还是并行的,传入 DISPATCH_QUEUE_SERIAL 或 NULL 表示创建串行队列。传入 DISPATCH_QUEUE_CONCURRENT 表示创建并行队列。
也就是说,自己可以创建 串行队列, 也可以创建 并行队列,如下:

  //串行队列
  dispatch_queue_t queue = dispatch_queue_create("fk_Queue", NULL);
  dispatch_queue_t queue = dispatch_queue_create("fk_Queue", DISPATCH_QUEUE_SERIAL);
  //并行队列
  dispatch_queue_t queue = dispatch_queue_create("fk_Queue", DISPATCH_QUEUE_CONCURRENT);

-------------------------------------------------------------分割君-----------------------------------------------------------------
^{ //your code//}表示你要执行的任务内容,显然是block;
-------------------------------------------------------------分割君-----------------------------------------------------------------

最后来看看他们的执行方式:

—————同步执行异步执行
串行队列当前线程,一个一个执行其他线程(同一线程),一个一个执行
并行队列当前线程,一个一个执行开很多线程,一起执行

再举个栗子:

dispatch_queue_t queue;
queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);  //并行队列
dispatch_sync(queue, ^{
	    sleep(3);
        NSLog(@"first sync");
    });
dispatch_sync(queue, ^{
        NSLog(@"second sync");
    });
或者
dispatch_queue_t queue2;
queue2 = dispatch_queue_create("myQueue2", DISPATCH_QUEUE_SERIAL);      // 串行队列
dispatch_sync(queue2, ^{
        NSLog(@"first sync");
    });
dispatch_sync(queue, ^{
        NSLog(@"second sync");
    });

结果都是:

2015-10-08 18:09:14.007 FKTest[1724:221306] first sync
2015-10-08 18:09:14.008 FKTest[1724:221306] second sync

所以只要是dispatch_sync(同步执行)的就是意味着会阻塞当前线程,知道其任务完成(也就是说block执行结束),不管队列是串行的还是并行的;

而dispatch_async(异步执行)则会根据的队列进行相关的操作:
串行队列:按照FIFO,一次取一个任务,完了再取,所以还是one by one,但是在哪个线程执行则要取决于当前的queue了,如果是同一个串行queue,那么会在一个线程中执行,如果是在不同的串行queue中则会在不同的线程中执行;
测试代码1:

    dispatch_queue_t queue;
    queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"first sync--- %@",[NSThread currentThread]);
    });
    dispatch_queue_t queue2;
    queue2 = dispatch_queue_create("myQueue2", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue2, ^{
       NSLog(@"second sync--- %@",[NSThread currentThread]);
    });

结果:

2015-10-08 18:46:59.822 FKTest[2087:257779] first sync--- <NSThread: 0x7fe77a08adb0>{number = 2, name = (null)}
2015-10-08 18:46:59.822 FKTest[2087:257778] second sync--- <NSThread: 0x7fe77a102ad0>{number = 3, name = (null)}

即在不同的线程执行的

测试代码2:

    dispatch_queue_t queue;
    queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"first sync--- %@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
       NSLog(@"second sync--- %@",[NSThread currentThread]);
    });

结果:

2015-10-08 18:48:00.060 FKTest[2110:259038] first sync--- <NSThread: 0x7fd878705a70>{number = 2, name = (null)}
2015-10-08 18:48:00.060 FKTest[2110:259038] second sync--- <NSThread: 0x7fd878705a70>{number = 2, name = (null)}
即在同一个线程里执行的

并行队列:这个很显然了,异步的,还是并行的队列,相当于大家相互没什么关系,谁爱在哪个线程玩,什么时候玩都是自己的事,不管彼此。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值