iOS 多线程

GCD队列+任务(OC&Swift)

2017-09-22  本文已影响112人  CocoaC_Wang

说明:本文主要用于个人能力的提高,主要参考于简书,Swift版本为3.0

1. 简介

什么是GCD呢?我们先看看百度百科的解释了解下概念

引用百度百科
Grand Central Dispatch (GCD) 是Apple开发的一个多核编程的较新的解决方法。它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。它是一个在线程池模式的基础上执行的并行任务。在Mac OS X 10.6雪豹中首次推出,也可在IOS 4及以上版本使用。

为什么要用GCD呢?

因为GCD有很多好处,具体如下:

既然GCD有这么多的好处,那么下面我们就来系统的学习一下GCD的使用方法。

2.任务和队列

学习GCD之前,先来了解GCD中两个核心概念:任务和队列

任务: 就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在GCD中是放在block中的,swift是放在闭包中的。执行任务有两种方式:同步执行异步执行。两者的主要区别是:是否具备开启新线程的能力。

队列:这里的队列指任务队列,即用来存放任务的队列。队列是一种特殊的线性表,采用FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务。在GCD中有两种队列:串行队列并行队列

3.GCD的使用步骤

GCD的使用步骤其实很简单,只有两步。

  1. 创建一个队列(串行队列或并行队列)
  2. 将任务添加到队列中,然后系统就会根据任务类型执行任务(同步执行或异步执行)

下面来看看队列的创建和任务的创建方法。

1. 队列的创建方法

OC版本:

// 串行队列的创建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
// 并行队列的创建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT); 

Swift版本:

// 创建串行队列
let queue = DispatchQueue(label: "test.queue")
// 创建并行队列
let queue = DispatchQueue(label: "test.queue", attributes: .concurrent)

2. 任务的创建方法

OC版本:

// 同步执行任务创建方法
dispatch_sync(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);  // 这里放任务代码
});
    
// 异步执行任务创建方法
dispatch_async(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);  // 这里放任务代码
});

Swift版本:

// 同步执行任务创建方法
queue.sync {
    print(Thread.current)
}
// 异步执行任务创建方法
queue.async {
    print(Thread.current)
}

虽然使用GCD只有两步,但是既然我们有两种队列,两种任务执行方式,那么我们就有了四种不同的组合方式。这四种不同的组合方式是:

  1. 并行队列 + 同步执行
  2. 并行队列 + 异步执行
  3. 串行队列 + 同步执行
  4. 串行队列 + 异步执行

实际上我们还有一种特殊的主队列,那就有六种不同的组合方式了

  1. 主队列 + 同步执行
  2. 主队列 + 异步执行

那么这几种不同组合方式有什么区别呢,这里为了方便,先上结果,再来讲解。为图省事,直接查看表格结果,然后可以跳过4. GCD的基本使用 了。

并行队列 串行队列 主队列
同步(sync) 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务
异步(async) 有开启新线程,并行执行任务 有开启新线程(1条),串行执行任务 没有开启新线程,串行执行任务

4. GCD的基本使用

先来讲讲并行队列的两种使用方法。

1. 并行队列 + 同步执行

- (void)syncConcurrentMethod{
    NSLog(@"syncConcurrentMethod---begin");
    
    dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"syncConcurrentMethod---end");
}

输出结果:
2017-09-19 10:57:34.223 OC-GCD[1824:54181] syncConcurrentMethod---begin
2017-09-19 10:57:34.223 OC-GCD[1824:54181] 1------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.223 OC-GCD[1824:54181] 1------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.223 OC-GCD[1824:54181] 2------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.223 OC-GCD[1824:54181] 2------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.224 OC-GCD[1824:54181] 3------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.224 OC-GCD[1824:54181] 3------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.224 OC-GCD[1824:54181] syncConcurrentMethod---end

Swift版本:

    func syncConcurrentMethod() {
        print("syncConcurrentMethod---begin")
        
        let queue = DispatchQueue(label: "test.queue", attributes: .concurrent)
        
        queue.sync {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("syncConcurrentMethod---end")
    }

输出结果:
syncConcurrentMethod---begin
1------ <NSThread: 0x61000006a440>{number = 1, name = main}
1------ <NSThread: 0x61000006a440>{number = 1, name = main}
2------ <NSThread: 0x61000006a440>{number = 1, name = main}
2------ <NSThread: 0x61000006a440>{number = 1, name = main}
3------ <NSThread: 0x61000006a440>{number = 1, name = main}
3------ <NSThread: 0x61000006a440>{number = 1, name = main}
syncConcurrentMethod---end

2. 并行队列 + 异步执行

OC版本:

- (void)asyncConcurrentMethod{
    NSLog(@"asyncConcurrentMethod---begin");
    
    dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"asyncConcurrentMethod---end");
}

