生产问题:
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