美文网首页多线程 & 网络
iOS多线程:GCD进阶篇

iOS多线程:GCD进阶篇

作者: 码小菜 | 来源:发表于2020-04-12 23:37 被阅读0次
    别墅

    目录
    一,dispatch_after
    二,dispatch_once
    三,dispatch_apply
    四,dispatch_group
    五,dispatch_semaphore
    六,dispatch_barrier

    一,dispatch_after

    1,使用

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSLog(@"1");
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"2");
        });
        
        NSLog(@"3");
    }
    
    // 打印
    07:04:14.185538+0800 Demo[82191:12753573] 1
    07:04:14.186943+0800 Demo[82191:12753573] 3
    07:04:17.185982+0800 Demo[82191:12753573] 2
    

    2,说明

    • 它的作用是延迟执行任务

    • 并不是在指定时间开始执行任务,而是在指定时间将任务添加到队列中

    • 因为队列可能会出现阻塞的情况,所以任务的执行时间不一定准确

    二,dispatch_once

    1,使用

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        for (int i = 0; i < 5; i++) {
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                NSLog(@"%d", i + 1);
            });
        }
    }
    
    // 打印
    1
    

    2,说明

    • 它的作用是保证任务只执行一次

    • 它能够保证任务的执行是线程安全的

    • 它常应用于单例模式

    三,dispatch_apply

    1,使用

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSLog(@"begin");
        
        NSArray *array = @[@"1", @"2", @"3"];
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        dispatch_apply(array.count, queue, ^(size_t index) {
            NSLog(@"%@---%@", array[index], [NSThread currentThread]);
        });
        
        NSLog(@"end");
    }
    
    // 打印
    begin
    2---<NSThread: 0x6000019498c0>{number = 3, name = (null)}
    3---<NSThread: 0x60000194a080>{number = 4, name = (null)}
    1---<NSThread: 0x600001916100>{number = 1, name = main}
    end
    

    2,说明

    • 它的作用是快速遍历一组数据,类似于for循环

    • for循环是逐个进行遍历,而它能够在多个线程中同时遍历多个数据

    • 它按指定的次数将任务添加到队列中,并等待所有的任务执行完毕才返回

    四,dispatch_group

    1,使用

    • dispatch_group_notify
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSLog(@"begin---%@", [NSThread currentThread]);
        
        dispatch_group_t group = dispatch_group_create();
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
        dispatch_group_async(group, queue, ^{
            NSLog(@"任务1---%@", [NSThread currentThread]);
            sleep(1.0);
        });
    
        dispatch_group_async(group, queue, ^{
            NSLog(@"任务2---%@", [NSThread currentThread]);
            sleep(1.0);
        });
    
        dispatch_group_async(group, queue, ^{
            NSLog(@"任务3---%@", [NSThread currentThread]);
            sleep(1.0);
        });
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"group中的任务都已经执行完毕---%@", [NSThread currentThread]);
        });
        
        NSLog(@"end---%@", [NSThread currentThread]);
    }
    
    // 打印
    begin---<NSThread: 0x60000289e800>{number = 1, name = main}
    end---<NSThread: 0x60000289e800>{number = 1, name = main}
    任务1---<NSThread: 0x6000028cc980>{number = 4, name = (null)}
    任务3---<NSThread: 0x6000028c6040>{number = 3, name = (null)}
    任务2---<NSThread: 0x6000028c2100>{number = 5, name = (null)}
    group中的任务都已经执行完毕---<NSThread: 0x60000289e800>{number = 1, name = main}
    
    • dispatch_group_wait
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSLog(@"begin---%@", [NSThread currentThread]);
        
        dispatch_group_t group = dispatch_group_create();
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
        dispatch_group_async(group, queue, ^{
            NSLog(@"任务1---%@", [NSThread currentThread]);
            sleep(1.0);
        });
    
        dispatch_group_async(group, queue, ^{
            NSLog(@"任务2---%@", [NSThread currentThread]);
            sleep(1.0);
        });
    
        dispatch_group_async(group, queue, ^{
            NSLog(@"任务3---%@", [NSThread currentThread]);
            sleep(1.0);
        });
    
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        NSLog(@"group中的任务都已经执行完毕---%@", [NSThread currentThread]);
        
        NSLog(@"end---%@", [NSThread currentThread]);
    }
    
    // 打印
    begin---<NSThread: 0x6000029fcbc0>{number = 1, name = main}
    任务2---<NSThread: 0x6000029a1780>{number = 6, name = (null)}
    任务1---<NSThread: 0x60000298d400>{number = 7, name = (null)}
    任务3---<NSThread: 0x6000029b3b40>{number = 4, name = (null)}
    group中的任务都已经执行完毕---<NSThread: 0x6000029fcbc0>{number = 1, name = main}
    end---<NSThread: 0x6000029fcbc0>{number = 1, name = main}
    
    • dispatch_group_enterdispatch_group_leave
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSLog(@"begin---%@", [NSThread currentThread]);
        
        dispatch_group_t group = dispatch_group_create();
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
        // group中的任务数+1
        dispatch_group_enter(group);
        dispatch_async(queue, ^{
            NSLog(@"任务1---%@", [NSThread currentThread]);
            sleep(1.0);
            // group中的任务数-1
            dispatch_group_leave(group);
        });
    
        // group中的任务数+1
        dispatch_group_enter(group);
        dispatch_async(queue, ^{
            NSLog(@"任务2---%@", [NSThread currentThread]);
            sleep(1.0);
            // group中的任务数-1
            dispatch_group_leave(group);
        });
    
        // group中的任务数+1
        dispatch_group_enter(group);
        dispatch_async(queue, ^{
            NSLog(@"任务3---%@", [NSThread currentThread]);
            sleep(1.0);
            // group中的任务数-1
            dispatch_group_leave(group);
        });
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"group中的任务数为0---%@", [NSThread currentThread]);
        });
        
        NSLog(@"end---%@", [NSThread currentThread]);
    }
    
    // 打印
    begin---<NSThread: 0x600002d960c0>{number = 1, name = main}
    end---<NSThread: 0x600002d960c0>{number = 1, name = main}
    任务1---<NSThread: 0x600002dfb100>{number = 7, name = (null)}
    任务3---<NSThread: 0x600002ddbc40>{number = 4, name = (null)}
    任务2---<NSThread: 0x600002dc3400>{number = 5, name = (null)}
    group中的任务数为0---<NSThread: 0x600002d960c0>{number = 1, name = main}
    

    2,说明

    • dispatch_group_wait会阻塞当前线程

    • dispatch_group_enterdispatch_group_leave的作用等同于dispatch_group_async

    • 它常应用于多个接口都请求完毕后再刷新UI

    五,dispatch_semaphore

    1,使用

    • 将异步执行任务转换为同步执行任务
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSLog(@"1---%@", [NSThread currentThread]);
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            sleep(1.0);
            NSLog(@"2---%@", [NSThread currentThread]);
            dispatch_semaphore_signal(semaphore);
        });
    
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"3---%@", [NSThread currentThread]);
    }
    
    // 打印
    1---<NSThread: 0x600002491080>{number = 1, name = main}
    2---<NSThread: 0x6000024c0e80>{number = 5, name = (null)}
    3---<NSThread: 0x600002491080>{number = 1, name = main}
    
    • 控制线程的最大并发数
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 最大并发数为2
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
    
        for (int i = 0; i < 10; i++) {
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
                sleep(1.0);
                NSLog(@"%d---%@", i + 1, [NSThread currentThread]);
    
                dispatch_semaphore_signal(semaphore);
            });
        }
    }
    
    // 打印(同时只打印两次)
    06:43:09.900220+0800 Demo[26085:16867256] 1---<NSThread: 0x6000006e2140>{number = 6, name = (null)}
    06:43:09.900238+0800 Demo[26085:16867255] 2---<NSThread: 0x6000006fff80>{number = 5, name = (null)}
    06:43:10.903011+0800 Demo[26085:16867239] 3---<NSThread: 0x6000006e7900>{number = 3, name = (null)}
    06:43:10.903022+0800 Demo[26085:16867243] 4---<NSThread: 0x6000006c7c40>{number = 8, name = (null)}
    06:43:11.906306+0800 Demo[26085:16867240] 5---<NSThread: 0x6000006b8600>{number = 4, name = (null)}
    06:43:11.906350+0800 Demo[26085:16867259] 6---<NSThread: 0x6000006c7f40>{number = 9, name = (null)}
    06:43:12.907370+0800 Demo[26085:16867261] 7---<NSThread: 0x6000006c7f80>{number = 11, name = (null)}
    06:43:12.907366+0800 Demo[26085:16867260] 8---<NSThread: 0x6000006cf140>{number = 10, name = (null)}
    06:43:13.912833+0800 Demo[26085:16867262] 9---<NSThread: 0x6000006c7d00>{number = 13, name = (null)}
    06:43:13.912925+0800 Demo[26085:16867263] 10---<NSThread: 0x6000006caac0>{number = 12, name = (null)}
    
    • 把初始值设置为1,代表同一时间只允许一个线程访问资源,这样它就能起到锁的作用
    @interface ViewController ()
    @property (nonatomic, assign) int ticket;
    @property (nonatomic, strong) dispatch_semaphore_t semaphore;
    @end
    
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.ticket = 10;
        self.semaphore = dispatch_semaphore_create(1);
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        dispatch_async(queue, ^{
            for (int i = 0; i < 5; i++) {
                [self saleTicket];
            }
        });
        
        dispatch_async(queue, ^{
            for (int i = 0; i < 5; i++) {
                [self saleTicket];
            }
        });
    }
    - (void)saleTicket {
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
        
        int oldTicket = self.ticket;
        sleep(0.3);
        oldTicket -= 1;
        self.ticket = oldTicket;
        NSLog(@"剩余%d张票---%@", self.ticket, [NSThread currentThread]);
        
        dispatch_semaphore_signal(self.semaphore);
    }
    @end
    
    // 打印
    剩余9张票---<NSThread: 0x60000324a980>{number = 3, name = (null)}
    剩余8张票---<NSThread: 0x600003253b80>{number = 5, name = (null)}
    剩余7张票---<NSThread: 0x60000324a980>{number = 3, name = (null)}
    剩余6张票---<NSThread: 0x600003253b80>{number = 5, name = (null)}
    剩余5张票---<NSThread: 0x60000324a980>{number = 3, name = (null)}
    剩余4张票---<NSThread: 0x600003253b80>{number = 5, name = (null)}
    剩余3张票---<NSThread: 0x60000324a980>{number = 3, name = (null)}
    剩余2张票---<NSThread: 0x600003253b80>{number = 5, name = (null)}
    剩余1张票---<NSThread: 0x60000324a980>{number = 3, name = (null)}
    剩余0张票---<NSThread: 0x600003253b80>{number = 5, name = (null)}
    

    2,说明

    • dispatch_semaphore_wait

    1>如果信号量的值大于0,就将值-1并往下执行

    2>如果信号量的值等于0,就让线程休眠并等待信号

    3>收到信号后会唤醒线程并重新判断信号量的值

    • dispatch_semaphore_signal

    将信号量的值+1并发送信号

    六,dispatch_barrier

    1,使用

    • dispatch_barrier_async
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSLog(@"begin---%@", [NSThread currentThread]);
        __block int data = 99;
        dispatch_queue_t queue = dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_async(queue, ^{
            sleep(1.0);
            NSLog(@"读1---%d---%@", data, [NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            sleep(1.0);
            NSLog(@"读2---%d---%@", data, [NSThread currentThread]);
        });
        
        dispatch_barrier_async(queue, ^{
            sleep(1.0);
            data = 100;
            NSLog(@"写---%@", [NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            sleep(1.0);
            NSLog(@"读3---%d---%@", data, [NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            sleep(1.0);
            NSLog(@"读4---%d---%@", data, [NSThread currentThread]);
        });
        
        NSLog(@"end---%@", [NSThread currentThread]);
    }
    
    // 打印
    07:23:15.929766+0800 Demo[34756:17878123] begin---<NSThread: 0x60000392ddc0>{number = 1, name = main}
    07:23:15.930049+0800 Demo[34756:17878123] end---<NSThread: 0x60000392ddc0>{number = 1, name = main}
    07:23:16.932491+0800 Demo[34756:17878203] 读1---99---<NSThread: 0x6000039719c0>{number = 3, name = (null)}
    07:23:16.932491+0800 Demo[34756:17878195] 读2---99---<NSThread: 0x60000396a280>{number = 5, name = (null)}
    07:23:17.938203+0800 Demo[34756:17878195] 写---<NSThread: 0x60000396a280>{number = 5, name = (null)}
    07:23:18.940880+0800 Demo[34756:17878203] 读4---100---<NSThread: 0x6000039719c0>{number = 3, name = (null)}
    07:23:18.940883+0800 Demo[34756:17878195] 读3---100---<NSThread: 0x60000396a280>{number = 5, name = (null)}
    
    • dispatch_barrier_sync
    dispatch_barrier_sync(queue, ^{
        sleep(1.0);
        data = 100;
        NSLog(@"写---%@", [NSThread currentThread]);
    });
    
    // 打印
    07:29:57.114729+0800 Demo[34807:17881597] begin---<NSThread: 0x600003e71580>{number = 1, name = main}
    07:29:58.120079+0800 Demo[34807:17881637] 读1---99---<NSThread: 0x600003e4ed00>{number = 4, name = (null)}
    07:29:58.120099+0800 Demo[34807:17881639] 读2---99---<NSThread: 0x600003e16a80>{number = 7, name = (null)}
    07:29:59.121744+0800 Demo[34807:17881597] 写---<NSThread: 0x600003e71580>{number = 1, name = main}
    07:29:59.122171+0800 Demo[34807:17881597] end---<NSThread: 0x600003e71580>{number = 1, name = main}
    07:30:00.124470+0800 Demo[34807:17881637] 读4---100---<NSThread: 0x600003e4ed00>{number = 4, name = (null)}
    07:30:00.124501+0800 Demo[34807:17881639] 读3---100---<NSThread: 0x600003e16a80>{number = 7, name = (null)}
    
    • dispatch_barrier_async_and_wait
    dispatch_barrier_async_and_wait(queue, ^{
        sleep(1.0);
        data = 100;
        NSLog(@"写---%@", [NSThread currentThread]);
    });
    
    // 打印
    10:20:10.414882+0800 Demo[35536:17905685] begin---<NSThread: 0x60000084ccc0>{number = 1, name = main}
    10:20:11.421195+0800 Demo[35536:17905758] 读2---99---<NSThread: 0x60000080d0c0>{number = 4, name = (null)}
    10:20:11.421212+0800 Demo[35536:17905764] 读1---99---<NSThread: 0x600000813100>{number = 3, name = (null)}
    10:20:12.422726+0800 Demo[35536:17905685] 写---<NSThread: 0x60000084ccc0>{number = 1, name = main}
    10:20:12.423153+0800 Demo[35536:17905685] end---<NSThread: 0x60000084ccc0>{number = 1, name = main}
    10:20:13.423888+0800 Demo[35536:17905758] 读4---100---<NSThread: 0x60000080d0c0>{number = 4, name = (null)}
    10:20:13.423965+0800 Demo[35536:17905764] 读3---100---<NSThread: 0x600000813100>{number = 3, name = (null)}
    

    2,说明

    • 执行顺序

    1>先同时执行在dispatch_barrier函数前添加的任务

    2>再单独执行在dispatch_barrier函数中添加的任务

    3>然后同时执行在dispatch_barrier函数后添加的任务

    • 对比

    1>dispatch_barrier_async:异步执行

    2>dispatch_barrier_sync:同步执行,会阻塞当前线程

    3>dispatch_barrier_async_and_wait:同步执行,会阻塞当前线程

    • 不能用全局并发队列,否则dispatch_barrier会失效

    • 它常应用于“多读单写”的场景

    相关文章

      网友评论

        本文标题:iOS多线程:GCD进阶篇

        本文链接:https://www.haomeiwen.com/subject/kbpbphtx.html