Cowboy Tech

GCD学习笔记

多线程基础

进程

进程是指在系统中正在运行的一个应用程序

每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内

线程

1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程,称为主线程)

一个进程(程序)的所有任务都在线程中执行

进程和线程的比较

  1. 线程是CPU调用(执行任务)的最小单位。

  2. 进程是CPU分配资源的最小单位。

  3. 一个进程中至少要有一个线程。

  4. 同一个进程内的线程共享进程的资源。

多线程

1个进程中可以开启多条线程,每条线程可以并行(同时)执行不同的任务

多线程技术可以提高程序的执行效率

同一时间,CPU只能处理1条线程,只有1条线程在工作(执行),多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换),如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象。

GCD

任务执行方式

同步执行:

只能在当前线程中执行任务,不具备开启新线程的能力,任务立刻马上执行,会阻塞当前线程并等待 Block中的任务执行完毕,然后当前线程才会继续往下运行

异步执行:

可以在新的线程中执行任务,具备开启新线程的能力,但不一定会开新线程,当前线程会直接往下执行,不会阻塞当前线程

队列:

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

串行队列(Serial Dispatch Queue)

让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

并发队列(Concurrent Dispatch Queue)

可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务),并发功能只有在异步(dispatch_async)函数下才有效

GCD的使用

队列的创建

创建并发队列

dispatch_queue_t queue = dispatch_queue_create("com.xxcc", DISPATCH_QUEUE_CONCURRENT);

GCD默认已经提供了全局并发队列

dispatch_queue_t quque1 =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

创建串行队列

dispatch_queue_t queue = dispatch_queue_create("com.xxcc", DISPATCH_QUEUE_SERIAL);

获得主队列

1
dispatch_queue_t  queue = dispatch_get_main_queue();

任务的执行

队列在queue中,任务在block块中

同步函数:要求立刻马上开始执行

/*
第一个参数:队列
第二个参数:block,在里面封装任务
*/
dispatch_sync(queue, ^{

});

异步函数 :等主线程执行完毕之后,回过头开线程执行任务

dispatch_async(queue, ^{

});

GCD的使用

六种组合使用

  1. 并发队列 + 同步执行: 无新线程,串行执行

  2. 并发队列 + 异步执行:有新线程,并发执行

  3. 串行队列 + 同步执行: 无新线程,串行执行

  4. 串行队列 + 异步执行:有1条新线程,并发执行

  5. 主队列 + 同步执行: 无新线程,串行执行

  6. 主队列 + 异步执行: 无新线程,串行执行

并发队列 + 同步执行

  1. 所有任务都是在主线程中执行的,不会开启新线程,由于只有一个线程,所以任务只能一个一个执行。

  2. 所有任务都在打印的syncConcurrent—begin和syncConcurrent—end之间,这说明任务是添加到队列中马上执行的。