输出结果:
2017-09-19 11:16:35.521 OC-GCD[2301:67293] asyncConcurrentMethod---begin
2017-09-19 11:16:35.521 OC-GCD[2301:67293] asyncConcurrentMethod---end
2017-09-19 11:16:35.521 OC-GCD[2301:67348] 1------<NSThread: 0x608000073e00>{number = 3, name = (null)}
2017-09-19 11:16:35.521 OC-GCD[2301:67719] 2------<NSThread: 0x6000000787c0>{number = 4, name = (null)}
2017-09-19 11:16:35.521 OC-GCD[2301:67720] 3------<NSThread: 0x6180000790c0>{number = 5, name = (null)}
2017-09-19 11:16:35.522 OC-GCD[2301:67348] 1------<NSThread: 0x608000073e00>{number = 3, name = (null)}
2017-09-19 11:16:35.522 OC-GCD[2301:67719] 2------<NSThread: 0x6000000787c0>{number = 4, name = (null)}
2017-09-19 11:16:35.522 OC-GCD[2301:67720] 3------<NSThread: 0x6180000790c0>{number = 5, name = (null)}

Swift版本:

func asyncConcurrentMethod() {
        print("asyncConcurrentMethod---begin")
        
        let queue = DispatchQueue(label: "test.queue", attributes: .concurrent)
        
        queue.async {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("asyncConcurrentMethod---end")
    }

输出结果:
asyncConcurrentMethod---begin
asyncConcurrentMethod---end
1------ <NSThread: 0x61000007e700>{number = 3, name = (null)}
2------ <NSThread: 0x60800007eac0>{number = 4, name = (null)}
3------ <NSThread: 0x60800007ec00>{number = 5, name = (null)}
1------ <NSThread: 0x61000007e700>{number = 3, name = (null)}
2------ <NSThread: 0x60800007eac0>{number = 4, name = (null)}
3------ <NSThread: 0x60800007ec00>{number = 5, name = (null)}

3. 串行队列 + 同步执行

- (void) syncSerialMethod {
    NSLog(@"syncSerialMethod---begin");
    
    dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"syncSerialMethod---end");
}

输出结果:
2017-09-19 11:35:00.774 OC-GCD[2699:78730] syncSerialMethod---begin
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 1------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 1------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 2------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 2------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 3------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.776 OC-GCD[2699:78730] 3------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.776 OC-GCD[2699:78730] syncSerialMethod---end
Swift版本:

func syncSerialMethod() {
        
        print("syncSerialMethod---begin")
        
        let queue = DispatchQueue(label: "test.queue")
        
        queue.sync {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("syncSerialMethod---end")
        
    }

输出结果:
syncSerialMethod---begin
1------ <NSThread: 0x6080000757c0>{number = 1, name = main}
1------ <NSThread: 0x6080000757c0>{number = 1, name = main}
2------ <NSThread: 0x6080000757c0>{number = 1, name = main}
2------ <NSThread: 0x6080000757c0>{number = 1, name = main}
3------ <NSThread: 0x6080000757c0>{number = 1, name = main}
3------ <NSThread: 0x6080000757c0>{number = 1, name = main}
syncSerialMethod---end

4. 串行队列 + 异步执行

- (void) asyncSerialMethod{
    NSLog(@"asyncSerialMethod---begin");
    
    dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"asyncSerialMethod---end");
}

输出结果:
2017-09-19 11:54:29.808 OC-GCD[3018:88451] asyncSerialMethod---begin
2017-09-19 11:54:29.808 OC-GCD[3018:88451] asyncSerialMethod---end
2017-09-19 11:54:29.808 OC-GCD[3018:88506] 1------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 1------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 2------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 2------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 3------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 3------<NSThread: 0x600000068940>{number = 3, name = (null)}

Swift版本:

