多线程实战(线程组+信号量+操作队列)

生产问题:

1. 上传100个psd
2. 每个psd内 100个图
3. 需要知道上传完每个psd 和 所有psd的时
思路:
    1. n个psd之间使用串行处理;
    2. psd中的n个图片使用并发处理, 使用信号量控制并发数;
    3. 图片上传内部又有3个异网络请求, 使用线程组实现穿透同步;

psd实现类:

//头文件
@interface PSDModel : NSObject
//psd开始时间
@property (nonatomic, strong) NSString *startTime;
//psd结束时间
@property (nonatomic, strong) NSString *endTime;
//psd  id
@property (nonatomic, assign) NSInteger PID;
//图片集合
@property (nonatomic, strong) NSArray *dataSource;
///完成个数
@property (nonatomic, strong) NSString * doneCount;
//信号量, 用来控制内部并发数量
@property (nonatomic, strong) dispatch_semaphore_t semaphore;
@end
//实现
#import "PSDModel.h"

@implementation PSDModel
- (instancetype)init
{
    self = [super init];
    if (self) {
        _semaphore = dispatch_semaphore_create(30);
    }
    return self;
}
@end

图片实现类:

//头文件
@interface Model : NSObject
//记录开始时间
@property (nonatomic, strong) NSString *startTime;
//记录结尾时间
@property (nonatomic, strong) NSString *endTime;

@property (nonatomic, strong) NSString *imageStr;
//id
@property (nonatomic, assign) NSInteger ID;
//线程组
@property (nonatomic, strong) dispatch_group_t uploadGroup;
//记录上传错误次数
@property (nonatomic, assign) NSInteger uploadErrorCount;
@end
//实现:
#import "Model.h"

@implementation Model

- (instancetype)init
{
    self = [super init];
    if (self) {
        _uploadGroup = dispatch_group_create();
    }
    return self;
}

@end

主类:

#import "ViewController.h"
#import "PSDModel.h"
#import "Model.h"
typedef void (^BackResult)(NSInteger);
@interface ViewController ()

{
    ///psd数量
    NSInteger _psdCount;
    ///每个psd中图片个数
    NSInteger _psdImgCount;
}
//操作队列
@property (nonatomic, strong) NSOperationQueue *taskQueue;
//存放psd
@property (nonatomic, strong) NSMutableArray * tempArray;
//当前正在执行的psd
@property (nonatomic, strong) PSDModel *  currentPsdModel;
//记录暂停
@property (nonatomic, assign) BOOL isStop;

///记录所有的psd时间
@property (nonatomic, strong) NSString *startTime;
@property (nonatomic, strong) NSString *endTime;

@end

@implementation ViewController

-(NSMutableArray *)tempArray{
    if (_tempArray == nil) {
        _tempArray = [NSMutableArray array];
    }
    return _tempArray;
}

/**
 1. 上传100个psd
 2. 每个psd内 100个图
 3. 需要知道上传完每个psd 和 所有psd的时间
 */
- (void)viewDidLoad {
    [super viewDidLoad];
    [self setDataSource];
}

//数据构造
- (void)setDataSource
{
    _psdCount = 10;
    _psdImgCount = 100;
    
    //初始化数据
    _taskQueue = [[NSOperationQueue alloc] init];
    
    for (int n=0; n<_psdCount; n++) {
        NSMutableArray * array = [NSMutableArray array];//模拟一个psd
        PSDModel * psdModel = [[PSDModel alloc] init];
        for (int i=0; i<_psdImgCount; i++) {
            Model * model = [[Model alloc] init];
            model.ID = (i+1)*10+(n+1)*10000;
            model.imageStr = [NSString stringWithFormat:@"%ld", i];
            [array addObject:model];
        }
        psdModel.dataSource = array;
        psdModel.PID = (n+1)*10000;
        [self.tempArray addObject:psdModel];
    }
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    ///开始处理pad任务, 记录开始时间
    self.startTime = [self getCurrentTimeStringToMilliSecond];
    [self run];
}

