1 简介

1.1 功能

       Operation Queue也是IOS的一种并行编程技术,类似Dispatch Queue可以帮助用户管理多线程。但是Operation Queue将任务封装在NSOperation对象中,从而可以更好的控制任务的执行。并且Dispatch Queue的先入先出的执行方式不同,Operation Queue任务的执行顺序可以控制。其中IOS是将任务交给NSOperation对象进行管理,其中NSOperation是个抽象类,必须被继承,目前系统预定义了两个子类:NSBlockOperation 和NSInvocationOperation。

其中启动任务,既让NSOperation对象执行任务 ,有两种方式,一种是调用NSOperation的start方法;一种是将NSOperation对象添加到NSOperationQueue 对象中。

1.2 第一个程序

1) NSBlockOperation

1 int main(int argc, const char * argv[]) {
2     //直接创建NSBlockOperation 对象。
3     NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
4         printf("blockOperation\n");
5     }];
6     [blockOperation start];    //启动NSBlockOperation 对象开始执行
7     return 0;
8 }

2) NSInvocationOperation

     NSInvocationOperation类只能在类中使用。

 1 //  创建一个object-C的类
 2 @implementation test_NSInvocationOperation
 3 -(id) init
 4 {
 5     if( self = [super init])
 6     {
 7         NSInvocationOperation *invacationOperation = [[NSInvocationOperation alloc]                      initWithTarget:self selector:@selector(myTaskMethod:) object:nil];
 8         [invacationOperation start];
 9     }
10      return self;
11 }
12 - (void)myTaskMethod:(id)data {
13     // Perform the task.
14     printf("hello myTaskMethod\n");
15 }
16 int main(int argc, const char * argv[]) {
17     @autoreleasepool {
18          test_NSInvocationOperation *in = [[test_NSInvocationOperation alloc] init];
19     }
20     return 0;
21 }

3) NSOperationQueue

 1 int main(int argc, const char * argv[]) {
 2     @autoreleasepool {
 3         NSBlockOperation *operation1s = [NSBlockOperation blockOperationWithBlock:^{
 4             NSLog(@"operation1s");
 5         }];
 6         NSBlockOperation *operation2s = [NSBlockOperation blockOperationWithBlock:^{
 7             NSLog(@"operation2s");
 8         }];
 9         NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //创建队列
10         queue.maxConcurrentOperationCount = 2;
11         [queue addOperation:operation1s]; //将NSOperation 对象添加到队列
12         [queue addOperation:operation2s];
13         
14         [queue waitUntilAllOperationsAreFinished];  //队列等待任务完成
15     }
16     return 0;
17 }

2 NSOperation

iOS并发编程中,把每个并发任务定义为一个Operation,对应的类名是NSOperation。NSOperation是一个抽象类,无法直接使用,它只定义了Operation的一些基本方法。我们需要创建一个继承于它的子类或者使用系统预定义的子类。

2.1 预定义子类

根据任务的使用方式不同,目前系统预定义了两个子类:NSInvocationOperation和NSBlockOperation。

1) NSBlockOperation

    该子类是将任务封装成block块,然后NSBlockOpration对象执行block块的任务。如:

1 NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 
2     //Do something here. 
3 }]; 

2) NSInvocationOperation

    该子类是将任务封装在函数中,然后NSInvocationOperation对象执行函数中的任务。如:

1 NSInvocationOperation *invacationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomethingWithObj:) object:nil]; 

2.2 自定义子类

如果预定义子类不能满足应用的需要,可以自定义NSOperation的子类。其中自定义子类只需实现两个方法:

  • 构造函数
  • main函数

      比如为了支持任务并发操作,但默认情况下Operation的start方法中直接调用了main方法,而main方法中会有比较耗时的处理任务。如果我们在一段代码连续start了多个Operation,这些Operation都是阻塞地依次执行完,因为第二个Operation必须等到第一个Operation执行完start内的main并返回。Operation默认都是不可并发的(使用了Operation Queue情况下除外,Operation Queue会独自管理自己的线程),因为默认情况下Operation并不额外创建线程。我们可以通过Operation的isConcurrent方法来判断Operation是否是可并发的。如果要让Operation可并发,我们需要让main在独立的线程中执行,并将isConcurrent返回YES。

 1 @interface MyOperation : NSOperation {
 2 }
 3 @end
 4 @implementation MyOperation
 5   - (id)init {
 6       self = [super init];
 7       return self;
 8 }
 9 - (BOOL)isConcurrent {
10     return YES;
11 }
12 - (void)main {
13    @try {
14        // Do the main work of the operation here.
15    }
16    @catch(...) {
17       // Do not rethrow exceptions.
18     } 
19 } 