- (void) syncConcurrent
{
    NSLog(@"syncConcurrent---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(@"syncConcurrent---end");
}

2016-10-04 12:28:52.933 FL_GCD_DEMO[6892:714486] syncConcurrent---begin
2016-10-04 12:28:52.933 FL_GCD_DEMO[6892:714486] 1------<NSThread: 0x61800006d8c0>{number = 1, name = main}
2016-10-04 12:28:52.934 FL_GCD_DEMO[6892:714486] 1------<NSThread: 0x61800006d8c0>{number = 1, name = main}
2016-10-04 12:28:52.934 FL_GCD_DEMO[6892:714486] 2------<NSThread: 0x61800006d8c0>{number = 1, name = main}
2016-10-04 12:28:52.934 FL_GCD_DEMO[6892:714486] 2------<NSThread: 0x61800006d8c0>{number = 1, name = main}
2016-10-04 12:28:52.934 FL_GCD_DEMO[6892:714486] 3------<NSThread: 0x61800006d8c0>{number = 1, name = main}
2016-10-04 12:28:52.934 FL_GCD_DEMO[6892:714486] 3------<NSThread: 0x61800006d8c0>{number = 1, name = main}
2016-10-04 12:28:52.935 FL_GCD_DEMO[6892:714486] syncConcurrent---end

并发队列 + 异步执行

  1. 除了主线程,又开启了3个线程,并且任务是交替着同时执行的。

  2. 所有任务是在打印的syncConcurrent—begin和syncConcurrent—end之后才开始执行的。说明任务不是马上执行,而是将所有任务添加到队列之后才开始同步执行。

- (void) asyncConcurrent
{
    NSLog(@"asyncConcurrent---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(@"asyncConcurrent---end");
}

2016-10-04 12:41:45.567 FL_GCD_DEMO[7091:747862] asyncConcurrent---begin
2016-10-04 12:41:45.568 FL_GCD_DEMO[7091:747862] asyncConcurrent---end
2016-10-04 12:41:45.568 FL_GCD_DEMO[7091:747987] 1------<NSThread: 0x610000071900>{number = 3, name = (null)}
2016-10-04 12:41:45.568 FL_GCD_DEMO[7091:747986] 2------<NSThread: 0x60000006f380>{number = 4, name = (null)}
2016-10-04 12:41:45.568 FL_GCD_DEMO[7091:747989] 3------<NSThread: 0x60800006f800>{number = 5, name = (null)}
2016-10-04 12:41:45.568 FL_GCD_DEMO[7091:747987] 1------<NSThread: 0x610000071900>{number = 3, name = (null)}
2016-10-04 12:41:45.568 FL_GCD_DEMO[7091:747986] 2------<NSThread: 0x60000006f380>{number = 4, name = (null)}
2016-10-04 12:41:45.568 FL_GCD_DEMO[7091:747989] 3------<NSThread: 0x60800006f800>{number = 5, name = (null)}

串行队列 + 同步执行

  1. 不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务

  2. 所有任务是在打印的syncConcurrent—begin和syncConcurrent—end之后才开始执行的。说明任务不是马上执行,而是将所有任务添加到队列之后才开始同步执行。

- (void) syncSerial
{
    NSLog(@"syncSerial---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(@"syncSerial---end");
}

2016-10-04 12:46:10.354 FL_GCD_DEMO[7152:759077] syncSerial---begin
2016-10-04 12:46:10.355 FL_GCD_DEMO[7152:759077] 1------<NSThread: 0x60800007b580>{number = 1, name = main}
2016-10-04 12:46:10.355 FL_GCD_DEMO[7152:759077] 1------<NSThread: 0x60800007b580>{number = 1, name = main}
2016-10-04 12:46:10.355 FL_GCD_DEMO[7152:759077] 2------<NSThread: 0x60800007b580>{number = 1, name = main}
2016-10-04 12:46:10.355 FL_GCD_DEMO[7152:759077] 2------<NSThread: 0x60800007b580>{number = 1, name = main}
2016-10-04 12:46:10.355 FL_GCD_DEMO[7152:759077] 3------<NSThread: 0x60800007b580>{number = 1, name = main}
2016-10-04 12:46:10.356 FL_GCD_DEMO[7152:759077] 3------<NSThread: 0x60800007b580>{number = 1, name = main}
2016-10-04 12:46:10.356 FL_GCD_DEMO[7152:759077] syncSerial---end

串行队列 + 异步执行

  1. 会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务

  2. 所有任务是在打印的syncConcurrent—begin和syncConcurrent—end之后才开始执行的。说明任务不是马上执行,而是将所有任务添加到队列之后才开始同步执行。

- (void) asyncSerial
{
    NSLog(@"asyncSerial---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(@"asyncSerial---end");
}

2016-10-04 15:22:49.819 FL_GCD_DEMO[8557:1007533] asyncSerial---begin
2016-10-04 15:22:49.819 FL_GCD_DEMO[8557:1007533] asyncSerial---end
2016-10-04 15:22:49.819 FL_GCD_DEMO[8557:1007620] 1------<NSThread: 0x610000068940>{number = 3, name = (null)}
2016-10-04 15:22:49.820 FL_GCD_DEMO[8557:1007620] 1------<NSThread: 0x610000068940>{number = 3, name = (null)}
2016-10-04 15:22:49.820 FL_GCD_DEMO[8557:1007620] 2------<NSThread: 0x610000068940>{number = 3, name = (null)}
2016-10-04 15:22:49.820 FL_GCD_DEMO[8557:1007620] 2------<NSThread: 0x610000068940>{number = 3, name = (null)}
2016-10-04 15:22:49.820 FL_GCD_DEMO[8557:1007620] 3------<NSThread: 0x610000068940>{number = 3, name = (null)}
2016-10-04 15:22:49.820 FL_GCD_DEMO[8557:1007620] 3------<NSThread: 0x610000068940>{number = 3, name = (null)}

主队列 + 同步执行

- (void)syncMain
{
    NSLog(@"syncMain---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(@"syncMain---end");
}

互等卡住不可行(在主线程中调用),dispatch_sync需要立即执行,而现在正在执行syncMain,除非将syncMain放到其他线程

dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
    [self syncMain];
});

主队列 + 异步执行

- (void)asyncMain
{
    NSLog(@"asyncMain---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(@"asyncMain---end");
}

2016-10-04 16:09:35.551 FL_GCD_DEMO[9244:1128884] 1------<NSThread: 0x618000078700>{number = 1, name = main}
2016-10-04 16:09:35.551 FL_GCD_DEMO[9244:1128884] 1------<NSThread: 0x618000078700>{number = 1, name = main}
2016-10-04 16:09:35.552 FL_GCD_DEMO[9244:1128884] 2------<NSThread: 0x618000078700>{number = 1, name = main}
2016-10-04 16:09:35.552 FL_GCD_DEMO[9244:1128884] 2------<NSThread: 0x618000078700>{number = 1, name = main}
2016-10-04 16:09:35.552 FL_GCD_DEMO[9244:1128884] 3------<NSThread: 0x618000078700>{number = 1, name = main}
2016-10-04 16:09:35.552 FL_GCD_DEMO[9244:1128884] 3------<NSThread: 0x618000078700>{number = 1, name = main}

其他线程中返回到主线程

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    for (int i = 0; i < 2; ++i) {
        NSLog(@"1------%@",[NSThread currentThread]);
    }

    // 回到主线程
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"2-------%@",[NSThread currentThread]);
    });
});