func asyncSerialMethod() {
        
        print("asyncSerialMethod---begin")
        
        let queue = DispatchQueue(label: "test.queue")
        
        queue.async {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("asyncSerialMethod---end")
        
    }

输出结果:
asyncSerialMethod---begin
asyncSerialMethod---end
1------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
1------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
2------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
2------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
3------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
3------ <NSThread: 0x600000267c80>{number = 3, name = (null)}

然后讲讲刚才提到过的特殊队列——主队列

再来看看主队列的两种组合方式

5. 主队列 + 同步执行

OC版本:

- (void)syncMainMethod{
    NSLog(@"syncMainMethod---begin");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"syncMainMethod---end");
}

输出结果:
2017-09-19 14:20:14.826 OC-GCD[4057:146416] syncMainMethod---begin
(lldb)

Swift版本:

func syncMainMethod() {
        
        print("syncMainMethod---begin")
        
        let queue = DispatchQueue.main
        
        queue.sync {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("syncMainMethod---end")
        
    }

输出结果:
syncMainMethod---begin
(lldb)

这时候,我们可以发现,在主线程中使用主队列 + 同步执行,任务不再执行了,而syncMainMethod---end也没有打印了,这是什么原因导致的呢?

这是因为我们在主线中执行这段代码。我们把任务放到了主队列中,也就是放到了主线程的队列中。而同步执行有个特点,就是对于任务是立马执行的。那么当我们把第一个任务放进主队列中,它会立即执行。但是对于主线程现在正在处理syncMainMethod方法,而任务又需要等syncMainMethod方法执行结束才能执行。而syncMainMethod执行到第一个任务的时候,又要等第一个任务执行完才能玩下执行第二和第三个任务。简单来说,就是syncMainMethod方法结束后才能执行第一个同步任务,而第一个同步任务又在syncMainMethod方法中,需要执行了本任务之后,才能继续执行其他任务,直到syncMainMethod方法完全结束,相互等待,造成了死锁

那么,现在的情况就是第一个任务都在等对方执行完毕,造成了死锁,所以我们的任务就执行不了,而且syncMainMethod---end也没打印

要是如果不在主线程中调用,而在其他线程中调用会如何呢?

OC版本:

    dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        [self syncMainMethod];
    });

输出结果:
2017-09-19 14:51:03.723 OC-GCD[4483:161903] syncMainMethod---begin
2017-09-19 14:51:03.723 OC-GCD[4483:161788] 1------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 1------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 2------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 2------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 3------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 3------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161903] syncMainMethod---end

Swift版本:

        let queue = DispatchQueue(label: "test.queue", attributes: .concurrent)
        queue.async {
            self.syncMainMethod()
        }

输出结果:
syncMainMethod---begin
1------ <NSThread: 0x61800007aa40>{number = 1, name = main}
1------ <NSThread: 0x61800007aa40>{number = 1, name = main}
2------ <NSThread: 0x61800007aa40>{number = 1, name = main}
2------ <NSThread: 0x61800007aa40>{number = 1, name = main}
3------ <NSThread: 0x61800007aa40>{number = 1, name = main}
3------ <NSThread: 0x61800007aa40>{number = 1, name = main}
syncMainMethod---end

6. 主队列 + 异步执行

OC版本:

- (void)asyncMainMethod{
    NSLog(@"asyncMainMethod---begin");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"asyncMainMethod---end");
}

输出结果:
2017-09-19 22:30:10.807 OC-GCD[1151:23348] asyncMainMethod---begin
2017-09-19 22:30:10.808 OC-GCD[1151:23348] asyncMainMethod---end
2017-09-19 22:30:10.809 OC-GCD[1151:23348] 1------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 1------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 2------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 2------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 3------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 3------<NSThread: 0x60000006e500>{number = 1, name = main}

Swift版本:

    func asyncMainMethod() {
        
        print("asyncMainMethod---begin")
        
        let queue = DispatchQueue.main
        
        queue.async {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("asyncMainMethod---end")
        
    }

输出结果:
asyncMainMethod---begin
asyncMainMethod---end
1------ <NSThread: 0x6080000707c0>{number = 1, name = main}
1------ <NSThread: 0x6080000707c0>{number = 1, name = main}
2------ <NSThread: 0x6080000707c0>{number = 1, name = main}
2------ <NSThread: 0x6080000707c0>{number = 1, name = main}
3------ <NSThread: 0x6080000707c0>{number = 1, name = main}
3------ <NSThread: 0x6080000707c0>{number = 1, name = main}

上一篇下一篇

猜你喜欢

热点阅读