2.3 对象操作

1) 启动运行

     启动NSOperation对象开始执行任务,其只需调用对象的start方法即可。其中start方法是同步调用方法,该方法底层又调用了main方法,所以需要等待main执行完成后,start才能够返回。如:

[operation start];

2) 优先级设置

我们可以为Operation设置一个线程优先级,即threadPriority。那么执行main的时候,线程优先级就会调整到所设置的线程优先级。这个默认值是0.5,我们可以在Operation执行前修改它。

operation.threadPriority = 0.1; 

3) 状态监听

     我们可以通过KVO机制来监听Operation的一下状态改变,比如一个Operation的执行状态或完成状态。这些状态的keypath包括以下几个:

  • isCancelled
  • isConcurrent
  • isExecuting
  • isFinished
  • isReady
  • dependencies
  • queuePriority
  • completionBlock

     如监听completionBlock 状态:

operation.completionBlock = ^{ 
    NSLog(@"finished"); 
};

3 NSOperationQueue

       NSOperationQueue是一个Operation执行队列,你可以将任何你想要执行的Operation添加到Operation Queue中,以在队列中执行。同时Operation和Operation Queue提供了很多可配置选项。Operation Queue的实现中,创建了一个或多个可管理的线程,为队列中的Operation提供可高度自定的执行环境。

3.1 创建队列

创建NSOperationQueue对象有三种形式:

  • [[NSoperationQueue alloc] init]:创建全新的线程队列;
  • [NSoperationQueue mainQueue]:获取主线程中的队列;
  • [NSoperationQueue currentQueue]:获取当前线程中的队列。

类似dispatch queue,系统也提供了一些queue,第2是系统提供的。

3.2 依赖关系

        有时候我们对任务的执行顺序有要求,一个任务必须在另一个任务执行之前完成,这就需要用到Operation的依赖(Dependency)属性。我们可以为每个Operation设定一些依赖的另外一些Operation,那么如果依赖的Operation没有全部执行完毕,这个Operation就不会被执行。

[operation addDependency:anotherOperation]; 
[operation removeDependency:anotherOperation]; 

3.3 执行优先级

        Operation在队列中默认是按FIFO(First In First Out)顺序执行的。同时我们可以为单个的Operation设置一个执行的优先级,打乱这个顺序。当Queue有空闲资源执行新的Operation时,会优先执行当前队列中优先级最高的待执行Operation。

3.4 最大并发数目

        在一个Operation Queue中是可以同时执行多个Operation的,Operation Queue会动态的创建多个线程来完成相应Operation。具体的线程数是由Operation Queue来优化配置的,这一般取决与系统CPU的性能,比如CPU的核心数,和CPU的负载。但我们还是可以设置一个最大并发数的,那么Operation Queue就不会创建超过最大并发数量的线程。

NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
queue.maxConcurrentOperationCount = 1; 

如果我们将maxConcurrentOperationCount设置为1,那么在队列中每次只能执行一个任务。这就是一个串行的执行队列了。