栅栏方法 dispatch_barrier_async

异步执行两组操作,而且第一组操作执行完之后,才能开始执行第二组操作。这样我们就需要一个相当于栅栏一样的一个方法将两组异步执行的操作组给分割起来,当然这里的操作组里可以包含一个或多个任务。这就需要用到dispatch_barrier_async方法在两个操作组间形成栅栏。

- (void)barrier
{
    dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"----1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----2-----%@", [NSThread currentThread]);
    });

    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"----3-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----4-----%@", [NSThread currentThread]);
    });
}

2016-10-04 16:23:38.931 FL_GCD_DEMO[9572:1168918] ----1-----<NSThread: 0x60000006e280>{number = 3, name = (null)}
2016-10-04 16:23:38.931 FL_GCD_DEMO[9572:1168921] ----2-----<NSThread: 0x60000006e240>{number = 4, name = (null)}
2016-10-04 16:23:38.932 FL_GCD_DEMO[9572:1168921] ----barrier-----<NSThread: 0x60000006e240>{number = 4, name = (null)}
2016-10-04 16:23:38.932 FL_GCD_DEMO[9572:1168921] ----3-----<NSThread: 0x60000006e240>{number = 4, name = (null)}
2016-10-04 16:23:38.932 FL_GCD_DEMO[9572:1168918] ----4-----<NSThread: 0x60000006e280>{number = 3, name = (null)}

