美文网首页
常用的GCD记录一下

常用的GCD记录一下

作者: 温水煮青蛙a | 来源:发表于2018-01-31 14:25 被阅读0次
子线程并行
//GCD开一个子线程
    //系统 并行队列
    //获得全局队列 (并行队列)
    //参数1.设置队列优先级别
    //参数2.系统预留参数设置为0
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(globalQueue, ^{
        NSLog(@"是否是主线程a =0 %d", [NSThread isMainThread]);
        //回到主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            self.view.backgroundColor = [UIColor redColor];
        });
    });
串行 主线程
//GCD串行  主线程
    //串行队列
    //调用系统的主线程实现串行队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    //执行队列任务
    //参数1.设置队列
    dispatch_async(mainQueue, ^{
        NSLog(@"是否是主线程a =1 %d", [NSThread isMainThread]);
    });
    dispatch_async(mainQueue, ^{
        NSLog(@"是否是主线程b =1 %d", [NSThread isMainThread]);
    });
    dispatch_async(mainQueue, ^{
        NSLog(@"是否是主线程c =1 %d", [NSThread isMainThread]);
    });
串行队列 子线程
//自定义串行队列  子线程
    //参数1.队列标识符  (串行队列)
    //参数2.设置队列类型
    dispatch_queue_t serialOueue = dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL);
    ////执行队列任务
    dispatch_async(serialOueue, ^{
        NSLog(@"是否是主线程a =0 %d", [NSThread isMainThread]);
    });
    dispatch_async(serialOueue, ^{
        NSLog(@"是否是主线程b =0 %d", [NSThread isMainThread]);
    });
    dispatch_async(serialOueue, ^{
        NSLog(@"是否是主线程c =0 %d", [NSThread isMainThread]);
    });
并行队列 子线程
//系统 并行队列    子线程
    // 1.创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    // 2.向队列中添加任务
    dispatch_async(queue, ^{  //
        NSLog(@"是否是主线程a =0 %d", [NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"是否是主线程b =0 %d", [NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"是否是主线程c =0 %d", [NSThread isMainThread]);
    });
栅栏函数 控制执行顺序 避免数据竞争
/*
     GCD栅栏函数作用:
     1.在它前面的任务执行结束后它才执行,它后面的任务要等它执行完成后才会开始执行。
     2.避免数据竞争
     */
    //GCD栅栏函数
    //http://www.jianshu.com/p/a5048100e843
    //* 与dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)(串行队列)一起使用,会创建一个线程,barrier前后的任务串行执行
    //* 与dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT)(自定义并发队列)一起使用,创建多个线程,barrier前后的任务都是并行执行.
 //栅栏函数
    dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        NSLog(@"是否是主线程a =0 %d", [NSThread isMainThread]);
        for (int i = 0; i < 10; i++) {
            NSLog(@"aaaaa");
        }

    });
    dispatch_async(queue, ^{
        NSLog(@"是否是主线程b =0 %d", [NSThread isMainThread]);
        for (int i = 0; i < 10; i++) {
            NSLog(@"bbbbbbbbbbbb");
        }
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
        NSLog(@"是否是主线程barrier =0 %d", [NSThread isMainThread]);
        for (int i = 0; i < 10; i++) {
            NSLog(@"barrier=========barrier");
        }
    });
    
    dispatch_async(queue, ^{
        NSLog(@"是否是主线程c =0 %d", [NSThread isMainThread]);
        for (int i = 0; i < 10; i++) {
            NSLog(@"cccccccccccccccccccc");
        }
    });
    dispatch_async(queue, ^{
        NSLog(@"是否是主线程d =0 %d", [NSThread isMainThread]);
        for (int i = 0; i < 10; i++) {
            NSLog(@"dddddddddddddddddddddddddddd");
        }
    });