下面我写了一个简单的Simple Code来说明一下Operation和Operation Queue。

 1    NSBlockOperation *operation5s = [NSBlockOperation blockOperationWithBlock:^{
 2         NSLog(@"operation5s begin");
 3         sleep(5);
 4         NSLog(@"operation5s end");
 5     }];
 6     operation5s.queuePriority = NSOperationQueuePriorityHigh;
 7     NSBlockOperation *operation1s = [NSBlockOperation blockOperationWithBlock:^{
 8         NSLog(@"operation1s begin");
 9         sleep(1);
10         NSLog(@"operation1s end");
11     }];
12     NSBlockOperation *operation2s = [NSBlockOperation blockOperationWithBlock:^{
13         NSLog(@"operation2s begin");
14         sleep(2);
15         NSLog(@"operation2s end");
16     }];
17     
18     operation1s.completionBlock = ^{
19         NSLog(@"operation1s finished in completionBlock");
20     };
21     
22     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
23     queue.maxConcurrentOperationCount = 1;
24     [queue addOperation:operation1s];
25     [queue addOperation:operation2s];
26     [queue addOperation:operation5s];
27     [queue waitUntilAllOperationsAreFinished]; 
28 
29 运行这段代码,我得到了一下输出结果:
30 operation1s begin 
31 operation1s end 
32 operation5s begin 
33 operation1s finished in completionBlock 
34 operation5s end 
35 operation2s begin 
36 operation2s end 

4 Operation与GCD

GCD 技术是一个轻量的,底层实现隐藏的神奇技术,我们能够通过GCD和block轻松实现多线程编程,有时候,GCD相比其他系统提供的多线程方法更加有效,当然,有时候GCD不是最佳选择,另一个多线程编程的技术 NSOprationQueue 让我们能够将后台线程以队列方式依序执行,并提供更多操作的入口,这和 GCD 的实现有些类似。

这种类似不是一个巧合,在早期,MacOX 与 iOS 的程序都普遍采用Operation Queue来进行编写后台线程代码,而之后出现的GCD技术大体是依照前者的原则来实现的,而随着GCD的普及,在iOS 4 与 MacOS X 10.6以后,Operation Queue的底层实现都是用GCD来实现的。

那这两者直接有什么区别呢?

  1. GCD是底层的C语言构成的API,而NSOperationQueue及相关对象是Objc的对象。在GCD中,在队列中执行的是由block构成的任务,这是一个轻量级的数据结构;而Operation作为一个对象,为我们提供了更多的选择;
  2. 在NSOperationQueue中,我们可以随时取消已经设定要准备执行的任务(当然,已经开始的任务就无法阻止了),而GCD没法停止已经加入queue的block(其实是有的,但需要许多复杂的代码);
  3. NSOperation能够方便地设置依赖关系,我们可以让一个Operation依赖于另一个Operation,这样的话尽管两个Operation处于同一个并行队列中,但前者会直到后者执行完毕后再执行;
  4. 我们能将KVO应用在NSOperation中,可以监听一个Operation是否完成或取消,这样子能比GCD更加有效地掌控我们执行的后台任务;
  5. 在NSOperation中,我们能够设置NSOperation的priority优先级,能够使同一个并行队列中的任务区分先后地执行,而在GCD中,我们只能区分不同任务队列的优先级,如果要区分block任务的优先级,也需要大量的复杂代码;
  6. 我们能够对NSOperation进行继承,在这之上添加成员变量与成员方法,提高整个代码的复用度,这比简单地将block任务排入执行队列更有自由度,能够在其之上添加更多自定制的功能。

总的来说,Operation queue 提供了更多你在编写多线程程序时需要的功能,并隐藏了许多线程调度,线程取消与线程优先级的复杂代码,为我们提供简单的API入口。从编程原则来说,一般 我们需要尽可能的使用高等级、封装完美的API,在必须时才使用底层API。但是我认为当我们的需求能够以更简单的底层代码完成的时候,简洁的GCD或许是个更好的选择,而Operation queue 为我们提供能更多的选择。

5 参考文献

[1] 并发编程之Operation Queue

[2] Apple:Concurrency Programming Guide

[3] NSOprationQueue 与 GCD 的区别与选用

