多线程开发是一件需要特别精心的事情,即使是对有多年开发经验的工程师来说。

为了能让初级开发工程师也能使用多线程,同时还要简化复杂性。各种编程工具提供了各自的办法。对于iOS来说,建议在尽可能的情况下避免直接操作线程,使用比如NSOperationQueue这样的机制。

可以把NSOperationQueue看作一个线程池,可往线程池中添加操作(NSOperation)到队列中。线程池中的线程可看作消费者,从队列中取走操作,并执行它。

你可以设置线程池中只有一个线程,这样,各个操作就可以认为是近似的顺序执行了。为什么说是近似呢,后面会做解释。

编写最简单的示例

先写个最简单的示例。

编写一个NSOperation的子类,只需实现main方法。这里非常类似Java的Thread,你可以继承它,并覆盖run方法,在该方法里面写入需要执行的代码。这里的main方法和run方法作用是相似的。

头文件:

@interface MyTask : NSOperation {
    int operationId;
}

@property int operationId;

@end

这里的operationId属性不是必须的,是我想在后面标识区分多个Task的标识位。

m文件:

@implementation MyTask

@synthesize operationId;

- (void)main{
    NSLog(@"task %i run … ",operationId);
    [NSThread sleepForTimeInterval:10];
    NSLog(@"task %i is finished. ",operationId);
}

@end

这里模拟了一个耗时10秒钟的操作。

下面需要把Task加入到队列中:

