• GCD / NSOperation


     GCD 与 NSOperation 的区别 ?

    1. GCD 是基于 C 语言写的核心服务, 非常简单高效, 而 NSOperation 是基于 GCD 的一种封装,抽象出来的对象, 所以一般情况下对于任务的依赖和并发数没有要求的情况下, GCD 的效率更高, 开销更小

    2. 依赖关系,NSOperation可以设置两个NSOperation之间的依赖,第二个任务依赖于第一个任务完成执行,GCD无法设置依赖关系,不过可以通过dispatch_barrier_async来实现这种效果

    3. KVO(键值对观察),NSOperation和容易判断Operation当前的状态(是否执行,是否取消),对此GCD无法通过KVO进行判断

    4. 优先级,NSOperation可以设置自身的优先级,但是优先级高的不一定先执行,GCD只能设置队列的优先级,无法在执行的block设置优先级;

    5. 继承,NSOperation是一个抽象类实际开发中常用的两个类是NSInvocationOperation和NSBlockOperation,同样我们可以自定义NSOperation,GCD执行任务可以自由组装,没有继承那么高的代码复用度;

    总的来说: 如果对于任务的并发数和任务之间的依赖关系没有要求, 可以直接使用 GCD, 否则使用 NSOperation 可以满足对任务的控制

    GCD

    GCD 面对的不是线程, GCD 面对的只有队列和任务这两个概念, 你不用管在哪个线程, 只需要把任务按正确的同步/异步的方式添加进串行/并发队列即可

    • 串行队列(先进入队列的任务先出队列,每次只执行一个任务) 顺序执行 
    • 并发队列(依然是“先入先出”,不过可以形成多个任务并发)   异步添加可以并发执行 同步添加只能顺序执行
    • 主队列(这是一个特殊的串行队列,而且队列中的任务一定会在主线程中执行)
    1. 同步执行  都不会开启新的线程
    2. 异步执行  会开启新的线程 除了主队列

              同步                          异步

    主队列    死锁              不会开启新线程(顺序执行)

    串行队列   在当前线程执行(顺序执行)     开启一个新的线程(顺序执行)      

    并发队列   在当前线程执行(顺序执行)     开启一个或多个线程(并发执行)

    下面是例子

    //异步 + 并行队列
    - (void)asyncConcurrent{
        //创建一个并行队列
        dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT);
     
        NSLog(@"---start---");
     
        //使用异步函数封装三个任务
        dispatch_async(queue, ^{
            NSLog(@"任务1---%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务2---%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务3---%@", [NSThread currentThread]);
        });
     
        NSLog(@"---end---");
    }

    结果:  start end  3 2 1  // 开启3个新的线程 同时执行的 没有先后

    //异步 + 串行队列
    - (void)asyncSerial{
        //创建一个串行队列
        dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL);
     
        NSLog(@"---start---");
        //使用异步函数封装三个任务
        dispatch_async(queue, ^{
            NSLog(@"任务1---%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务2---%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务3---%@", [NSThread currentThread]);
        });
        NSLog(@"---end---");
    }

    //  结果 start end 123   开启一个新的线程 顺序执行

    //同步 + 并行队列
    - (void)syncConcurrent{
        //创建一个并行队列
        dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT);
     
        NSLog(@"---start---");
        //使用同步函数封装三个任务
        dispatch_sync(queue, ^{
            NSLog(@"任务1---%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"任务2---%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"任务3---%@", [NSThread currentThread]);
        });
        NSLog(@"---end---");
     
    // 结果 start 123 end  同步任务不会开启新线程也就没法并发执行  按顺序在一个单线程执行
     
    // 同步+串行队列
    - (void)syncSerial{
        //创建一个串行队列
        dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL);
     
        NSLog(@"---start---");
        //使用异步函数封装三个任务
        dispatch_sync(queue, ^{
            NSLog(@"任务1---%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"任务2---%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"任务3---%@", [NSThread currentThread]);
        });
        NSLog(@"---end---");
    }
     
    // 结果: start 123 end   跟同步串行一样 不能开启一个新的线程 只能在一个线程里按顺序执行
     
    // 异步+ 主队列
    - (void)asyncMain{
        //获取主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
     
        NSLog(@"---start---");
        //使用异步函数封装三个任务
        dispatch_async(queue, ^{
            NSLog(@"任务1---%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务2---%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务3---%@", [NSThread currentThread]);
        });
        NSLog(@"---end---");
    }
     
    // 结果 start 123 end  不会开启新的线程 会异步执行   主队列就运行在主线程
     
    // 同步 + 主队列  死锁
     
    *************************** GCD 实现所有异步操作完成之后执行的任务 *****************************
    //先创建一个组
    dispatch_group_t group = dispatch_group_create();
    // 异步添加到任务到并行队列
     
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      //请求1 NSLog(@"Request_1");
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //请求2 NSLog(@"Request_2");
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //请求3 NSLog(@"Request_3");
    });
    // 当所有任务都执行完成之后 才执行
     
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    //界面刷新 NSLog(@"任务均完成,刷新界面");
    });
    //  打印结果 2 1 3 刷新界面   会开启多线程 异步任务完成的顺序不受控制

    *******************************如果需要添加任务之间的依赖**************************
    1. dispatch_group_t group =dispatch_group_create();  
    2.         dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{  
    3.                           NSLog(@"任务1");  
    4.          });  
    5.       
    6.         dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{  
    7.                          NSLog(@"任务2");  
    8.          });  
    9.       
    10.         dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{  
    11.                     NSLog(@"任务3");  
    12.     }); 
    //  任务 1 2 并行执行 执行完之后执行 3 
     
    1. dispatch_queue_t myqueue =dispatch_queue_create("myqueue.queue",DISPATCH_QUEUE_CONCURRENT);  
    2.      dispatch_async(myqueue, ^{  
    3.         NSLog(@"任务1");  
    4.     });  
    5.       
    6.     dispatch_async(myqueue, ^{  
    7.         NSLog(@"任务2");  
    8.     });  
    9.       
    10.     dispatch_barrier_async(myqueue, ^{  
    11.         NSLog(@"任务3");  
    12.     });  
    13.       
    14.     dispatch_async(myqueue, ^{  
    15.         NSLog(@"任务4");  
    16.     });  
    17.     dispatch_async(myqueue, ^{  
    18.         NSLog(@"任务5");  
    19.     });  
    //  1 2 并行执行 执行完之后执行3 最后执行 4 5 
    // *dispatch_barrier_async 会等待当前队列的任务执行完之后再执行dispatch_barrier_async(myqueue, ^{
           NSLog(@"任务3");

         });

    // NSOperation
    NSOperation 实现多线程的使用步骤分为三步:
    1. 创建操作:先将需要执行的操作封装到一个 NSOperation 对象中。
    2. 创建队列:创建 NSOperationQueue 对象。
    3. 将操作加入到队列中:将 NSOperation 对象添加到 NSOperationQueue 对象中。

    之后呢,系统就会自动将 NSOperationQueue 中的 NSOperation 取出来,在新线程中执行操作

    使用NSOperation子类的方式有三种: 
    NSInvocationOperation 
    NSBlockOperation 
    自定义子类继承NSOperation,实现响应的方法

    先看看NSInvocationOperation的使用:

    1. 同步执行的 直接操作 不加入 queue

    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"这是一个参数"];
    [operation start]; }
    /// 将参数与当前线程打印
    - (void)demo:(NSString *)str { NSLog(@"%@--%@",str,[NSThread currentThread]); }

    2. 加入队列 异步执行
    // 创建操作队列
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    // 创建操作(最后的object参数是传递给selector方法的参数)
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"这是一个参数"];
    // 将操作添加到操作队列
    [operationQueue addOperation:operation]; }
    /// 将参数与当前线程打印
    - (void)demo:(NSString *)str { NSLog(@"%@--%@",str,[NSThread currentThread]); }
    开启了一个子线程  且是异步执行的
    只有将operation放到一个NSOperationQueue中,才会异步执行操作。

    再看看NSBlockOperation

    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"%@",[NSThread currentThread]); }];
    // 开始执行任务 [operation start];
    // 直接執行 同步執行 不會開啟新線程//创建NSBlockOperation操作对象
    22     NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
    23         NSLog(@"NSBlockOperation------%@",[NSThread currentThread]);
    24     }];
    25     
    26     //添加操作  在子线程异步执行
    27     [operation addExecutionBlock:^{
    28         NSLog(@"NSBlockOperation1------%@",[NSThread currentThread]);
    29     }]; 
    30     
        // 在子线程 异步执行 31 [operation addExecutionBlock:^{ 32 NSLog(@"NSBlockOperation2------%@",[NSThread currentThread]); 33 }]; 34 35 //开启执行操作 36 [operation start];


    // 為 operation 添加依賴關係 
    1.  NSOperationQueue *queue=[[NSOperationQueue alloc] init];  
    2.     //创建操作  
    3.     NSBlockOperation *operation1=[NSBlockOperation blockOperationWithBlock:^(){  
    4.         NSLog(@"执行第1次操作,线程:%@",[NSThread currentThread]);  
    5.     }];  
    6.     NSBlockOperation *operation2=[NSBlockOperation blockOperationWithBlock:^(){  
    7.         NSLog(@"执行第2次操作,线程:%@",[NSThread currentThread]);  
    8.     }];  
    9.     NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^(){  
    10.         NSLog(@"执行第3次操作,线程:%@",[NSThread currentThread]);  
    11.     }];  
    12.     //添加依赖  
    13.     [operation1 addDependency:operation2];  
    14.     [operation2 addDependency:operation3];  
    15.     //将操作添加到队列中去  
    16.     [queue addOperation:operation1];  
    17.     [queue addOperation:operation2];  
    18.     [queue addOperation:operation3]; 
    先執行3 然後 2 最後1  都是在同一個子線程執行的
    // 设置最大并发数

     // 1.创建队列
    
    
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    
     
    
    
        // 2.设置最大并发操作数
    
    
        queue.maxConcurrentOperationCount = 1// 串行队列
    
    
    // queue.maxConcurrentOperationCount = 2; // 并发队列
    
    
    // queue.maxConcurrentOperationCount = 8; // 并发队列
    
    
     
    
    
        // 3.添加操作
    
    
        [queue addOperationWithBlock:^{
    
    
            for (int i = 0; i < 2; i++) {
    
    
                [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
    
    
                NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程
    
    
            }
    
    
        }];
    
    
        [queue addOperationWithBlock:^{
    
    
            for (int i = 0; i < 2; i++) {
    
    
                [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
    
    
                NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程
    
    
            }
    
    
        }];
    
    
        [queue addOperationWithBlock:^{
    
    
            for (int i = 0; i < 2; i++) {
    
    
                [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
    
    
                NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程
    
    
            }
    
    
        }];
    
    
        [queue addOperationWithBlock:^{
    
    
            for (int i = 0; i < 2; i++) {
    
    
                [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
    
    
                NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程
    
    
            }
    
    
        }];
    当最大并发操作数为1时,操作是按顺序串行执行的,并且一个操作完成之后,下一个操作才开始执行。当最大操作并发数为2时,操作是并发执行的,可以同时执行两个操作。而开启线程数量是由系统决定的,不需要我们来管理
     

    NSBlockOperation最开始的任务是在主线程中执行的,再给NSBlockOperation添加的额外的任务是在子线程中执行的,程序自动帮助开启了子线程。

    GCD队列和NSOperationQueue队列类型比较: 
    GCD的队列类型: 
    (1)并发队列:a.全局 b.自己创建的 
    (2)串行队列:a.主队列 b.自己创建的 
    NSOperationQueue队列类型: 
    (1)主队列[NSOperationQueue mainQueue],添加到主队列中的任务,都会在主线程中执行。 
    (2)其他队列(串行、并发),添加到其他队列中的任务,都会自动放在子线程中执行。

    NSOperation默认是同步执行的。

    创建一个 operation 直接 start 执行的话会在 main thread , 再添加额外的block 任务的时候会开启新的线程异步执行

    创建一个 operation 和 queue 并把 operation 放进 queue 会自动放进子线程

     
     
  • 相关阅读:
    bzoj1081 [SCOI2005]超级格雷码
    bzoj3790 神奇项链
    bzoj2822 [AHOI2012]树屋阶梯
    bzoj1485 [HNOI2009]有趣的数列
    bzoj1486 [HNOI2009]最小圈
    bzoj2721 [Violet 5]樱花
    POJ 1238 Substrings
    ZOJ Team Formation
    POJ 1459 Power Network
    POJ 1458 Common Subsequence
  • 原文地址:https://www.cnblogs.com/ChrisZhou666/p/8797504.html
Copyright © 2020-2023  润新知