iOS 并行编程:NSOperation Queues的更多相关文章

  1. iOS 并行编程:GCD Dispatch Queues

    1 简介 1.1 功能          Grand Central Dispatch(GCD)技术让任务并行排队执行,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务.任务可以是一个函数 ...

  2. iOS多线程编程--NSOperation(转)

    这篇文章写得非常不错,基础用法都涉及到了,我把文章提到的例子都写到了demo里面, 原文地址: iOS多线程--彻底学会多线程之『NSOperation』 demo下载:https://github. ...

  3. iOS 并行编程:Thread

    1 创建线程 1.1 NSThread       使用 NSThread 来创建线程有两个可以使用的方法: 1) 使用 detachNewThreadSelector:toTarget:withOb ...

  4. iOS 并行编程:GCD Dispatch Sources

    1 简介 dispatch source是一种用于处理事件的数据类型,这些被处理的事件为操作系统中的底层级别.Grand Central Dispatch(GCD)支持如下的dispatch sour ...

  5. Swift 并行编程现状和展望 - async/await 和参与者模式

    这篇文章不是针对当前版本 Swift 3 的,而是对预计于 2018 年发布的 Swift 5 的一些特性的猜想.如果两年后我还记得这篇文章,可能会回来更新一波.在此之前,请当作一篇对现代语言并行编程 ...

  6. iOS多线程编程原理及实践

    摘要:iOS开发中,开发者不仅要做好iOS的内存管理,而且如果你的iOS涉及多线程,那你也必须了解iOS编程中对多线程的限制,iOS主线程的堆栈大小为1M,其它线程均为512KB,且这个限制开发者是无 ...

  7. Objective-C编程 — 并行编程

    多线程 线程的基本概念 线程 (thread)是进程(process)A 内假想的持有 CPU 使用权的执行单位.一般情况下,一个进程 只有一个线程,但也可以创建多个线程并在进程中并行执行.应用在执行 ...

  8. C#中的多线程 - 并行编程 z

    原文:http://www.albahari.com/threading/part5.aspx 专题:C#中的多线程 1并行编程Permalink 在这一部分,我们讨论 Framework 4.0 加 ...

  9. 【iOS开发】NSOperation简单介绍

    iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现 ...

随机推荐

  1. Subline Text快捷键

    我经常使用的快捷键 Ctrl+A: 全选Ctrl+C: 复制 重复工作必备: Ctrl+D:选择单词,重复可增加选择下一个相同的单词Alt+F3:选择所有相同的词F3: 下一个Shift+F3:前一个 ...

  2. 理解Java ClassLoader机制

    当JVM(Java虚拟机)启动时,会形成由三个类加载器组成的初始类加载器层次结构: bootstrap classloader                |       extension cla ...

  3. BZOJ_1612_[Usaco2008_Jan]_Cow_Contest_奶牛的比赛_(dfs)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1612 \(n\)头奶牛比赛,给出一些胜负情况,问可以确定多少头奶牛的排名. 分析 无论胜负,只 ...

  4. apache开源项目--Ignite

    Apache Ignite 内存数组组织框架是一个高性能.集成和分布式的内存计算和事务平台,用于大规模的数据集处理.Ignite 为应用和不同的数据源之间提供一个高性能.分布式内存中数据组织管理的框架 ...

  5. MVC3.0 中Razor 学习

    随着MVC3.0RTM版本的发布,最近将公司的项目从MVC2.0升级到MVC3.0.同时打算在MVC3中全面使用Razor模板引擎.现将Razor学习拿出来和大家分享,如果存在不足的地方欢迎您指出. ...

  6. SQL Server 2008空间数据应用系列一:空间信息基础

    转自:http://www.cnblogs.com/beniao/archive/2011/01/18/1933412.html Microsoft SQL Server 2008 提供了全面性的空间 ...

  7. FCLK PCLK HCLK

    一.对clock的基本认识 1 s3c2410的clock & power management模块包含三个部分:clock control.usb control.power control ...

  8. java项目中eclipse控制台输出log4j的信息

    最近做的一个hadoop项目中,用MR实现了一个比较复杂的问题,其中的日志信息都是使用的是log4j来处理的.但不知怎么控制台不输出日志信息,只能输出System.out.println()信息,这个 ...

  9. Storm系列(十七)DRPC介绍

    Storm版本0.9.5 在storm中DRPC服务应用于远程分布式计算,根据客户端提交的请求参数,而返回Storm计算的结果. DRPC服务启动流程(远程模式) 启动DRPC服务,启动命令:stor ...

  10. pes and ts stream, how to convert

    http://stackoverflow.com/questions/4145575/transport-stream-mpeg-file-fromat What you are probably w ...