- (void)viewDidLoad {
    [super viewDidLoad];
    queue=[[NSOperationQueue alloc] init];
   
    int index=1;
    MyTask *task=[[[MyTask alloc] init] autorelease];
    task.operationId=index++;
        
    [queue addOperation:task];

我直接找了个Controller的方法写上了。运行结果是,界面出现了,而task还未执行完,说明是多线程的。10秒钟后,日志打印完毕,类似这样:

2011-07-18 15:59:14.622 MultiThreadTest[24271:6103] task 1 run …

2011-07-18 15:59:24.623 MultiThreadTest[24271:6103] task 1 is finished.

可以向操作队列(NSOperationQueue)增加多个操作,比如这样:

- (void)viewDidLoad {
    [super viewDidLoad];
    queue=[[NSOperationQueue alloc] init];
   
    int index=1;
    MyTask *task=[[[MyTask alloc] init] autorelease];
    task.operationId=index++;    
    [queue addOperation:task];
   
    task=[[[MyTask alloc] init] autorelease];
    task.operationId=index++;

[queue addOperation:task];
}

那么打印出的内容是不定的,有可能是这样:

2011-07-18 15:49:48.087 MultiThreadTest[24139:6203] task 1 run …

2011-07-18 15:49:48.087 MultiThreadTest[24139:1903] task 2 run …
2011-07-18 15:49:58.122 MultiThreadTest[24139:6203] task 1 is finished.
2011-07-18 15:49:58.122 MultiThreadTest[24139:1903] task 2 is finished.

甚至有可能是这样:

2011-07-18 15:52:24.686 MultiThreadTest[24168:1b03] task 2 run …

2011-07-18 15:52:24.685 MultiThreadTest[24168:6003] task 1 run …
2011-07-18 15:52:34.708 MultiThreadTest[24168:1b03] task 2 is finished.
2011-07-18 15:52:34.708 MultiThreadTest[24168:6003] task 1 is finished.

因为两个操作提交的时间间隔很近,线程池中的线程,谁先启动是不定的。

那么,如果需要严格意义的顺序执行,怎么办呢?

处理操作之间的依赖关系

如果操作直接有依赖关系,比如第二个操作必须等第一个操作结束后再执行,需要这样写:

queue=[[NSOperationQueue alloc] init];

int index=1;
MyTask *task=[[[MyTask alloc] init] autorelease];
task.operationId=index++;

[queue addOperation:task];

task=[[[MyTask alloc] init] autorelease];
task.operationId=index++;

if ([[queue operations] count]>0) {
    MyTask *theBeforeTask=[[queue operations] lastObject];
    [task addDependency:theBeforeTask];
}

[queue addOperation:task];

这样,即使是多线程情况下,可以看到操作是严格按照先后次序执行的。

控制线程池中的线程数

可以通过类似下面的代码:

[queue setMaxConcurrentOperationCount:2];

来设置线程池中的线程数,也就是并发操作数。默认情况下是-1,也就是没有限制,同时运行队列中的全部操作。

队列的优先级

使用NSOperationQueue简化多线程开发中介绍了iOS的操作队列使用方法。这里补充一下队列的优先级功能。

假设现在队列中有多个操作(NSOperation),现在再向队列中加入新的操作,并且希望新增加的操作排在未执行操作的最前面。这时就需要设置操作的优先级了。

编写了个最简单的NSOperation,头文件:

#import <Foundation/Foundation.h>

@interface MyOperation : NSOperation{
    NSString *name;
}

@property (nonatomic,retain) NSString *name;

@end

实现文件:

#import "MyOperation.h"

@implementation MyOperation

@synthesize name;

-(void) main{
    NSLog(@"run operation: %@",name);
    [NSThread sleepForTimeInterval:3];
}

@end

在控制器里创建3个实例:

- (void)viewDidLoad {
    [super viewDidLoad];
    queue=[[NSOperationQueue alloc] init];
    [queue setMaxConcurrentOperationCount:1];
   
    MyOperation *o1=[[[MyOperation alloc] init] autorelease];
    o1.name=@"o1";
    [queue addOperation:o1];
   
    MyOperation *o2=[[[MyOperation alloc] init] autorelease];
    o2.name=@"o2";
    [queue addOperation:o2];
   
    [NSThread sleepForTimeInterval:1];
   
    MyOperation *o3=[[[MyOperation alloc] init] autorelease];
    o3.name=@"o3";
    [o3 setQueuePriority:NSOperationQueuePriorityHigh];
    [queue addOperation:o3];

运行效果:

2011-07-26 14:47:23.822 NSOperationQueueDemo[27495:6003] run operation: o1

2011-07-26 14:47:26.823 NSOperationQueueDemo[27495:6003] run operation: o3
2011-07-26 14:47:29.824 NSOperationQueueDemo[27495:6203] run operation: o2

可见,操作3成功的插到第一个等待操作(操作2)之前执行了。

[ios2]使用NSOperationQueue简化多线程开发和队列的优先级 【转】的更多相关文章

  1. 使用NSOperationQueue简化多线程开发

    多线程开发是一件需要特别精心的事情,即使是对有多年开发经验的工程师来说. 为了能让初级开发工程师也能使用多线程,同时还要简化复杂性.各种编程工具提供了各自的办法.对于iOS来说,建议在尽可能的情况下避 ...

  2. iOS多线程开发

    概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的,一个复杂的多步操 ...

  3. 玩转iOS开发 - 多线程开发

    前言 本文主要介绍iOS多线程开发中使用的主要技术:NSOperation, GCD. NSThread, pthread. 内容依照开发中的优先推荐使用的顺序进行介绍,涉及多线程底层知识比較多的NS ...

  4. iOS多线程开发--NSThread NSOperation GCD

    多线程 当用户播放音频.下载资源.进行图像处理时往往希望做这些事情的时候其他操作不会被中 断或者希望这些操作过程中更加顺畅.在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势 ...

  5. C#为什么要多线程开发(一)

    首先说下多线程出现的原因: 为了解决负载均衡问题,充分利用CPU资源.为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而不互相干扰.为了处理大量的IO操作时或处理的情况需要花费大量的时间等等 ...

  6. 多线程开发之二 NSOperation

    效果如下: ViewController.h #import <UIKit/UIKit.h> @interface ViewController : UITableViewControll ...

  7. iOS多线程开发资源抢夺和线程间的通讯问题

    说到多线程就不得不提多线程中的锁机制,多线程操作过程中往往多个线程是并发执行的,同一个资源可能被多个线程同时访问,造成资源抢夺,这个过程中如果没有锁机制往往会造成重大问题.举例来说,每年春节都是一票难 ...

  8. IOS多线程知识总结/队列概念/GCD/主队列/并行队列/全局队列/主队列/串行队列/同步任务/异步任务区别(附代码)

    进程:正在进行中的程序被称为进程,负责程序运行的内存分配;每一个进程都有自己独立的虚拟内存空间 线程:线程是进程中一个独立的执行路径(控制单元);一个进程中至少包含一条线程,即主线程 队列 dispa ...

  9. IOS多线程知识总结/队列概念/GCD/串行/并行/同步/异步

    进程:正在进行中的程序被称为进程,负责程序运行的内存分配;每一个进程都有自己独立的虚拟内存空间: 线程:线程是进程中一个独立的执行路径(控制单元);一个进程中至少包含一条线程,即主线程. 队列:dis ...

随机推荐

  1. CentOS上安装WordPress搭建博客平台

    前两天在服务器上搭建了AMP,今天试着在上面安装了一个WordPress(中文:http://cn.wordpress.org/,英文:http://wordpress.org/),我安装的是英文最新 ...

  2. iSwifting社区【www.iSwifting.com】招聘版主

    iSwifting社区[www.iSwifting.com]昨天找来几个主持人.我已经被任命为他们的任务领域. 他们有百度的project噢,还有cocoaChina问答区的活跃人物! 欢迎大家一起学 ...

  3. leetcode第二题--Median of Two Sorted Arrays

    Problem:There are two sorted arrays A and B of size m and n respectively. Find the median of the two ...

  4. unix域套接字UDP网络编程

    unix域套接字UDP网络编程,服务器如下面: #include <stdio.h> #include <stdlib.h> #include <string.h> ...

  5. 用HTML和javascript(JS)计算触屏手机手指滑动方向的演示

    移动终端的流行,程序员希望通过HTML+JS完成触屏动作的识别.下面给出具体实现的例子,供大家参考. 将下面的代码复制并保存,用手机访问,现在的手机浏览器一般都支持触屏,针对本演示来讲就是支持三个js ...

  6. oracle读写文件--利用utl_file包对磁盘文件的读写操作

    oracle读写文件--利用utl_file包对磁盘文件的读写操作 摘要: 用户提出一个需求,即ORACLE中的一个表存储了照片信息,字段类型为BLOB,要求能导出成文件形式. 本想写个C#程序来做, ...

  7. C#/ASP.NET/AJAX

      C#/ASP.NET/AJAX ASP.NET 4.5新特性一:强类型数据绑定(Strongly-Type Data-Bindings) 摘要: 随着ASP.NET 4.5的发布提供了很多的新特性 ...

  8. 在MVC中使用SignalR

    在MVC中使用SignalR 接着上一篇:<ASP.NET SignalR系列>第四课 SignalR自托管(不用IIS) 一.概述 本教程主要阐释了如何在MVC下使用ASP.NET Si ...

  9. 来自 Repository 的一丝线索,Domain Model 再重新设计

    来自 Repository 的一丝线索,Domain Model 再重新设计 写在前面 阅读目录: 疑惑解读 设计窘境 一幅图的灵感 为嘛还是你-Repository 后记 上一篇<No zuo ...

  10. 如何给非AppCompatActivity添加Toolbar?--关于5.0新特性兼容5.0以下设备的探索

    Android支持包22.1引进了AppCompatDelegate 最新22.1版本的支持包引入了大量酷炫的新特性,这些特性将允许我们轻易地将材料设计/API 21+的特性应用到之前的那些老的,不兼 ...