iOS线程

ios并发机制(四) —— NSOperation的串并行和操作

2017-08-16  本文已影响40人  刀客传奇

版本记录

版本号 时间
V1.0 2017.08.16

前言

信号量机制是多线程通信中的比较重要的一部分,对于NSOperation可以设置并发数,但是对于GCD就不能设置并发数了,那么就只能靠信号量机制了。接下来这几篇就会详细的说一下并发机制。感兴趣的可以看这几篇文章。
1. ios并发机制(一) —— GCD中的信号量及几个重要函数
2.ios并发机制(二) —— NSOperation实现多并发之创建任务
3.ios并发机制(三) —— NSOperation实现多并发之创建队列和开启线程

NSOperation串并行的实现

NSOperation的串并行是通过设置最大并发数maxConcurrentOperationCount来实现的。

不管是串行还是并行,开启的线程数目是系统决定的,并不是我们决定的。

1. 串行

下面我们看一下代码。

#import "JJSerialConquenceVC.h"

@interface JJSerialConquenceVC ()

@end

@implementation JJSerialConquenceVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    //创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //设置并发数
    queue.maxConcurrentOperationCount = 1;
    
    [queue addOperationWithBlock:^{
        NSLog(@"1_thread = %@",[NSThread currentThread]);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"2_thread = %@",[NSThread currentThread]);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"3_thread = %@",[NSThread currentThread]);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"4_thread = %@",[NSThread currentThread]);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"5_thread = %@",[NSThread currentThread]);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"6_thread = %@",[NSThread currentThread]);
    }];
}

@end

下面看输出结果

2017-08-16 17:58:58.090660+0800 JJOC[10149:4513595] 1_thread = <NSThread: 0x170276740>{number = 4, name = (null)}
2017-08-16 17:58:58.090813+0800 JJOC[10149:4513595] 2_thread = <NSThread: 0x170276740>{number = 4, name = (null)}
2017-08-16 17:58:58.090868+0800 JJOC[10149:4513595] 3_thread = <NSThread: 0x170276740>{number = 4, name = (null)}
2017-08-16 17:58:58.090919+0800 JJOC[10149:4513595] 4_thread = <NSThread: 0x170276740>{number = 4, name = (null)}
2017-08-16 17:58:58.090967+0800 JJOC[10149:4513595] 5_thread = <NSThread: 0x170276740>{number = 4, name = (null)}
2017-08-16 17:58:58.091014+0800 JJOC[10149:4513595] 6_thread = <NSThread: 0x170276740>{number = 4, name = (null)}

可见,是串行执行的,而且系统只给开了一个线程。

2. 并行

下面我们看一下并行下的代码。

#import "JJSerialConquenceVC.h"

@interface JJSerialConquenceVC ()

@end

@implementation JJSerialConquenceVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    //创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //设置并发数
    queue.maxConcurrentOperationCount = 3;
    
    [queue addOperationWithBlock:^{
        NSLog(@"1_thread = %@",[NSThread currentThread]);
        sleep(1);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"2_thread = %@",[NSThread currentThread]);
        sleep(1);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"3_thread = %@",[NSThread currentThread]);
        sleep(1);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"4_thread = %@",[NSThread currentThread]);
        sleep(1);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"5_thread = %@",[NSThread currentThread]);
        sleep(1);
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"6_thread = %@",[NSThread currentThread]);
        sleep(1);
    }];
}

@end

看输出结果

2017-08-16 18:02:38.893083+0800 JJOC[10154:4514418] 1_thread = <NSThread: 0x1742716c0>{number = 4, name = (null)}
2017-08-16 18:02:38.893199+0800 JJOC[10154:4514414] 2_thread = <NSThread: 0x1700746c0>{number = 3, name = (null)}
2017-08-16 18:02:38.893644+0800 JJOC[10154:4514415] 3_thread = <NSThread: 0x174271840>{number = 5, name = (null)}
2017-08-16 18:02:39.897629+0800 JJOC[10154:4514414] 5_thread = <NSThread: 0x1700746c0>{number = 3, name = (null)}
2017-08-16 18:02:39.897613+0800 JJOC[10154:4514418] 4_thread = <NSThread: 0x1742716c0>{number = 4, name = (null)}
2017-08-16 18:02:39.898884+0800 JJOC[10154:4514415] 6_thread = <NSThread: 0x174271840>{number = 5, name = (null)}

