松下 洗碗机洗碗机多少钱?性价比怎么样

GCD为Grand Central Dispatch的缩写。Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法。在Mac OS X 10.6雪豹中首次推出,并在最近引入到了iOS4.0。GCD是一个替代诸如NSThread等技术的很高效和强大的技术。GCD完全可以处理诸如 数据锁定和资源泄漏等复杂的异步编程问题。
GCD可以完成很多事情,但是这里仅关注在iOS应用中实现多线程所需的一些基础知识。在开始之前,需要理解是要提供给GCD队列的是代码块,用于在系统或者用户创建的的队列上调度运行。
声明一个队列
如下会返回一个用户创建的队列:dispatch_queue_t myQueue = dispatch_queue_create(“com.iphonedevblog.post”, NULL);其中,第一个参数是标识队列的,第二个参数是用来定义队列的参数(目前不支持,因此传入NULL)。
执行一个队列  
如下会异步执行传入的代码:
dispatch_async(myQueue, ^{ [self doSomething]; });其中,首先传入之前创建的队列,然后提供由队列运行的代码块。
声明并执行一个队列
如果不需要保留要运行的队列的引用,可以通过如下代码实现之前的功能: dispatch_async(dispatch_queue_create (“com.iphonedevblog.post”, NULL), ^{ [self doSomething]; });如果需要暂停一个队列,可以调用如下代码。暂停一个队列会阻止和该队列相关的所有代码运行。dispatch_suspend(myQueue);暂停一个队列  
如果暂停一个队列不要忘记恢复。暂停和恢复的操作和内存管理中的retain和release类似。调用dispatch_suspend会增加暂 停计数,而dispatch_resume则会减少。队列只有在暂停计数变成零的情况下才开始运行。dispatch_resume(myQueue);恢复一个队列  从队列中在主线程运行代码 有 些操作无法在异步队列运行,因此必须在主线程(每个应用都有一个)上运行。UI绘图以及任何对NSNotificationCenter的调用必须在主线 程长进行。在另一个队列中访问主线程并运行代码的示例如下:dispatch_sync(dispatch_get_main_queue(), ^{ [self dismissLoginWindow]; });注意,dispatch_suspend (以及dispatch_resume)在主线程上不起作用。
使用GCD,可以让你的程序不会失去响应. 多线程不容易使用,用了GCD,会让它变得简单。你无需专门进行线程管理, 很棒!
让你的程序保持响应的原则:
1. 不要柱塞主线程
2. 把工作一到其他线程中做。
3. 做完后更新主线程的UI.
举例说明:
没有GCD的代码:
- (void)addTweetWithMsg:(NSString*)msg url:(NSURL*)url {
// 在主线程调用。
DTweet *tw = [[DTweet alloc] initWithMsg:msg];
[tweets addTweet:tw display:YES];
tw.img = [imageCache getImgFromURL:url];//bottle neck
[tweets updateTweet:tw display:YES];
[tw release];
有GCD的代码:
- (void)addTweetWithMsg:(NSString*)msg url:(NSURL*)url {
//在主线程调用。
DTweet *tw = [[DTweet alloc] initWithMsg:msg];
[tweets addTweet:tw display:YES];
dispatch_async(image_queue, ^{
tw.img = [imageCache getImgFromURL:url];//放到一个异步队列里。
dispatch_async(main_queue, ^{
[tweets updateTweet:tw display:YES];//放到异步的主线程里。
[tw release];
1. GCD is part of libSystem.dylib
2. #include &dispatch/dispatch.h&
NSThread的方法:代码如下:
- (void)viewDidLoad
[super viewDidLoad];
NSThread *thread1=[[NSThread alloc]initWithTarget:self selector:@selector(print1) object:nil];
[thread1 start];
NSThread *thread2=[[NSThread alloc]initWithTarget:self selector:@selector(print2) object:nil];
[thread2 start];
-(void)print1{
for (int i=0; i&100; i++) {
NSLog(@"我是print1正在执行%d",i);
-(void)print2{
for (int i=0; i&100; i++) {
NSLog(@"print2正在执行%d",i);
NSInvocationOperation 的方法:代码如下
NSInvocationOperation *operation1=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(print1) object:@"1"];
NSInvocationOperation *operation2=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(print2) object:@"2"];//当然这里可以用一个方法。
NSOperationQueue *queue=[[NSOperationQueue alloc]init];
[queue addOperation:operation1];
[queue addOperation:operation2];
GCD的方法:代码如下:
dispatch_queue_t t1=dispatch_queue_create("1", NULL);
dispatch_queue_t t2=dispatch_queue_create("2", NULL);
dispatch_async(t1, ^{
[self print1];
dispatch_async(t2, ^{
[self print2];
Push的原理:
图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider。
APNS 是Apple Push Notification Service(Apple Push服务器)的缩写,是苹果的服务器。
上图可以分为三个阶段。
第一阶段:.net应用程序把要发送的消息、目的iPhone的标识打包,发给APNS。
第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发到iPhone。
第三阶段:iPhone把发来的消息传递给相应的应用程序, 并且按照设定弹出Push通知。
http://blog.csdn.net/zhuqilin0/article/details/6527113
//消息推送机制
看内存泄露时候:在搜索中搜索run 找到Run Static Snalyzer .多线程中为什么要使用Dispatch_after实现代码的延时执行 - 简书
多线程中为什么要使用Dispatch_after实现代码的延时执行
iOS中timer相关的延时调用,常见的有NSObject中的performSelector:withObject:afterDelay:这个方法在调用的时候会设置当前runloop中timer,还有一种延时,直接使用NSTimer来配置任务。
这两种方式都一个共同的前提,就是当前线程里面需要有一个运行的runloop并且这个runloop里面有一个timer。
我们知道:只有主线程会在创建的时候默认自动运行一个runloop,并且有timer,普通的子线程是没有这些的。这样就带来一个问题了,有些时候我们并不确定我们的模块是不是会异步调用到,而我们在写这样的延时调用的时候一般都不会去检查运行时的环境,这样在子线程中被调用的时候,我们的代码中的延时调用的代码就会一直等待timer的调度,但是实际上在子线程中又没有这样的timer,这样我们的代码就永远不会被调到。
下面的代码展示了performSelector和dispatch_time的不同
/ testDispatch_after 延时添加到队列
/-(void) testDispatch_after{
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"3秒后添加到队列");
});}-(void) testDelay{
NSLog(@"3秒后testDelay被执行");}/ dispatch_barrier_async 栅栏的作用 */-(void) testDispatch_Barrier{
//dispatch_queue_t gcd = dispatch_queue_create("这是序列队列", NULL);
dispatch_queue_t gcd = dispatch_queue_create("这是并发队列", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(gcd, ^{
NSLog(@"b0");
//这个selector不会执行
[self performSelector:@selector(testDelay) withObject:nil afterDelay:3];
//代码会执行
//[self testDispatch_after];
dispatch_release(gcd);}
在有多线程操作的环境中,这样performSelector的延时调用,其实是缺乏安全性的。我们可以用另一套方案来解决这个问题,就是使用GCD中的dispatch_after来实现单次的延时调用iOS那些事(39)
Grand Central Dispatch是苹果过去几年创造出来的非常强大的API,在Let’s Build系列的最新一期中,我们将探究dispatch_queue基础功能的重新实现。该主题是Rob Rixr提议的。
dispatch queue是一个工作队列,其背后是一个全局的线程池。特别是,提交到队列的任务会在后台线程异步执行。所有线程共享同一个后台线程池,这使得系统更有效率。
这也是我将要模仿的API的精髓部分。GCD还提供了很多精心设计的功能,为了简单起见,本文将把它们都略过。比如线程池的线程数量会根据待完成的任务数和系统CPU的使用率动态作调整。如果你已经有一堆任务占满了CPU,然后再扔给它另一个任务,GCD不会再创建另外的工作线程,因为CPU已经被100%占用,再执行别的任务只会更低效。这里我会写死线程数而不做模拟动态调整。同时我还会忽略并发队列的目标队列和调度屏障功能。
我们目标是聚焦于dispatch queue的真髓:能串行、能并行、能同步、能异步以及共享同一个线程池。
和以往一样,今天文章的代码可以在GitHub上找到:
如果你想读的过程中自己探索,以上是所有代码。
GCD是基于C语言的 API。虽然最新的系统版本中GCD对象已经转成了Objective-C对象,但API仍保持纯C接口(加了block扩展)。这对实现底层接口是好事,GCD提供了出色而简单的接口,但对我个人而言,我更喜欢用Objective-C来实现。
Objective-C类名称为MADispatchQueue,包含四个调用方法:
1.获取全局共享队列的方法。GCD有多个不同优先级的全局队列,出于简单考虑,我们在实现中保留一个。
2.串行和并行队列的初始化函数。
3.异步分发调用
4.同步分发调用
接口声明:
@interface MADispatchQueue : NSObject
+ (MADispatchQueue *)globalQ
- (id)initSerial: (BOOL)
- (void)dispatchAsync: (dispatch_block_t)
- (void)dispatchSync: (dispatch_block_t)
接下来的目标就是实现这些方法的功能。
线程池接口
队列后面的线程池接口更简单。它将真正执行提交的任务。队列负责在合适的时间把已入队的任务提交给它。
线程池只做一件事:投递任务并运行。对应地,一个接口只有一个方法:
@interface MAThreadPool : NSObject
- (void)addBlock: (dispatch_block_t)
由于这是核心部分,我们先实现它。
线程池实现
首先看实例变量。线程池能被多个内部线程或外部线程访问,因此需要线程安全。而在可能的情况下,GCD会使用原子操作,而我这里以一种以前比较流行的方式-加锁。我需要知道锁处于等待和锁相关的信号,而不仅仅强制其互斥,因此我使用NSCondition而不是NSLock。如果你不熟悉,NSCondition 本质上还是锁,只是添加了一个条件变量:
NSCondition *_lock;
想要知道什么时候增加工作线程,我要知道线程池里的线程数,有多少线程正被占用以及所能拥有的最大线程数:
NSUInteger _threadC
NSUInteger _activeThreadC
NSUInteger _threadCountL
最后,得有一个NSMutableArray类型的block列表模拟一个队列,从队列后端添加新block,从队列前端删除:
NSMutableArray *_blocks;
初始化函数很简单。初始化锁和block数组,随便设置一个最大线程数比如128:
- (id)init {
if((self = [super init])) {
_lock = [[NSCondition alloc] init];
_blocks = [[NSMutableArray alloc] init];
_threadCountLimit = 128;
return self;
工作线程运行了一个简单的无限循环。只要block数组为空,它将一直等待。一旦有block加入,它将被从数组中取出并执行。同时将活动线程数加1,完成后活动线程数减1:
- (void)workerThreadLoop: (id)ignore {
首先要获取锁。注意需要在循环开始前获得。至于原因,等写到循环结束时你就会明白。
[_lock lock];
无限循环开始:
while(1) {
如果队列为空,等待锁:
while([_blocks count] == 0) {
[_lock wait];
注意:这里是内循环结束而非if判断。原因是由于虚假唤醒。简单说来就是wait 在没有信号通知的情况下也有可能返回,目前为此,条件检测的正确方式是当wait 返回时重新进行条件检测。
一旦有队列中有block,取出:
dispatch_block_t block = [_blocks firstObject];
[_blocks removeObjectAtIndex: 0];
活动线程计数加,表示有新线程正在处理任务:
现在执行block,我们先得释放锁,不然代码并发执行时会出现死锁:
[_lock unlock]
安全释放锁后,执行block
block执行完毕,活动线程计数减1。该操作必须在锁内做,以避免竞态条件,最后是循环结束:
[_lock lock];
_activeThreadCount
现在你该明白为什么需要在进入循环前获得锁了。循环的最后是在锁内减少活动线程计数。循环开始检测block队列。通过在循环外第一次获得锁,后续循环迭代能够使用一个锁来完成,而不是锁,解锁,然后再立即上锁。
下面是 addBlock:
- (void)addBlock: (dispatch_block_t)block {
这里唯一需要做的是获得锁:
[_lock lock];
添加一个新的block到block队列:
[_blocks addObject: block]
如果有一个空闲的工作线程去执行这个block的话,这里什么都不需要做。如果没有足够的工作线程去处理等待的block,而工作线程数也没超限,则我们需要创建一个新线程:
NSUInteger idleThreads = _threadCount - _activeThreadC
if([_blocks count] & idleThreads && _threadCount & _threadCountLimit) {
[NSThread detachNewThreadSelector: @selector(workerThreadLoop:)
toTarget: self
withObject: nil];
_threadCount++;
一切准备就绪。由于空闲线程都在休眠,唤醒它:
[_lock signal]
最后释放锁:
[_lock unlock];
线程池能在达到预设的最大线程数前创建工作线程,以处理对应的block。现在以此为基础实现队列。
和线程池一样,队列使用锁保护其内容。和线程池不同的是,它不需要等待锁,也不需要信号触发,仅仅是简单互斥即可,因此采用 NSLock:
NSLock *_lock;
和线程池一样,它把 pending block存在NSMutableArray里。
NSMutableArray *_pendingBlocks;
标识是串行还是并行队列:
如果是串行队列,还需要标识当前是否有线程正在运行:
BOOL _serialR
并行队列里有无线程都一样处理,所以无需关注。
全局队列是一个全局变量,共享线程池也一样。它们都在+initialize里创建:
static MADispatchQueue *gGlobalQ
static MAThreadPool *gThreadP
+ (void)initialize {
if(self == [MADispatchQueue class]) {
gGlobalQueue = [[MADispatchQueue alloc] initSerial: NO];
gThreadPool = [[MAThreadPool alloc] init];
由于+initialize里已经初始化了,+globalQueue 只需返回该变量。
+ (MADispatchQueue *)globalQueue {
return gGlobalQ
这里所做的事情和dispatch_once是一样的,但是实现GCD API的时候使用GCD API有点自欺欺人,即使代码不一样。
初始化一个队列:初始化lock 和pending Blocks,设置_serial变量:
- (id)initSerial: (BOOL)serial {
if ((self = [super init])) {
_lock = [[NSLock alloc] init];
_pendingBlocks = [[NSMutableArray alloc] init];
return self;
实现剩下的公有API前,我们需先实现一个底层方法用于给线程分发一个block,然后继续调用自己去处理另一个block:
- (void)dispatchOneBlock {
整个生命周期所做的是在线程池上运行block,分发代码如下:
[gThreadPool addBlock: ^{
然后取队列中的第一个block,显然这需要在锁内完成,以避免出现问题:
[_lock lock];
dispatch_block_t block = [_pendingBlocks firstObject];
[_pendingBlocks removeObjectAtIndex: 0];
[_lock unlock];
取到了block又释放了锁,block接下来可以安全地在后台线程执行了:
如果是并行执行的话就不需要再做啥了。如果是串行执行,还需要以下操作:
if(_serial) {
串行队列里将会积累别的block,但不能执行,直到先前的block完成。block完成后,dispatchOneBlock 接下来会看是否还有其他的block被添加到队列里面。若有,它调用自己去处理下一个block。若无,则把队列的运行状态置为NO:
[_lock lock];
if([_pendingBlocks count] & 0) {
[self dispatchOneBlock];
_serialRunning = NO;
[_lock unlock];
用以上方法来实现dispatchAsync:就非常容易了。添加block到pending
block队列,合适的时候设置状态并调用dispatchOneBlock:
- (void)dispatchAsync: (dispatch_block_t)block {
[_lock lock];
[_pendingBlocks addObject: block];
如果串行队列空闲,设置队列状态为运行并调用dispatchOneBlock 进行处理。
if(_serial && !_serialRunning) {
_serialRunning = YES;
[self dispatchOneBlock];
如果队列是并行的,直接调用dispatchOneBlock。由于多个block能并行执行,所以这样能保证即使有其他block正在运行,新的block也能立即执行。
} else if (!_serial) {
[self dispatchOneBlock];
如果串行队列已经在运行,则不需要另外做处理。因为block执行完成后对dispatchOneBlock 的调用最终会调用加入到队列的block。接着释放锁:
[_lock unlock];
对于 dispatchSync: GCD的处理更巧妙,它是直接在调用线程上执行block,以防止其他block在队列上执行(如果是串行队列)。在此我们不用做如此聪明的处理,我们仅仅是对dispatchAsync:进行封装,让其一直等待直到block执行完成。
它使用局部NSCondition进行处理,另外使用一个done变量来指示block何时完成:
- (void)dispatchSync: (dispatch_block_t)block {
NSCondition *condition = [[NSCondition alloc] init];
__block BOOL done = NO;
下面是异步分发block。block里面调用传入的block,然后设置done的值,给condition发信号
[self dispatchAsync: ^{
[condition lock];
done = YES;
[condition signal];
[condition unlock];
在调用线程里面,等待信号done ,然后返回
[condition lock];
while (!done) {
[condition wait];
[condition unlock];
到此。block的执行就结束了,这也是MADispatchQueue API的最后一点内容。
全局线程池可以使用block队列和智能产生的线程实现。使用一个共享全局线程池,就能构建一个能提供基本的串行/并行、同步/异步功能的dispatch queue。这样就重建了一个简单的GCD,虽然缺少了很多非常好的特性且更低效率。但这能让我们瞥见其内部工作过程,揭示了它毕竟不是那么神秘(除dispatch_once比较神秘外)
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:37676次
排名:千里之外
原创:21篇
转载:19篇
(1)(2)(2)(2)(5)(2)(6)(10)(1)(2)(4)(3)标签:至少1个,最多5个
iOS多线程总结
1、iOS多线程对比
1.NSThread每个NSThread对象对应一个线程,真正最原始的线程。1)优点:NSThread 轻量级最低,相对简单。2)缺点:手动管理所有的线程活动,如生命周期、线程同步、睡眠等。
2.NSOperation自带线程管理的抽象类。1)优点:自带线程周期管理,操作上可更注重自己逻辑。2)缺点:面向对象的抽象类,只能实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。
3.GCDGrand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。1)优点:最高效,避开并发陷阱。2)缺点:基于C实现。
4.选择小结1)简单而安全的选择NSOperation实现多线程即可。2)处理大量并发数据,又追求性能效率的选择GCD。3) 在频繁使用多线程的程序中一般不建议使用NSThread
2、NSThread
NSThread是Objective-C 中提供的对POSIX 线程 API的封装。
直接使用线程可能会引发的一个问题是,如果你的代码和所基于的框架代码都创建自己的线程时,那么活动的线程数量有可能以指数级增长。这在大型工程中是一个常见问题。例如,在 8 核 CPU 中,你创建了 8 个线程来完全发挥 CPU 性能。然而在这些线程中你的代码所调用的框架代码也做了同样事情(因为它并不知道你已经创建的这些线程),这样会很快产生成成百上千的线程。代码的每个部分自身都没有问题,然而最后却还是导致了问题。使用线程并不是没有代价的,每个线程都会消耗一些内存和内核资源。
2.1、三种实现开启线程方式
动态实例化
NSThread *thread = [[NSThread alloc] initWithTarget:self
selector:@selector(loadImageSource:) object:imgUrl];
thread.threadPriority = 1;// 设置线程的优先级(0.0 - 1.0,1.0最高级)
[thread start];
静态实例化
[NSThread detachNewThreadSelector:@selector(loadImageSource:) toTarget:self withObject:imgUrl];
隐式实例化
[self performSelectorInBackground:@selector(loadImageSource:) withObject:imgUrl];
//在指定线程上操作
[self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES];
需要继承NSThread,并且重写main方法,然后通过start方法启动。
2.2、常见操作方式
//取消线程
//启动线程
//判断某个线程的状态的属性
@property (readonly, getter=isExecuting) BOOL
@property (readonly, getter=isFinished) BOOL
@property (readonly, getter=isCancelled) BOOL
//设置和获取线程名字
-(void)setName:(NSString *)n;
-(NSString *)
//获取当前线程信息
+ (NSThread *)currentT
//获取主线程信息
+ (NSThread *)mainT
//使当前线程暂停一段时间,或者暂停到某个时刻
+ (void)sleepForTimeInterval:(NSTimeInterval)
+ (void)sleepUntilDate:(NSDate *)
3、GCD(Grand Centra Dispatch)
通过 GCD,开发者不用再直接跟线程打交道了,只需要向队列中添加代码块即可,GCD 在后端管理着一个线程池。GCD 不仅决定着你的代码块将在哪个线程被执行,它还根据可用的系统资源对这些线程进行管理。这样可以将开发者从线程管理的工作中解放出来,通过集中的管理线程,来缓解大量线程被创建的问题。
GCD 带来的另一个重要改变是,作为开发者可以将工作考虑为一个队列,而不是一堆线程,这种并行的抽象模型更容易掌握和使用。
GCD 公开有 5 个不同的队列:运行在主线程中的 main queue,3 个不同优先级的后台队列,以及一个优先级更低的后台队列(用于 I/O)。 另外,开发者可以创建自定义队列:串行或者并行队列。自定义队列非常强大,在自定义队列中被调度的所有 block 最终都将被放入到系统的全局队列中和线程池中。
&center&&/center&
在绝大多数情况下使用默认的优先级队列就可以了。如果执行的任务需要访问一些共享的资源,那么在不同优先级的队列中调度这些任务很快就会造成不可预期的行为。这样可能会引起程序的完全挂起,因为低优先级的任务阻塞了高优先级任务,使它不能被执行。
3.1、三种线程队列类型
主线程队列 main queue
它是全局可用的serial queue,它是在应用程序主线程上执行任务的。
dispatch_get_main_queue()
并行队列global dispatch queue
又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
这里的两个参数得说明一下:第一个参数用于指定优先级,分别使用DISPATCH_QUEUE_PRIORITY_HIGH和DISPATCH_QUEUE_PRIORITY_LOW两个常量来获取高和低优先级的两个queue;第二个参数目前未使用到,默认0即可。
串行队列serial queues
又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。
dispatch_queue_create("", NULL);
凡是自己创建的队列默认为串行队列。可在创建参数上添加DISPATCH_QUEUE_CONCURRENT,构建并行队列。
//串行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
3.2、两种线程类型
dispatch_sync(&#queue#&, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
dispatch_async(&#queue#&, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
3.3、6种多线程实现
后台执行线程创建
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self loadImageSource:imgUrl1];
UI线程执行(只是为了测试,长时间加载内容不放在主线程)
dispatch_async(dispatch_get_main_queue(), ^{
[self loadImageSource:imgUrl1];
一次性执行(常用来写单例)
static dispatch_once_t onceT
dispatch_once(&onceToken, ^{
[self loadImageSource:imgUrl1];
并发地执行循环迭代
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
size_t count = 10;
dispatch_apply(count, queue, ^(size_t i) {
NSLog(@"循环执行第%li次",i);
[self loadImageSource:imgUrl1];
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self loadImageSource:imgUrl1];
自定义dispatch_queue_t
dispatch_queue_t urls_queue = dispatch_queue_create("", NULL);
dispatch_async(urls_queue, ^{
[self loadImageSource:imgUrl1];
3.4、队列组(dispatch_group_t)
队列组可以将很多队列添加到一个组里,这样做的好处是,当这个组里所有的任务都执行完了,队列组会通过一个方法通知我们。
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"group1");
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"group2");
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"group3");
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"updateUi");
dispatch_release(group);
3.5、其他用法
dispatch_barrier_async的使用
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行。
dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"dispatch_async1");
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:4];
NSLog(@"dispatch_async2");
dispatch_barrier_async(queue, ^{
NSLog(@"dispatch_barrier_async");
[NSThread sleepForTimeInterval:4];
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"dispatch_async3");
打印结果: 16:20:33.967 gcdTest[] dispatch_async1 16:20:35.967 gcdTest[] dispatch_async2 16:20:35.967 gcdTest[] dispatch_barrier_async 16:20:40.970 gcdTest[] dispatch_async3
dispatch_apply的使用
执行某个代码片段N次。
dispatch_apply(5, globalQ, ^(size_t index) {
// 执行5次
4、NSOperation
NSOperation 是苹果公司对 GCD 的封装,完全面向对象,NSOperation 和 NSOperationQueue 分别对应 GCD 的任务和队列 。操作步骤也很好理解:
将要执行的任务封装到一个 NSOperation 对象中。
将此任务添加到一个 NSOperationQueue 对象中。
4.1、NSOperation类型
NSOperation 只是一个抽象类,所以不能封装任务。但它有 2 个子类用于封装任务。分别是:NSInvocationOperation 和 NSBlockOperation 。创建一个 Operation 后,需要调用 start 方法来启动任务,它会 默认在当前队列同步执行。当然你也可以在中途取消一个任务,只需要调用其 cancel方法即可。
//1.创建NSInvocationOperation对象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
//2.开始执行
[operation start];
//1.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
//2.开始任务
[operation start];
自定义Operation
除了上面的两种 Operation 以外,我们还可以自定义 Operation。自定义 Operation 需要继承 NSOperation 类,并实现其 main() 方法,因为在调用 start() 方法的时候,内部会调用 main() 方法完成相关逻辑。所以如果以上的两个类无法满足你的欲望的时候,你就需要自定义了。你想要实现什么功能都可以写在里面。除此之外,你还需要实现 cancel() 在内的各种方法。
如果是需要并发执行的话,还必须要重写start
asynchronous
finished方法。
4.2、两种队列(NSOperation)
NSOperationQueue 有两种不同类型的队列:主队列和自定义队列。主队列运行在主线程之上,而自定义队列在后台执行。在两种类型中,这些队列所处理的任务都使用 NSOperation 的子类来表述。
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //自定义队列
//添加一个NSOperation
[queue addOperation:operation]
//添加一组NSOperation
[queue addOperations:operations waitUntilFinished:NO
//添加一个block形式的Operation
[queue addOperationWithBlock:^{
//执行一个Block的操作
[queue setMaxConcurrentOperationCount:1];
//单个NSOperation取消
[operation cancel]
//取消NSOperationQueue中的所有操作
[queue cancelAllOperations]
// 暂停queue
[queue setSuspended:YES];
// 继续queue
[queue setSuspended:NO];
我们可以通过设置maxConcurrentOperationCount 属性来控制并发任务的数量,当设置为 1 时, 那么它就是一个串行队列。主对列默认是串行队列,这一点和 dispatch_queue_t是相似的。
NSOperation 有一个非常实用的功能,那就是添加依赖。比如有 3 个任务:A: 从服务器上下载一张图片,B:给这张图片加个水印,C:把图片返回给服务器。这时就可以用到依赖了:
//1.任务一:下载图片
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
//2.任务二:打水印
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"打水印
- %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
//3.任务三:上传图片
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"上传图片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
//4.设置依赖
[operation2 addDependency:operation1];
//任务二依赖任务一
[operation3 addDependency:operation2];
//任务三依赖任务二
//5.创建队列并加入任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
5、使用选择
目前在 iOS 和 OS X 中有两套先进的同步 API 可供我们使用:NSOperation 和 GCD 。其中 GCD 是基于 C 的底层的 API ,而 NSOperation 则是 GCD 实现的 Objective-C API。 虽然 NSOperation 是基于 GCD 实现的, 但是并不意味着它是一个 GCD 的 “dumbed-down” 版本, 相反,我们可以用NSOperation 轻易的实现一些 GCD 要写大量代码的事情。 因此, NSOperationQueue 是被推荐使用的, 除非你遇到了 NSOperationQueue 不能实现的问题。
为什么优先使用NSOperationQueue而不是GCD
曾经我有一段时间我非常喜欢使用GCD来进行并发编程,因为虽然它是C的api,但是使用起来却非常简单和方便, 不过这样也就容易使开发者忘记并发编程中的许多注意事项和陷阱。比如你可能写过类似这样的代码(这样来请求网络数据):
dispatch_async(_Queue, ^{
//请求数据
NSData *data = [NSData dataWithContentURL:[NSURL URLWithString:@"/a.png"]];
dispatch_async(dispatch_get_main_queue(), ^{
[self refreshViews:data];
没错,它是可以正常的工作,但是有个致命的问题:这个任务是无法取消的 dataWithContentURL:是同步的拉取数据,它会一直阻塞线程直到完成请求,如果是遇到了超时的情况,它在这个时间内会一直占有这个线程;在这个期间并发队列就需要为其他任务新建线程,这样可能导致性能下降等问题。因此我们不推荐这种写法来从网络拉取数据。
操作队列(operation queue)是由 GCD 提供的一个队列模型的 Cocoa 抽象。GCD 提供了更加底层的控制,而操作队列则在 GCD 之上实现了一些方便的功能,这些功能对于 app 的开发者来说通常是最好最安全的选择。NSOperationQueue相对于GCD来说有以下优点:
提供了在 GCD 中不那么容易复制的有用特性。
可以很方便的取消一个NSOperation的执行
可以更容易的添加任务的依赖关系
提供了任务的状态:isExecuteing, isFinished.
0 收藏&&|&&12
你可能感兴趣的文章
5 收藏,149
2 收藏,470
4 收藏,907
分享到微博?
技术专栏,帮你记录编程中的点滴,提升你对技术的理解收藏感兴趣的文章,丰富自己的知识库
明天提醒我
我要该,理由是:
扫扫下载 App

我要回帖

更多关于 松下洗碗机怎么样 的文章

 

随机推荐