多线程分组
///////////////////////////////////////////多线程分组的写法      
http://blog.csdn.net/wangzitao126/article/details/43195533
博客
#第一种
    dispatch_group_t group = dispatch_group_create();
    // 某个任务放进 group
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        // 任务代码1
        dispatch_group_enter(group);//加入组
        执行网络请求后处理数据
        dispatch_group_leave(group);//离开组
    });
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        // 任务代码2
        dispatch_group_enter(group);//加入组
        执行网络请求后处理数据
        dispatch_group_leave(group);//离开组
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 任务全部完成处理    加入几次就要离开几次  这个回调才会被执行
        NSLog(@"isover");
    });
创建一个任务组,然后将异步操作放进组里面,在最后用notify 告知所有任务完成,并做相应处理,一般来说都是在主线程里面刷新UI来提示用户了。你如果不依赖UI放进子线程里面也是没有问题的。当然group同步的方式还有其他

#第二种
dispatch_group_t group = dispatch_group_create();
// 某个任务放进 group
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
       // 任务代码1  
       dispatch_group_enter(group);//加入组
       // 任务代码i 假定任务 是异步执行block回调
       // block 回调执行
       dispatch_group_leave(group);//离开组
    });
   dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
   dispatch_async(dispatch_get_main_queue(), ^{
       // 主线程处理
       // 任务全部完成处理
       NSLog(@"isover");
    });
首先我们异步执行,因为dispatch_group_wait函数是阻塞的,for里面安排了三个任务,这三个任务都是加载,在任务开始前 调用 enter,任务完成时调用leave,wait函数一直阻塞,直到它发现group里面的任务全部leave,它才放弃阻塞(任务全部完成),然后我们在主线程更新UI告知用户.

# Swift
        let group = DispatchGroup()
        let queue = DispatchQueue.global()
        queue.async(group: group) {
            group.enter()
            // 耗时操作
            group.leave()
        }
        group.notify(queue: DispatchQueue.main) {
        //异步操作都完成之后,主线程操作
        }
GCD信号量
//GCD信号量
    //控制线程并发数
    //创建信号量  这里设置最大数量是5
    dispatch_semaphore_t sema = dispatch_semaphore_create(5);
    for (int i = 0; i < 100; i++) {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);//在这里添加网络请求  但是是等待的  这里信号量先是=0  下边+1之后  执行dispatch_semaphore_wait内部实现之后  信号量-1
        //创建任务
        dispatch_async(queue, ^{
            NSLog(@"是否是主线程a = %d", [NSThread isMainThread]);
            NSLog(@"%i",i);
//            sleep(2);
            // 操作
            dispatch_semaphore_signal(sema); //这里信号量+1  上边的任务会执行
        });   
    }
//dispatch_semaphore_wait:信号等待,它像一个安保,比如小区规定最多只能进入3辆车,而进入一辆车后名额就会减少一个,当剩下的名额为0的时候,再有汽车说要进去时,就只能在外面等待了,直到有名额闲置出来了,才能开进小区。
//dispatch_semaphore_signal:信号释放,当有一辆车从小区出来时,就腾出来了一个名额。

#利用信号量实现->异步执行->同步处理
按照:任务1 -> 任务2 -> 任务3    的执行顺序执行
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_semaphore_t sema = dispatch_semaphore_create(1);
    // 2.向队列中添加任务
    dispatch_async(queue, ^{
        //等待(sema信号量==0的时候 线程等待 不往下执行)
        //初始化的时候 sema信号量==1 这里不会出现等待的情况
        //但是执行完dispatch_semaphore_wait 相当于执行了sema--(信号量-1)的操作
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        //任务1->异步返回结果
        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        [manager POST:@"url" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            dispatch_semaphore_signal(sema);//请求成功   sema++(信号量+1)
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            dispatch_semaphore_signal(sema);//请求失败   sema++(信号量+1)
        }];
    });
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        //任务2->异步返回结果之后
        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        [manager POST:@"url" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            dispatch_semaphore_signal(sema);//请求成功
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            dispatch_semaphore_signal(sema);//请求失败
        }];
    });
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        //任务3->异步返回结果之后
        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        [manager POST:@"url" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            dispatch_semaphore_signal(sema);//请求成功
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            dispatch_semaphore_signal(sema);//请求失败
        }];
    });