-(void)run
{
    self.isStop = NO;
    if (self.currentPsdModel) {
        NSInteger index = [self.tempArray indexOfObject:self.currentPsdModel];
        if (index == self.tempArray.count-1) {
            NSLog(@"上传完毕");
            self.currentPsdModel = nil;
            self.endTime = [self getCurrentTimeStringToMilliSecond];
            NSLog(@"startTime:%@ ----- endTime:%@",self.startTime, self.endTime);
            return;
        }
        if (self.tempArray.count > index+1) {
            self.currentPsdModel = self.tempArray[index+1];
        }
    }else{
        self.currentPsdModel = self.tempArray.firstObject;
    }
    if (self.currentPsdModel == nil) {
        NSLog(@"上传结束");
        return;
    }
    NSLog(@"开始psd, %ld", self.currentPsdModel.PID);
    [self.currentPsdModel addObserver:self forKeyPath:@"doneCount" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
    self.currentPsdModel.startTime = [self getCurrentTimeStringToMilliSecond];
    [self startDOPsd];
}

-(void)stop{
    self.isStop = YES;
    if (self.currentPsdModel!= nil) {
        [self.currentPsdModel removeObserver:self forKeyPath:@"doneCount"];
    }
}

-(void)dealloc{
    if (self.currentPsdModel!= nil) {
        [self.currentPsdModel removeObserver:self forKeyPath:@"doneCount"];
    }
}

//监听当前的psd是否上传完毕
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if ([@"doneCount" isEqual:keyPath]) {
        if (self.currentPsdModel.doneCount.intValue == self.currentPsdModel.dataSource.count) {
            [self.currentPsdModel removeObserver:self forKeyPath:@"doneCount"];//上一个psd处理结束
            self.currentPsdModel.endTime = [self getCurrentTimeStringToMilliSecond];
            NSLog(@"结束psd, %ld", self.currentPsdModel.PID);
            [self run];
        }
    }
}

//开始遍历上传
-(void)startDOPsd
{
    PSDModel *psdModel = self.currentPsdModel;
    for (int i = 0; i < psdModel.dataSource.count; i++) {
        if (self.isStop) {
            return;
        }
        Model *model = psdModel.dataSource[i];
        [self task:model];
    }
}

- (NSString *)getCurrentTimeStringToMilliSecond
{
    // 获取当前时间戳 精确到毫秒
    long long currentTime = [[NSDate date] timeIntervalSince1970] * 1000;
    return [NSString stringWithFormat:@"%lld",currentTime];
}


//表示一个图片上传任务
-(void)task:(Model *)model
{
    dispatch_semaphore_wait(self.currentPsdModel.semaphore, DISPATCH_TIME_FOREVER);
    //一个图片分为: 签名 验证 上传  加入3个步骤  串行进行  回调为异步
    model.startTime = [self getCurrentTimeStringToMilliSecond];
    NSLog(@"%ld:开始一个图片上传任务 --> %@",model.ID, [NSThread currentThread]);
    
    [self sign:model];
    [self auth:model];

    __weak typeof(self)weakSelf = self;
    dispatch_group_notify(model.uploadGroup, dispatch_queue_create("end", 0), ^{
        //这里记录一个图片上传结束的时间
        //签名验证之后上传图片操作
        [self upload:model andBack:^(NSInteger result) {
            //根据result 失败还是成功  重新请求
            if(result == 1){
                ///记录结束时间
                model.endTime = [self getCurrentTimeStringToMilliSecond];
                
                NSLog(@"%ld:结束一个图片上传任务 --> %@",model.ID, [NSThread currentThread]);
                
                ///释放信号量
                dispatch_semaphore_signal(weakSelf.currentPsdModel.semaphore);
                
                ///记录psd中完成的个数 synchronized控制单写任务   同时还能通知 (KVO) 是否进行下一个psd的上传
                @synchronized (self) {
                    weakSelf.currentPsdModel.doneCount = [NSString stringWithFormat:@"%ld",weakSelf.currentPsdModel.doneCount.integerValue+1];
                }
            }else{//请求失败
                @synchronized (self) {
                    model.uploadErrorCount+=1;
                }
            }
        }];
    });
}

-(void)sign:(Model *)model{
    dispatch_group_enter(model.uploadGroup);
    dispatch_async(dispatch_queue_create("sign", 0), ^{
        sleep(2);
        NSLog(@"%ld:签名结束 --> %@",model.ID,[NSThread currentThread]);
        dispatch_group_leave(model.uploadGroup);
    });
}

-(void)auth:(Model *)model{
    dispatch_group_enter(model.uploadGroup);
    dispatch_async(dispatch_queue_create("auth", 0), ^{
        sleep(2);
        NSLog(@"%ld:验证结束 --> %@",model.ID, [NSThread currentThread]);
        dispatch_group_leave(model.uploadGroup);
    });
}

-(void)upload:(Model *)model andBack:(BackResult)backResult{
    dispatch_async(dispatch_queue_create("upload", 0), ^{
        sleep(2);
        NSLog(@"%ld:上传结束 --> %@",model.ID, [NSThread currentThread]);
        if (backResult != nil) {
//            backResult(0);//失败
            backResult(1);//成功
        }
    });
}

@end

猜你喜欢

转载自blog.csdn.net/Batac_Lee/article/details/113177074