可以看见系统给开启了3个线程,执行顺序也变成了123546,说明是并行的。


操作依赖

有的时候我们希望执行完一个任务再去执行另外一个任务,这个时候就需要操作依赖了。比如说A、B两个操作,我们希望执行完A操作以后再去执行B操作,那么我们就可以设置B依赖于A,具体就是使用方法addDependency:

下面还是直接看代码。

#import "JJAddDependencyVC.h"

@interface JJAddDependencyVC ()

@end

@implementation JJAddDependencyVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1_thread = %@",[NSThread currentThread]);
        
    }];
    
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"2_thread = %@",[NSThread currentThread]);
        
    }];
    
    [operation2 addDependency:operation1];
    
    [queue addOperation:operation1];
    [queue addOperation:operation2];
}

@end

下面看输出结果

2017-08-16 18:15:05.030277+0800 JJOC[10159:4515800] 1_thread = <NSThread: 0x17007d5c0>{number = 4, name = (null)}
2017-08-16 18:15:05.030469+0800 JJOC[10159:4515800] 2_thread = <NSThread: 0x17007d5c0>{number = 4, name = (null)}

可见,通过操作依赖实现了运行顺序的控制。

下面说一点题外话,就是GCD中线程同步的实现。

group实现

#import "JJGCDGroupVC.h"

@interface JJGCDGroupVC ()

@end

@implementation JJGCDGroupVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    dispatch_queue_t queue = dispatch_queue_create(0, 0);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"task 1 on %@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"task 2 on %@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify( group, queue, ^{
        NSLog( @"all task done %@", [NSThread currentThread] );
        NSLog(@"可以执行其他的任务了");
    } );
}

@end

下面看输出结果

2017-08-16 18:35:32.894210+0800 JJOC[10163:4518939] task 1 on <NSThread: 0x174079900>{number = 4, name = (null)}
2017-08-16 18:35:32.894343+0800 JJOC[10163:4518939] task 2 on <NSThread: 0x174079900>{number = 4, name = (null)}
2017-08-16 18:35:32.894393+0800 JJOC[10163:4518939] all task done <NSThread: 0x174079900>{number = 4, name = (null)}
2017-08-16 18:35:32.894424+0800 JJOC[10163:4518939] 可以执行其他的任务了

可见开启了线程并实现了任务的同步。

信号量semaphore实现

    dispatch_semaphore_t sem =     dispatch_semaphore_create(0);
    [networkManager requestWithDelay:5 completion:^{
        dispatch_semaphore_signal(sem);//+1
    }];
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);//-1
    NSLog(@"OK");

信号量方面的知识,前几篇已经说过了,这里很清晰的是等待网络请求结束,才可以行NSLog(@"OK");这段代码。

barrier

barrier阻塞的使用起来就很方便了,它就相当于一个栅栏,将不同的任务块区分开来,如下图所示。

barrier

这里需要主要的是,barrier只能用于并发队列不能用于全局队列。

下面看代码。

#import "JJGCDBarrierVC.h"

@interface JJGCDBarrierVC ()

@end

@implementation JJGCDBarrierVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("cc.imguiqing", DISPATCH_QUEUE_CONCURRENT);
    
    //开启异步任务
    
    dispatch_async(queue, ^{
        NSLog(@"task 1 on %@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"task 2 on %@",[NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"barrier ==========");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"task 3 on %@",[NSThread currentThread]);
    });
}

@end

下面看输出结果

2017-08-16 18:49:07.271659+0800 JJOC[10166:4521475] task 1 on <NSThread: 0x174078380>{number = 3, name = (null)}
2017-08-16 18:49:07.271736+0800 JJOC[10166:4521478] task 2 on <NSThread: 0x170261b80>{number = 4, name = (null)}
2017-08-16 18:49:07.271761+0800 JJOC[10166:4521478] barrier ==========
2017-08-16 18:49:07.271799+0800 JJOC[10166:4521478] task 3 on <NSThread: 0x170261b80>{number = 4, name = (null)}

这个很好理解就不多说了。


一些其他方法

1. - (void)cancel;

2. - (void)cancelAllOperations;

3. @property (getter=isSuspended) BOOL suspended;

上面所说的名词,暂停和取消是有区别的,暂停的意思就是操作以后还可以回复,而取消的意思就是所有的操作清空,不能继续执行其他的剩下的操作了。

后记

未完,待续~~~

上一篇下一篇

猜你喜欢

热点阅读