延时执行方法 dispatch_after

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // 2秒后异步执行这里的代码...
NSLog(@"run-----");
});

一次性代码 dispatch_once

使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1次。

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 只执行1次的代码(这里面默认是线程安全的)
});

多线程同时遍历 dispatch_apply

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(6, queue, ^(size_t index) {
    NSLog(@"%zd------%@",index, [NSThread currentThread]);
});

2016-10-04 16:30:58.280 FL_GCD_DEMO[9720:1191743] 1------<NSThread: 0x610000067840>{number = 3, name = (null)}
2016-10-04 16:30:58.280 FL_GCD_DEMO[9720:1191746] 3------<NSThread: 0x610000067800>{number = 5, name = (null)}
2016-10-04 16:30:58.280 FL_GCD_DEMO[9720:1191744] 2------<NSThread: 0x60000006a200>{number = 4, name = (null)}
2016-10-04 16:30:58.280 FL_GCD_DEMO[9720:1191661] 0------<NSThread: 0x610000060e80>{number = 1, name = main}
2016-10-04 16:30:58.280 FL_GCD_DEMO[9720:1191762] 4------<NSThread: 0x610000067880>{number = 6, name = (null)}
2016-10-04 16:30:58.280 FL_GCD_DEMO[9720:1191763] 5------<NSThread: 0x610000067b00>{number = 7, name = (null)}

队列组 dispatch_group

分别异步执行2个耗时操作,然后当2个耗时操作都执行完毕后再回到主线程执行操作。

-(void)testGroupQueue
{
        NSLog(@"用户想要登录");

        dispatch_group_t group = dispatch_group_create();

        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            sleep(1);
            NSLog(@"填写账号完成");
        });
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            sleep(1);
            NSLog(@"填写密码完成");
        });

        dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            NSLog(@"用户可以登录了");
        });
}

2016-02-26 13:22:09.973 FL_GCD_DEMO[5494:3812823] 用户想要登录
2016-02-26 13:22:10.978 FL_GCD_DEMO[5494:3812859] 填写密码完成
2016-02-26 13:22:10.978 FL_GCD_DEMO[5494:3812860] 填写账号完成
2016-02-26 13:22:10.978 FL_GCD_DEMO[5494:3812860] 用户可以登录了

Suspend和Resume

有时可能需要我们中断某些操作,还需要我们恢复执行,这个时候就可以用到suspend和resume操作.

suspend不会停止当当前正在执行的block,而是中断了后面未执行的,在resume之后再执行后面的block

-(void)testSuspendAndResume
{
    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"start");
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:5];
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:5];
        NSLog(@"2");
    });

    [NSThread sleepForTimeInterval:3];
    NSLog(@"suspend");
    dispatch_suspend(queue);
    [NSThread sleepForTimeInterval:5];
    NSLog(@"resume");
    dispatch_resume(queue);
}

2016-02-25 22:01:02.475 FL_GCD_DEMO[4890:3722720] start
2016-02-25 22:01:05.476 FL_GCD_DEMO[4890:3722720] suspend
2016-02-25 22:01:07.479 FL_GCD_DEMO[4890:3722759] 1
2016-02-25 22:01:10.478 FL_GCD_DEMO[4890:3722720] resume
2016-02-25 22:01:15.478 FL_GCD_DEMO[4890:3722759] 2

dispatch_semaphore

-(void)testSemaphore
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i = 0; i <10; i++)
    {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_async(queue, ^{
            NSLog(@"下载资源:%i",i);
            sleep(2);
            dispatch_semaphore_signal(semaphore);
        });
    }
}

