問(wèn)題:假如現(xiàn)在有1w個(gè)任務(wù)需要執(zhí)行,并且在全部執(zhí)行完成之后進(jìn)行一個(gè)提示避归,該怎么做荣月?
思路1:最直接的會(huì)想到dispatch_group,本身就是為一組任務(wù)設(shè)計(jì)的
#define OPERATION_COUNT 10000
#define OPERATION_SLEEP_TIME 0.01f
- (void)myOperation:(NSInteger)index {
[NSThread sleepForTimeInterval:OPERATION_SLEEP_TIME];
}
- (void)runMyOperationsWithGCD {
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < OPERATION_COUNT; i++) {
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
[self myOperation:i];
});
}
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"operations are finished");
});
}
思考1:這段代碼看的應(yīng)該非常清爽梳毙,但是會(huì)創(chuàng)建過(guò)多的線程哺窄,也給系統(tǒng)帶來(lái)了巨大的負(fù)擔(dān),是需要優(yōu)化的账锹。
問(wèn)題:假設(shè)在原始問(wèn)題的基礎(chǔ)上約束最多10個(gè)并發(fā)線程萌业,又有什么好的辦法?
思路2:采用iOS的NSOperationQueue奸柬,這個(gè)東西簡(jiǎn)直是按照這種需求設(shè)計(jì)的生年,非常好用
#define MAX_CONCURRENT_COUNT 10
#define OPERATION_COUNT 10000
#define OPERATION_SLEEP_TIME 0.1f
- (void)myOperation:(NSInteger)index {
NSLog(@"enter myOperation:%ld, thread:%@", (long)index, [NSThread currentThread]);
[NSThread sleepForTimeInterval:OPERATION_SLEEP_TIME];
}
- (void)runMyOPerationsWithNSOperation {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = MAX_CONCURRENT_COUNT;//設(shè)置最大并發(fā)數(shù)
for (int i = 0; i < OPERATION_COUNT; i++) {
[queue addOperationWithBlock:^{
[self myOperation:i];
}];
}
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[queue waitUntilAllOperationsAreFinished];//等待所有任務(wù)完成
NSLog(@"operations are finished");
});
}
思考2:個(gè)人覺(jué)得,這是最方便的方法廓奕,簡(jiǎn)單明了晶框,沒(méi)有過(guò)多的線程和冗余的代碼。
問(wèn)題:如果不使用NSOperation懂从,又有什么好的辦法嗎授段?
思路3:通過(guò)信號(hào)量控制并發(fā),并結(jié)合思路1的dispatch_group實(shí)現(xiàn)組任務(wù)完成后的通知
#define MAX_CONCURRENT_COUNT 10
#define OPERATION_COUNT 10000
#define OPERATION_SLEEP_TIME 0.1f
- (void)myOperation:(NSInteger)index {
NSLog(@"enter myOperation:%ld, thread:%@", (long)index, [NSThread currentThread]);
[NSThread sleepForTimeInterval:OPERATION_SLEEP_TIME];
}
- (void)runMyOperationsWithSemaphore {
//創(chuàng)建信號(hào)量番甩,控制最大并發(fā)數(shù)為10
dispatch_semaphore_t semaphore = dispatch_semaphore_create(MAX_CONCURRENT_COUNT);
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < OPERATION_COUNT; i++) {
//wait一次侵贵,semaphore減一,當(dāng)semaphore小于0時(shí)會(huì)一直wait
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
[self myOperation:i];
//任務(wù)完成后缘薛,觸發(fā)semaphore,以允許新的任務(wù)進(jìn)入
dispatch_semaphore_signal(semaphore);
});
}
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"operations are finished");
});
}
思考3:這種方式其實(shí)是在思路1的基礎(chǔ)上增加了信號(hào)量的并發(fā)限制漱抓,相當(dāng)于一種簡(jiǎn)單的改進(jìn)乞娄。
最后显歧,如果采用最傳統(tǒng)的NSThread,跟信號(hào)量配合范删,可以實(shí)現(xiàn)多任務(wù)并發(fā)到旦,但如何判斷所有任務(wù)都已執(zhí)行完畢,只想到了通過(guò)計(jì)數(shù)的方式添忘,并沒(méi)有想到更好的辦法。如果大家有更好的辦法,歡迎留言拴清,私信!
最最后娄周,附上demo煤辨,地址