#典型的例子就是卖火车票(查询同一趟车次余票)  多个窗口(相当于并发多个线程)
这样才是一个安全的线程
//火车票数量
@property (nonatomic, assign)int ticketNum;
//声明信号量
@property (nonatomic, strong)dispatch_semaphore_t sema;

//GCD信号量
    //控制线程并发数
    //创建信号量  这里设置最大数量是1
    self.sema = dispatch_semaphore_create(1);

self.ticketNum = 10;//车票数量
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    // 向队列中添加任务
    dispatch_async(queue, ^{  
        for (int i = 0; i < 5; i++) {
            [self diminishingNum:1];
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 4; i++) {
            [self diminishingNum:2];
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            [self diminishingNum:3];
        }
    });
//卖出火车票 执行一次就减少一张车票
-(void)diminishingNum:(int)n
{
    NSLog(@"前self.ticketNum====%d  ->任务n==%d", self.ticketNum, n);
    dispatch_semaphore_wait(self.sema, DISPATCH_TIME_FOREVER);//在这里添加网络请求  但是是等待的  这里信号量先是=0  下边+1之后  执行dispatch_semaphore_wait内部实现之后  信号量-1
    if (self.ticketNum == 0) {
        NSLog(@"车票已卖完===%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@  ->任务n==%d", self.ticketNum, [NSThread currentThread], n]);
    }else{
        sleep(2);//处理车票或者网络请求 是否卖出
        self.ticketNum--;//这里减少一张车票
        NSLog(@"后self.ticketNum====%d  ->任务n==%d", self.ticketNum, n);
        NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@  ->任务n==%d", self.ticketNum, [NSThread currentThread], n]);
    }
    dispatch_semaphore_signal(self.sema); //这里信号量+1  上边的任务会执行
}
打印
前self.ticketNum====10  ->任务n==1
前self.ticketNum====10  ->任务n==3
前self.ticketNum====10  ->任务n==2
后self.ticketNum====9  ->任务n==1
剩余票数:9 窗口:<NSThread: 0x60000149df00>{number = 9, name = (null)}  ->任务n==1
前self.ticketNum====9  ->任务n==1
后self.ticketNum====8  ->任务n==3
剩余票数:8 窗口:<NSThread: 0x6000014dc540>{number = 6, name = (null)}  ->任务n==3
前self.ticketNum====8  ->任务n==3
后self.ticketNum====7  ->任务n==2
剩余票数:7 窗口:<NSThread: 0x600001498f40>{number = 10, name = (null)}  ->任务n==2
前self.ticketNum====7  ->任务n==2
后self.ticketNum====6  ->任务n==1
剩余票数:6 窗口:<NSThread: 0x60000149df00>{number = 9, name = (null)}  ->任务n==1
前self.ticketNum====6  ->任务n==1
后self.ticketNum====5  ->任务n==3
剩余票数:5 窗口:<NSThread: 0x6000014dc540>{number = 6, name = (null)}  ->任务n==3
前self.ticketNum====5  ->任务n==3
后self.ticketNum====4  ->任务n==2
剩余票数:4 窗口:<NSThread: 0x600001498f40>{number = 10, name = (null)}  ->任务n==2
前self.ticketNum====4  ->任务n==2
后self.ticketNum====3  ->任务n==1
剩余票数:3 窗口:<NSThread: 0x60000149df00>{number = 9, name = (null)}  ->任务n==1
[MapViewController.m:223行] 前self.ticketNum====3  ->任务n==1
后self.ticketNum====2  ->任务n==3
剩余票数:2 窗口:<NSThread: 0x6000014dc540>{number = 6, name = (null)}  ->任务n==3
[MapViewController.m:230行] 后self.ticketNum====1  ->任务n==2
剩余票数:1 窗口:<NSThread: 0x600001498f40>{number = 10, name = (null)}  ->任务n==2
前self.ticketNum====1  ->任务n==2
后self.ticketNum====0  ->任务n==1
剩余票数:0 窗口:<NSThread: 0x60000149df00>{number = 9, name = (null)}  ->任务n==1
前self.ticketNum====0  ->任务n==1
车票已卖完===剩余票数:0 窗口:<NSThread: 0x600001498f40>{number = 10, name = (null)}  ->任务n==2
车票已卖完===剩余票数:0 窗口:<NSThread: 0x60000149df00>{number = 9, name = (null)}  ->任务n==1
NSLock线程锁
/*
NSLock *lock = [[NSLock alloc] init];
 [lock lock];//加锁
[self 方法];//执行调用方法
  [lock unlock];//解锁
*/
NSLock *lock = [[NSLock alloc] init];
    dispatch_queue_t globalQueue = dispatch_queue_create("aaa", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(globalQueue, ^{
        NSLog(@"是否是主线程11 =0 %d", [NSThread isMainThread]);
        [lock lock];
        sleep(3);
        NSLog(@"11111");
        [lock unlock];
    });
    dispatch_async(globalQueue, ^{
        NSLog(@"是否是主线程222 =0 %d", [NSThread isMainThread]);
        [lock lock];
        sleep(3);
        NSLog(@"222222");
        [lock unlock];
    });
    dispatch_async(globalQueue, ^{
        NSLog(@"是否是主线程333 =0 %d", [NSThread isMainThread]);
        [lock lock];
        sleep(3);
        NSLog(@"333333");
        [lock unlock];
    });
打印
    是否是主线程11 =0 0
    11111
    是否是主线程222 =0 0
    222222
    是否是主线程333 =0 0
    333333
#以上是没问题的  下面说一下死锁现象
NSLock死锁现象
简单的说就是(同一个线程中不能加锁两次或多次,要加锁->解锁->加锁->解锁...)
[lock lock];
[lock lock];//死锁了  往下的代码不会执行了
不会执行
.
.
.
[lock unlock];//不会执行
针对火车票的线程锁

效率上 dispatch_semaphore > NSLock > @synchronized

NSLock
-(void)diminishingNum:(int)n
{//self.lock1 = [[NSLock alloc] init];
    NSLog(@"前self.ticketNum====%d  ->任务n==%d", self.ticketNum, n);
    [self.lock1 lock];
        if (self.ticketNum == 0) {
            NSLog(@"车票已卖完===%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@  ->任务n==%d", self.ticketNum, [NSThread currentThread], n]);
        }else{
            sleep(2);//处理车票或者网络请求 是否卖出
            self.ticketNum--;//这里减少一张车票
            NSLog(@"后self.ticketNum====%d  ->任务n==%d", self.ticketNum, n);
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@  ->任务n==%d", self.ticketNum, [NSThread currentThread], n]);
        }
    [self.lock1 unlock];
}
@synchronized用法简单 但是性能比较低效消耗性能
-(void)diminishingNum:(int)n
{
    NSLog(@"前self.ticketNum====%d  ->任务n==%d", self.ticketNum, n);
    @synchronized (self) {
        if (self.ticketNum == 0) {
            NSLog(@"车票已卖完===%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@  ->任务n==%d", self.ticketNum, [NSThread currentThread], n]);
        }else{
            sleep(2);//处理车票或者网络请求 是否卖出
            self.ticketNum--;//这里减少一张车票
            NSLog(@"后self.ticketNum====%d  ->任务n==%d", self.ticketNum, n);
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@  ->任务n==%d", self.ticketNum, [NSThread currentThread], n]);
        }
    }
}

相关文章

网友评论

      本文标题:常用的GCD记录一下

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