2016-02-26 14:04:33.392 FL_GCD_DEMO[5713:3848434] 下载资源:1
2016-02-26 14:04:33.392 FL_GCD_DEMO[5713:3848431] 下载资源:0
2016-02-26 14:04:35.397 FL_GCD_DEMO[5713:3848434] 下载资源:2
2016-02-26 14:04:35.397 FL_GCD_DEMO[5713:3848431] 下载资源:3
2016-02-26 14:04:37.400 FL_GCD_DEMO[5713:3848434] 下载资源:5
2016-02-26 14:04:37.400 FL_GCD_DEMO[5713:3848431] 下载资源:4
2016-02-26 14:04:39.401 FL_GCD_DEMO[5713:3848431] 下载资源:6
2016-02-26 14:04:39.401 FL_GCD_DEMO[5713:3848434] 下载资源:7
2016-02-26 14:04:41.406 FL_GCD_DEMO[5713:3848434] 下载资源:9
2016-02-26 14:04:41.406 FL_GCD_DEMO[5713:3848431] 下载资源:8

说明:dispatch_semaphore_create(2)创建了一个单位为2的信号量
dispatch_semaphore_wait()会消耗一个单位
ispatch_semaphore_signal()会增加一个单位
而dispatch_semaphore_create(2)中传入的“2”决定了这个信号量最多包含2个单位。
dispatch_semaphore_wait()中的参数2DISPATCH_TIME_FOREVER表示当信号量单位变为0个,则使得代码的执行停止在当前位置不再继续下去,直到收到signal使得单位大于0,才继续往下执行。
在上述代码中,每执行一次下载会占用一个单位,下载完成后通过signal告诉wait可以继续向下执行代码,从而控制同时进行的下载数量。

GCD in Swift 3

获取全局队列

DispatchQueue.global(qos: DispatchQoS.*)

DispatchQueue.global(qos: .userInitiated).async {
print("user initiated task")
}

DISPATCH_QUEUE_PRIORITY_HIGH    .userInitiated
DISPATCH_QUEUE_PRIORITY_DEFAULT    .default
DISPATCH_QUEUE_PRIORITY_LOW    .utility
DISPATCH_QUEUE_PRIORITY_BACKGROUND    .background

创建队列

let queue = DispatchQueue(label: "Kenneth")

let conQueue = DispatchQueue(label: "Kenneth", attributes: .concurrent)

let backgroundQueue = DispatchQueue(label: "com.app.queue",
                                qos: .background, 
                                target: nil)

同步任务

let queue = DispatchQueue(label: "Kenneth")
queue.sync {
    print("Hello World")
}

异步任务

let queue = DispatchQueue(label: "Kenneth")
queue.async {
    print("Hello World")
}

全局队列异步

DispatchQueue.global().async {
    //Something that wastes time
    DispatchQueue.main.async {
    //返回主线程
    }
}

延时操作

注意这里的单位是秒

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.5) {
    // 你想做啥
}

dispatch_once

dispatch_once 在 OC 时代是一个用来写单例的很好的工具,它保证任务只执行一次。然而在 Swift 3 中,这个函数被删除了。
在 Swift 中,好用又简洁的单例请使用 static let。

DispatchWorkItem

除了直接使用 Global Queue, 还可以定义 DispatchWorkItem。 DispatchWorkItem 定义了一个操作的内部代码,以及优先级,特性等等。 它可以直接在任何队列中执行:

let queue = DispatchQueue(label: "swift.queue")
let workItem = DispatchWorkItem(qos: .userInitiated, flags: .assignCurrentContext) { 

}
queue.async(execute: workItem)

You can also use same block of code many times by wrapping it in DispatchWorkItem instance and passing it to DispatchQueue

let block = DispatchWorkItem {
    print("do something")
}
DispatchQueue.main.async(execute: block)
  1. iOS多线程–彻底学会多线程之GCD
  2. GCD(Grand Central Dispatch)快速上手
  3. GCD in Swift 3
  4. GCD for Swift