美文网首页
线程之GCD

线程之GCD

作者: zcz朝 | 来源:发表于2017-01-24 16:30 被阅读0次

    今天看了看线程,发现自己对线程还不是很了解,于是练了练手算是学习学习,iOS中线程一共分为四种:Pthread,NSThread,GCD 和 NSOperation.
    Pthread基本不用,很多系统中都支持,iOS中也支持.但是基本不用.

    NSThread我还很菜,也许是我知道的不多,我所知道的确实不难,具体有啥,在Xcode中点进去看看里面的属性和方法一目了然,这里多说一句在swift中,Thread取消了Perform.......的自启动方法.

    GCD:根据目前本菜鸟所学,需要注意的关键点为队列(queue),任务,组(group).队列分串行队列(DISPATCH_QUEUE_SERIAL)和并行队列(DISPATCH_QUEUE_CONCURRENT) 任务分为同步(sync)和异步(async)

    1.异步执行,并发队列

    - (void)GCDasyncConcurrentThread {
        dispatch_queue_t queue1 = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_async(queue1, ^{
            NSLog(@"%@",[NSThread currentThread]);
    //        NSLog(@"%@",[NSThread currentThread]);
    
            dispatch_async(queue1, ^{
                NSLog(@"zzz%@",[NSThread currentThread]);
            });
            NSLog(@"after1");
        });
        
        dispatch_async(queue1, ^{
            NSLog(@"%@",[NSThread currentThread]);
    //        NSLog(@"%@",[NSThread currentThread]);
    
            dispatch_async(queue1, ^{
                NSLog(@"zzz%@",[NSThread currentThread]);
            });
            NSLog(@"after2");
        });
        
        dispatch_async(queue1, ^{
            NSLog(@"%@",[NSThread currentThread]);
    //        NSLog(@"%@",[NSThread currentThread]);
    
            dispatch_async(queue1, ^{
                NSLog(@"zzz%@",[NSThread currentThread]);
            });
            NSLog(@"after3");
        });
        
        NSLog(@"after");
    } 
    
    2017-01-24 13:15:46.738 GCD学习[3445:112733] <NSThread: 0x6100000711c0>{number = 3, name = (null)}
    2017-01-24 13:15:46.738 GCD学习[3445:112735] <NSThread: 0x61800006be40>{number = 5, name = (null)}
    2017-01-24 13:15:46.738 GCD学习[3445:112732] <NSThread: 0x60000006f640>{number = 4, name = (null)}
    2017-01-24 13:15:46.738 GCD学习[3445:112697] after
    2017-01-24 13:15:46.738 GCD学习[3445:112733] after1
    2017-01-24 13:15:46.738 GCD学习[3445:112761] zzz<NSThread: 0x6080000725c0>{number = 6, name = (null)}
    2017-01-24 13:15:46.738 GCD学习[3445:112735] after3
    2017-01-24 13:15:46.738 GCD学习[3445:112732] after2
    2017-01-24 13:15:46.738 GCD学习[3445:112762] zzz<NSThread: 0x608000072440>{number = 7, name = (null)}
    2017-01-24 13:15:46.738 GCD学习[3445:112763] zzz<NSThread: 0x60000006f580>{number = 8, name = (null)}
    

    并发异步执行,会开启线程,并且队列中线程的执行顺序不确定,多写几个耗时不同的线程会发现,当开启新线程之前会检查当前队列中是否存在闲置线程 ,如果有闲置线程,便用闲置线程执行要执行的操作,如果没有闲置线程便新开一条线程。

    2.异步执行 串行队列

    //GCD 异步执行 串行队列 产生新线程   同一队列只会产生一个线程
    - (void)GCDasyncSrialThread {
        NSLog(@"before");
        dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
        dispatch_async(queue, ^{
            NSLog(@"now:1");
            [NSThread currentThread].name = @"thread1";
            NSLog(@"%@",[NSThread currentThread]);
        });
    
        dispatch_async(queue, ^{
            NSLog(@"now:2");
            NSLog(@"%@",[NSThread currentThread]);
            dispatch_async(queue, ^{
                NSLog(@"now:4");
                NSLog(@"%@",[NSThread currentThread]);
            });
        });
        
        dispatch_async(queue, ^{
            NSLog(@"now:3");
            NSLog(@"%@",[NSThread currentThread]);
        });
        NSLog(@"after");
        NSLog(@"%@",[NSThread currentThread]);
    }
    
    2017-01-24 13:26:12.327 GCD学习[3537:116874] before
    2017-01-24 13:26:12.328 GCD学习[3537:116874] after
    2017-01-24 13:26:12.328 GCD学习[3537:116923] now:1
    2017-01-24 13:26:12.328 GCD学习[3537:116874] <NSThread: 0x6000000682c0>{number = 1, name = main}
    2017-01-24 13:26:12.328 GCD学习[3537:116923] <NSThread: 0x61000006cac0>{number = 3, name = thread1}
    2017-01-24 13:26:12.328 GCD学习[3537:116923] now:2
    2017-01-24 13:26:12.328 GCD学习[3537:116923] <NSThread: 0x61000006cac0>{number = 3, name = thread1}
    2017-01-24 13:26:12.329 GCD学习[3537:116923] now:3
    2017-01-24 13:26:12.329 GCD学习[3537:116923] <NSThread: 0x61000006cac0>{number = 3, name = thread1}
    2017-01-24 13:26:12.329 GCD学习[3537:116923] now:4
    2017-01-24 13:26:12.329 GCD学习[3537:116923] <NSThread: 0x61000006cac0>{number = 3, name = thread1}
    

    一个串行队列中执行异步操作只会产生一个子线程,并且所有执行的异步操作先进入队列的先操作,后进入队列的后操作。此处now4实在子线程中开辟一条新线程,如果将now4的异步(async)改为同步(sync)程序会崩溃,产生线程阻塞,同步执行不会产生新线程,后面后提到.

    3.同步执行 串行队列

    //GCD 同步执行 串行队列 不产生新线程   线程阻塞
    - (void)GCDsyncSrialThread {
        dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
        NSLog(@"before");
        dispatch_sync(queue, ^{
            
            NSLog(@"now1");
            [NSThread currentThread].name = @"thread1";
            NSLog(@"%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            
    //        dispatch_sync(queue, ^{
    //            NSLog(@"now4");
    //            NSLog(@"%@",[NSThread currentThread]);
    //        });
            
            NSLog(@"now2");
            NSLog(@"%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"now3");
            NSLog(@"%@",[NSThread currentThread]);
        });
        NSLog(@"after");
    }
    
    2017-01-24 13:48:36.036 GCD学习[3729:125159] before
    2017-01-24 13:48:36.036 GCD学习[3729:125159] now1
    2017-01-24 13:48:36.036 GCD学习[3729:125159] <NSThread: 0x6000000778c0>{number = 1, name = thread1}
    2017-01-24 13:48:36.036 GCD学习[3729:125159] now2
    2017-01-24 13:48:36.036 GCD学习[3729:125159] <NSThread: 0x6000000778c0>{number = 1, name = thread1}
    2017-01-24 13:48:36.037 GCD学习[3729:125159] now3
    2017-01-24 13:48:36.037 GCD学习[3729:125159] <NSThread: 0x6000000778c0>{number = 1, name = thread1}
    2017-01-24 13:48:36.037 GCD学习[3729:125159] after
    

    串行队列中同步执行任务,不会产生新的子线程,并且执行顺序为先进入队列的任务先执行,后进入队列的后执行,前一个任务未完成不会进入后一个任务,所以上面代码中被注掉的部分打开运行时会卡在此处,产生线程阻塞.原因是因为在队列中,now4加入队列需要等待now2线程执行完才能进行,而now2中后面的语句执行要在now4执行后执行,这是互相等待都不执行就产生了线程阻塞.将now4的同步(sync)改为异步(async)就可以解决线程阻塞问题.但在实际开发中问题的解决并非这么简单,要考虑实际情况以及任务执行顺序.上面提到的线程阻塞也是相互等待产生的问题

    4.同步执行 并行队列

    //GCD 同步执行 并行队列 不产生新线程
    - (void)GCDsyncConcurrentThread {
        dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
        
        NSLog(@"before");
        dispatch_sync(queue, ^{
            [NSThread currentThread].name = @"thread1";
            NSLog(@"now:1");
            NSLog(@"%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"now:2");
            NSLog(@"%@",[NSThread currentThread]);
            
            dispatch_sync(queue, ^{
                NSLog(@"now:4");
                NSLog(@"%@",[NSThread currentThread]);
            });
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"now:3");
            NSLog(@"%@",[NSThread currentThread]);
        });
        NSLog(@"after");
        NSLog(@"%@",[NSThread currentThread]);
    }
    
    2017-01-24 14:03:28.900 GCD学习[3904:132214] before
    2017-01-24 14:03:28.900 GCD学习[3904:132214] now:1
    2017-01-24 14:03:28.900 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}
    2017-01-24 14:03:28.900 GCD学习[3904:132214] now:2
    2017-01-24 14:03:28.900 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}
    2017-01-24 14:03:28.901 GCD学习[3904:132214] now:4
    2017-01-24 14:03:28.901 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}
    2017-01-24 14:03:28.901 GCD学习[3904:132214] now:3
    2017-01-24 14:03:28.901 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}
    2017-01-24 14:03:28.901 GCD学习[3904:132214] after
    2017-01-24 14:03:28.901 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}
    

    并行队列 同步执行不会产生新线程, 所有任务按代码顺序执行,在并同步任务中添加同步任务,可以在上层任务未完成时执行内部任务,可以想象为遇到什么事情 就解决什么事,不分进入队列时间,一切按执行过程走.

    5.GCD 队列组

    //GCD 队列组
    - (void)GCDgroup{
        dispatch_group_t group = dispatch_group_create();
        
        dispatch_queue_t queue1 = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_queue_t queue2 = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_queue_t queue3 = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
    
        dispatch_group_async(group, queue1, ^{
            NSLog(@"1");
        });
        dispatch_group_async(group, queue2, ^{
            NSLog(@"2");
        });
        dispatch_group_async(group, queue2, ^{
            NSLog(@"3");
        });
        dispatch_group_async(group, queue1, ^{
            NSLog(@"4");
        });
        dispatch_group_async(group, queue1, ^{
            NSLog(@"5");
        });
        dispatch_group_async(group, queue2, ^{
            NSLog(@"6");
        });
        dispatch_group_async(group, queue2, ^{
            NSLog(@"7");
        });
        dispatch_group_async(group, queue3, ^{
            NSLog(@"8");
        });
        dispatch_group_async(group, queue3, ^{
            NSLog(@"9");
        });
        dispatch_group_notify(group, queue1, ^{
            NSLog(@"wan");
        });
    }
    
    2017-01-24 15:01:17.948 GCD学习[4371:151987] 2
    2017-01-24 15:01:17.948 GCD学习[4371:151971] 1
    2017-01-24 15:01:17.948 GCD学习[4371:151972] 8
    2017-01-24 15:01:17.948 GCD学习[4371:151974] 4
    2017-01-24 15:01:17.948 GCD学习[4371:151990] 3
    2017-01-24 15:01:17.948 GCD学习[4371:151991] 5
    2017-01-24 15:01:17.948 GCD学习[4371:151992] 6
    2017-01-24 15:01:17.949 GCD学习[4371:151993] 7
    2017-01-24 15:01:17.949 GCD学习[4371:151987] 9
    2017-01-24 15:01:17.949 GCD学习[4371:151993] wan
    

    队列组中装的是队列,组中所有队列执行结束会执行dispatch_group_notify(<#dispatch_group_t _Nonnull group#>, <#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)

    队列组中还有一些其他的API,如
    dispatch_group_enter(dispatch_group_t group);在组内加入执行代码块 与leave要同时出现 不然会crash.
    dispatch_group_leave(dispatch_group_t group);
    dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);检查组内任务多久之后是否完成是否完成,如果完成,返回值为0,否则不为0如:
    dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5*NSEC_PER_SEC));设定等待5秒,观察五秒后是否组内任务全部完成,如果未完成继续执行组内任务 返回非0数继续执行,如果在5秒内完成则返回0,继续后续执行.所以此API无论返回什么,并不影响程序运行.
    dispatch_apply API是sync与group的关联,将block中的执行加入到queue中关联一个组. iterations重复次数,queue队列,和带残block,index为每次任务标号,无序执行.可无序遍历容器类.

    dispatch_apply(10, queue3, ^(size_t index) {
            
        });```
    还有dispatch_after 延迟操作,延迟多久在哪个队列中执行什么操作.
    dispatch_once 只执行一次的操作,可用于单例.在类方法中
    

    static Class class = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    class = [[Class alloc]init];
    });
    return class;

    还有另外一种单例写法,和两种的严格与不严格形式,啥时候有遇到相关内容再带一下吧.都很简单.
    GCD功能无比强大,脑洞打开后,拥有无限可能.学的很肤浅,技术还很渣,仍需努力,继续革命.
    第二篇渣文出炉.

    相关文章

      网友评论

          本文标题:线程之GCD

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