说起异步,其实也是用多线程实现的,所以先讲解下多线程的原理,多线程就是给各个线程分时间片,但各个时间片时间又很短,所以看起来像是并发执行。多线程的好处是可以避免阻塞造成的CPU计算时间浪费,可以显著提高CPU的利用率。
异步调用函数就是一个可以无需等待被调用函数的返回值就让操作继续进行的方法,其原理其实就是把这些复制的运算添加到一个新的线程里面去并利用回调函数通知操作完成,在objective-c还可以用block来替代回调函数。一般是需要处理一些复制的业务逻辑,需要较长时间去处理,这时候是不能让它阻塞主线程,导致界面未响应,所以需要异步调用这些复杂的操作。
下面会举例说明,例子代码都自定义类Async中实现,再通过main.m中用单元测试逐个测试。
1.performSelector
NSObject提供了以performSelector为前缀的一系列方法。它们可以让用户在指定线程中,或者立即,或者延迟执行某个方法调用。这个方法给了用户实现多线程编程最简单的方法。 我们这里只讨论异步调用的方法。
在后台线程中执行方法,也就是异步调用的方法:
例子是在控制台中执行,所以需要自定义一个类来演示,自定义类如下
Async.h
#import <Foundation/Foundation.h>
@interface Async : NSObject
{
BOOL gFinish;
}
- (void)TestAsyncPerform;
- (void)TestMyOperation;
- (void)TestNSInvocationOperation;
- (void)TestNSBlockOperation;
- (void)TestNSOperationQueue;
- (void)TestGCD1;
- (void)TestGCD2;
- (void)TestGCD3;
- (void)TestGCD4;
@end
Async.m中实现如下方法:
- (void)TestAsyncPerform
{
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
//[self performSelectorInBackground:@selector(run:) withObject:@"performSelector"];
[self performSelectorOnMainThread:@selector(run:) withObject:@"performSelector" waitUntilDone:NO];
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
}
-(void)run:(NSString *)str
{
if ([NSThread isMainThread]) {
NSLog(@"%@:当前在主线程中工作",str);
}
else
{
NSLog(@"%@:当前在工作线程中工作",str);
}
sleep(1);
gFinish = YES;
}
mian.mm用单元测试调用:
TEST(Async, perform)
{
Async *async = [[Async alloc] init];
[async TestAsyncPerform];
}
int main(int argc, char * argv[])
{
testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
输出结果:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.perform
2015-10-20 15:33:50.779 test_asynchronous[1568:303] 当前在主线程中工作
2015-10-20 15:33:50.782 test_asynchronous[1568:2003] perform:当前在工作线程中工作
[ OK ] Async.perform (4004 ms)
[----------] 1 test from Async (4004 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (4004 ms total)
[ PASSED ] 1 test.
该方法的操作和主线程不同,说明是异步的。
NSOperationQueuePriority VeryHigh
NSOperationQueuePriority High
NSOperationQueuePriority Normal
NSOperationQueuePriority Low
NSOperationQueuePriority VeryLow
(6)NSOperation使用状态机模型来表示状态。通常,你可以使用KVO(Key-Value Observing)观察任务的执行状态。这是其他多线程工具所不具备的功能。NSOperation提供以下状态:
isReady
isExecuting
isFinished
(7)NSOperation 对象之间的依赖性可以用如下代码表示:
[refreshUIOperation addDependency:requestDataOperation];
[operationQueue addOperation:requestDataOperation];
[operationQueue addOperation:refreshUIOperation];
除非 requestDataOperation的状态isFinished返回YES,不然refreshUIOperation这个操作不会开始。
(8)NSOperation 还有一个非常有用功能,就是“取消”。这是其他多线程工具(包括后面要讲到的GCD)都没有的。调用NSOperation的cancel:方法即可取消该任务。当你知道这个任务没有必要再执行下去时,尽早安全地取消它将有利于节省系统资源。
(1).自定义的Operation类,把操作写在main函数里面:
MyOperation.h
#import <Foundation/Foundation.h>
@interface MyOperation : NSOperation
@end
MyOperation.m
#import "MyOperation.h"
@implementation MyOperation
-(void)main
{
if ([NSThread isMainThread]) {
NSLog(@"MyOperation:当前在主线程中工作");
}
else
{
NSLog(@"MyOperation:当前在工作线程中工作");
}
sleep(1);
}
@end
添加一个观察方法去观察任务的状态:
-(void)ObserveState1:(NSOperation *)operation
{
while (true)
{
//sleep(1);
if ([operation isExecuting]) {
NSLog(@"MyOperation 任务执行中");
}
else if ([operation isFinished])
{
NSLog(@"MyOperation 任务完成");
gFinish = YES;
break;
}
else if ([operation isReady])
{
NSLog(@"MyOperation 任务准备中");
}
}
}
- (void)TestMyOperation
{
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
MyOperation *operation1 = [[MyOperation alloc] init];
//观察任务状态
[self performSelectorInBackground:@selector(ObserveState1:) withObject:operation1];
[operation1 start];
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
return;
}
TEST(Async, MyOperation)
{
Async *async = [[Async alloc] init];
[async TestMyOperation];
}
int main(int argc, char * argv[])
{
testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
输出结果:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.MyOperation
2015-10-21 11:34:15.893 test_asynchronous[837:303] 当前在主线程中工作
2015-10-21 11:34:15.896 test_asynchronous[837:2103] MyOperation任务准备中
2015-10-21 11:34:15.897 test_asynchronous[837:2103] MyOperation任务执行中
2015-10-21 11:34:15.898 test_asynchronous[837:2103] MyOperation任务执行中
.....
2015-10-21 11:34:16.897 test_asynchronous[837:303] MyOperation:当前在主线程中工作
2015-10-21 11:34:16.898 test_asynchronous[837:2103] MyOperation任务执行中
2015-10-21 11:34:16.899 test_asynchronous[837:2103] MyOperation任务完成
[ OK ] Async.MyOperation (5005 ms)
[----------] 1 test from Async (5005 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (5006 ms total)
[ PASSED ] 1 test.
用NSOperationQueue的好处是可以一次添加多个任务,并且NSOperation的一大特点是可以查看任务的状态并且可以中途停止。
-(void)ObserveState2:(NSOperation *)operation
{
while (true)
{
//sleep(1);
if ([operation isExecuting]) {
NSLog(@"NSInvocationOperation 任务执行中");
}
else if ([operation isFinished])
{
NSLog(@"NSInvocationOperation 任务完成");
gFinish = YES;
break;
}
else if ([operation isReady])
{
NSLog(@"NSInvocationOperation 认准准备中");
}
}
}
- (void)TestNSInvocationOperation
{
gFinish = NO;
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self
selector:@selector(run:)
object:@"NSInvocationOperation"];
[self performSelectorInBackground:@selector(ObserveState2:) withObject:operation2];
[operation2 start];
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
}
TEST(Async, NSInvocationOperation)
{
Async *async = [[Async alloc] init];
[async TestNSInvocationOperation];
}
int main(int argc, char * argv[])
{
testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
输出结果:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.NSInvocationOperation
2015-10-21 11:39:29.341 test_asynchronous[854:303] 当前在主线程中工作
2015-10-21 11:39:29.344 test_asynchronous[854:2003] NSInvocationOperation任务执行中
2015-10-21 11:39:29.344 test_asynchronous[854:303] NSInvocationOperation:当前在主线程中工作
2015-10-21 11:39:29.345 test_asynchronous[854:2003] NSInvocationOperation任务执行中
2015-10-21 11:39:29.345 test_asynchronous[854:2003] NSInvocationOperation任务执行中
.....
2015-10-21 11:39:30.360 test_asynchronous[854:2003] NSInvocationOperation任务完成
[ OK ] Async.NSInvocationOperation (5006 ms)
[----------] 1 test from Async (5006 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (5006 ms total)
[ PASSED ] 1 test.
(3)NSBlockOperation
-(void)ObserveState3:(NSOperation *)operation
{
while (true)
{
//sleep(1);
if ([operation isExecuting]) {
NSLog(@"NSBlockOperation 任务执行中");
}
else if ([operation isFinished])
{
NSLog(@"NSBlockOperation 任务完成");
gFinish = YES;
break;
}
else if ([operation isReady])
{
NSLog(@"NSBlockOperation 任务准备中");
}
}
}
- (void)TestNSBlockOperation
{
gFinish = NO;
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
if ([NSThread isMainThread]) {
NSLog(@"NSBlockOperation:当前在主线程中工作");
}
else
{
NSLog(@"NSBlockOperation:当前在工作线程中工作");
}
}];
[self performSelectorInBackground:@selector(ObserveState3:) withObject:operation3];
[operation3 start];
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
}
在main.mm
TEST(Async, NSBlockOperation)
{
Async *async = [[Async alloc] init];
[async TestNSBlockOperation];
}
int main(int argc, char * argv[])
{
testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
输出结果:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.NSBlockOperation
2015-10-21 13:36:40.518 test_asynchronous[1031:303] 当前在主线程中工作
2015-10-21 13:36:40.521 test_asynchronous[1031:2003] NSBlockOperation任务执行中
2015-10-21 13:36:40.521 test_asynchronous[1031:2003] NSBlockOperation任务执行中
2015-10-21 13:36:40.522 test_asynchronous[1031:2003] NSBlockOperation任务执行中
.....2015-10-21 13:36:41.521 test_asynchronous[1031:303] NSBlockOperation:当前在主线程中工作
2015-10-21 13:36:41.521 test_asynchronous[1031:2003] NSBlockOperation任务执行中
2015-10-21 13:36:41.521 test_asynchronous[1031:2003] NSBlockOperation任务完成
[ OK ] Async.NSBlockOperation (5004 ms)
[----------] 1 test from Async (5004 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (5004 ms total)
[ PASSED ] 1 test.
(4)NSOperationQueue
在Async.m中的实现
- (void)TestNSOperationQueue
{
gFinish = NO;
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//2.operation
//(1)MyOperation
MyOperation *operation1 = [[MyOperation alloc] init];
[self performSelectorInBackground:@selector(ObserveState1:) withObject:operation1];
[operation1 setQueuePriority:NSOperationQueuePriorityVeryLow];
//(2)NSInvocationOperation
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self
selector:@selector(run:)
object:@"NSInvocationOperation"];
[self performSelectorInBackground:@selector(ObserveState2:) withObject:operation2];
[operation2 setQueuePriority:NSOperationQueuePriorityNormal];
//(3)NSBlockOperation
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
if ([NSThread isMainThread]) {
NSLog(@"NSBlockOperation:当前在主线程中工作");
}
else
{
NSLog(@"NSBlockOperation:当前在工作线程中工作");
}
sleep(1);
}];
[self performSelectorInBackground:@selector(ObserveState3:) withObject:operation3];
[operation3 setQueuePriority:NSOperationQueuePriorityVeryHigh];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
}
在main.mm中调用
TEST(Async, NSOperationQueue)
{
Async *async = [[Async alloc] init];
[async TestNSOperationQueue];
}
int main(int argc, char * argv[])
{
testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
输出结果:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.NSOperationQueue
2015-10-21 13:39:57.854 test_asynchronous[1047:303] 当前在主线程中工作
2015-10-21 13:39:57.856 test_asynchronous[1047:2003] MyOperation任务准备中
2015-10-21 13:39:57.857 test_asynchronous[1047:2a03] NSInvocationOperation认准准备中
2015-10-21 13:39:57.857 test_asynchronous[1047:3003] NSBlockOperation任务准备中
2015-10-21 13:39:57.857 test_asynchronous[1047:2003] MyOperation任务准备中
2015-10-21 13:39:57.857 test_asynchronous[1047:2a03] NSInvocationOperation认准准备中
2015-10-21 13:39:57.857 test_asynchronous[1047:3107] NSBlockOperation:当前在工作线程中工作
2015-10-21 13:39:57.858 test_asynchronous[1047:3003] NSBlockOperation任务执行中
2015-10-21 13:39:57.859 test_asynchronous[1047:2a03] NSInvocationOperation任务执行中
2015-10-21 13:39:57.859 test_asynchronous[1047:2003] MyOperation任务执行中
.....
2015-10-21 13:39:58.859 test_asynchronous[1047:2003] MyOperation任务完成
2015-10-21 13:39:58.860 test_asynchronous[1047:2a03] NSInvocationOperation任务执行中
2015-10-21 13:39:58.861 test_asynchronous[1047:2a03] NSInvocationOperation任务完成
2015-10-21 13:39:58.861 test_asynchronous[1047:3003] NSBlockOperation任务完成
[ OK ] Async.NSOperationQueue (4004 ms)
[----------] 1 test from Async (4004 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (4004 ms total)
[ PASSED ] 1 test.
为了方便查看,在观察方法中等待一秒,如下:
-(void)ObserveState1:(NSOperation *)operation
{
while (true)
{
sleep(1);
if ([operation isExecuting]) {
NSLog(@"MyOperation 任务执行中");
}
else if ([operation isFinished])
{
NSLog(@"MyOperation 任务完成");
gFinish = YES;
break;
}
else if ([operation isReady])
{
NSLog(@"MyOperation 任务准备中");
}
}
}
另外两个也一样。
检验依赖关系:
- (void)TestNSOperationQueue
{
gFinish = NO;
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//2.operation
//(1)MyOperation
MyOperation *operation1 = [[MyOperation alloc] init];
[self performSelectorInBackground:@selector(ObserveState1:) withObject:operation1];
[operation1 setQueuePriority:NSOperationQueuePriorityVeryLow];
//(2)NSInvocationOperation
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self
selector:@selector(run:)
object:@"NSInvocationOperation"];
[self performSelectorInBackground:@selector(ObserveState2:) withObject:operation2];
[operation2 setQueuePriority:NSOperationQueuePriorityNormal];
//(3)NSBlockOperation
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
if ([NSThread isMainThread]) {
NSLog(@"NSBlockOperation:当前在主线程中工作");
}
else
{
NSLog(@"NSBlockOperation:当前在工作线程中工作");
}
sleep(1);
}];
[self performSelectorInBackground:@selector(ObserveState3:) withObject:operation3];
[operation3 setQueuePriority:NSOperationQueuePriorityVeryHigh];
[operation3 addDependency:operation1];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
}
输出结果:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.NSOperationQueue
2015-10-21 14:10:34.714 test_asynchronous[1102:303] 当前在主线程中工作
2015-10-21 14:10:34.717 test_asynchronous[1102:1403] NSInvocationOperation:当前在工作线程中工作
2015-10-21 14:10:35.718 test_asynchronous[1102:2003] MyOperation任务执行中
2015-10-21 14:10:35.718 test_asynchronous[1102:1a03] MyOperation:当前在工作线程中工作
2015-10-21 14:10:35.718 test_asynchronous[1102:2a03] NSInvocationOperation任务执行中
2015-10-21 14:10:35.720 test_asynchronous[1102:1a03] NSBlockOperation:当前在工作线程中工作
2015-10-21 14:10:36.718 test_asynchronous[1102:3003] NSBlockOperation任务执行中
2015-10-21 14:10:36.721 test_asynchronous[1102:2003] MyOperation任务完成
2015-10-21 14:10:36.721 test_asynchronous[1102:2a03] NSInvocationOperation任务完成
2015-10-21 14:10:37.720 test_asynchronous[1102:3003] NSBlockOperation任务完成
[ OK ] Async.NSOperationQueue (4004 ms)
[----------] 1 test from Async (4004 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (4004 ms total)
[ PASSED ] 1 test.
第三个依赖第一个,尽管第三个优先级最高,但是还是会等待第一个完成后再执行。
3.GCD
GCD(Grand Central Dispatch)是Apple公司为了提高OS X和iOS系统在多核处理器上运行并行代码的能力而开发的一系列相关技术,它提供了对线程的高级抽象。GCD是一整套技术,包含了语言级别的新功能,运行时库,系统级别的优化,这些一起为并发代码的执行提供了系统级别的广泛优化。所以,GCD也是Apple推荐的多线程编程工具。
GCD 提供了一套纯 C API。但是,它提供的API简单易用并且有功能强大的任务管理和多线程编程能力。GCD需要和blocks(Objective-C的闭包)配合使用。block是GCD执行单元。GCD的任务需要被拆解到block中。block被排入GCD的分发队列,GCD会为你排期运行。GCD创建,
所有的dispatch objective都是objective-c对象,这意味着当ARC开启了的时候是不需要主动调用dispatch_retain或dispatch_release 来释放资源,若不启用ARC就要主动调用释放。若你想在ARC开启了的情况下调用dispatch_retain或dispatch_release 来释放资源,可以通过添加-DOS_OBJECT_USE_OBJC=0到你的编译器标志禁用的Objective-C为基础的派遣对象。
在 GCD中存在三种队列:
1串行分发队列(Serial dispatch queue)串行分发队列又被称为私有分发队列,按顺序执行队列中的任务,且同一时间只执行一个任务。
串行分发队列常用于实现同步锁。下面代码创建了一个串行分发队列:
dispatch_queue_t serialQueue = dispatch_queue_create("com.example.MyQueue", NULL);
2并发分发队列(Concurrent dispatch queue)串行分发队列又被称为全局分发队列,也按顺序执行队列中的任务,但是顺序开始的多个任务会
并发同时执行。并发分发队列常用于管理并发任务。下面代码创建了一个并发分发队列:
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3主分发队列(Main dispatch queue)主分发队列是一个全局唯一的特殊的串行分发队列。队列中的任务会被在应用的主线程中执行。
主分发队列可以用于执行 UI 相关的操作。取得主分发队列的方法:dispatch_queue_t mainQueue = dispatch_get_main_queue();
GCD任务执行方式
GCD 中有两种任务执行方式:
异步执行, dispatch_async,意味将任务放入队列之后,主线程不会等待block的返回结果,而是立即继续执行下去。
同步执行, dispatch_sync,意味将任务放入队列之后,主线程被阻塞,需要等待block的执行结果返回,才能继续执行下去。
整个队列的操作是异步还是阻塞取决于调用dispatch_async还是dispatch_sync,而队列中各任务的执行是一个个执行还是并发执行就取决于是用串行队列还是并发队列了,但不管是串行队列还是并发队列,只要是dispatch_sync调用的,队列里面的任务都会一个个执行。
(1)串行分发队列异步调用
在Async.m的实现
- (void)TestGCD1
{
gFinish = NO;
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
dispatch_queue_t serialQueue = dispatch_queue_create("myQueue", NULL);
for (int i = 0; i < 5; i ++) {
dispatch_async(serialQueue, ^{
if ([NSThread isMainThread]) {
NSLog(@"task%d:当前在主线程中工作",i);
}
else
{
NSLog(@"task%d:当前在工作线程中工作",i);
}
sleep(1);
if (i == 4) {
gFinish = YES;
}
});
}
NSLog(@"串行分发队列异步执行");
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
}
TEST(Async, GCD1)
{
Async *async = [[Async alloc] init];
[async TestGCD1];
}
int main(int argc, char * argv[])
{
testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.GCD1
2015-10-20 16:03:24.004 test_asynchronous[1722:303] 当前在主线程中工作
2015-10-20 16:03:24.006 test_asynchronous[1722:1603] task0:当前在工作线程中工作
2015-10-20 16:03:24.006 test_asynchronous[1722:303] 串行分发队列异步执行
2015-10-20 16:03:25.008 test_asynchronous[1722:1603] task1:当前在工作线程中工作
2015-10-20 16:03:26.010 test_asynchronous[1722:1603] task2:当前在工作线程中工作
2015-10-20 16:03:27.012 test_asynchronous[1722:1603] task3:当前在工作线程中工作
2015-10-20 16:03:28.014 test_asynchronous[1722:1603] task4:当前在工作线程中工作
[ OK ] Async.GCD1 (8005 ms)
[----------] 1 test from Async (8005 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (8005 ms total)
[ PASSED ] 1 test.
该队列是异步的,但每个任务都在同一个线程中按FIFO顺序执行。
(2)串行分发队列同步调用
在Async.m的实现
- (void)TestGCD2
{
gFinish = NO;
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
dispatch_queue_t serialQueue = dispatch_queue_create("myQueue", NULL);
for (int i = 0; i < 5; i ++) {
dispatch_sync(serialQueue, ^{
if ([NSThread isMainThread]) {
NSLog(@"task%d:当前在主线程中工作",i);
}
else
{
NSLog(@"task%d:当前在工作线程中工作",i);
}
sleep(1);
if (i == 4) {
gFinish = YES;
}
});
}
NSLog(@"串行分发队列同步执行");
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
}
在main.mm的实现
TEST(Async, GCD2)
{
Async *async = [[Async alloc] init];
[async TestGCD2];
}
int main(int argc, char * argv[])
{
testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.GCD2
2015-10-20 15:56:48.917 test_asynchronous[1679:303] 当前在主线程中工作
2015-10-20 15:56:48.919 test_asynchronous[1679:303] task0:当前在主线程中工作
2015-10-20 15:56:49.920 test_asynchronous[1679:303] task1:当前在主线程中工作
2015-10-20 15:56:50.923 test_asynchronous[1679:303] task2:当前在主线程中工作
2015-10-20 15:56:51.925 test_asynchronous[1679:303] task3:当前在主线程中工作
2015-10-20 15:56:52.926 test_asynchronous[1679:303] task4:当前在主线程中工作
2015-10-20 15:56:53.929 test_asynchronous[1679:303] 串行分发队列同步执行
[ OK ] Async.GCD2 (9014 ms)
[----------] 1 test from Async (9014 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (9014 ms total)
[ PASSED ] 1 test.
- (void)TestGCD3
{
gFinish = NO;
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 5; i ++) {
dispatch_async(concurrentQueue,
^{
if ([NSThread isMainThread]) {
NSLog(@"task%d:当前在主线程中工作",i);
}
else
{
NSLog(@"task%d:当前在工作线程中工作",i);
}
sleep(1);
if (i == 4) {
gFinish = YES;
}
});
}
NSLog(@"并行分发队列异步执行");
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
}
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.GCD3
2015-10-20 16:00:26.541 test_asynchronous[1696:303] 当前在主线程中工作
2015-10-20 16:00:26.543 test_asynchronous[1696:303] 并行分发队列异步执行
2015-10-20 16:00:26.544 test_asynchronous[1696:1603] task0:当前在工作线程中工作
2015-10-20 16:00:26.544 test_asynchronous[1696:2003] task1:当前在工作线程中工作
2015-10-20 16:00:26.544 test_asynchronous[1696:2203] task3:当前在工作线程中工作
2015-10-20 16:00:26.544 test_asynchronous[1696:2103] task2:当前在工作线程中工作
2015-10-20 16:00:26.544 test_asynchronous[1696:2303] task4:当前在工作线程中工作
[ OK ] Async.GCD3 (4004 ms)
[----------] 1 test from Async (4005 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (4005 ms total)
[ PASSED ] 1 test.
- (void)TestGCD4
{
gFinish = NO;
if ([NSThread isMainThread]) {
NSLog(@"当前在主线程中工作");
}
else
{
NSLog(@"当前在工作线程中工作");
}
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 5; i ++) {
dispatch_sync(concurrentQueue,
^{
if ([NSThread isMainThread]) {
NSLog(@"task%d:当前在主线程中工作",i);
}
else
{
NSLog(@"task%d:当前在工作线程中工作",i);
}
sleep(1);
if (i == 4) {
gFinish = YES;
}
});
}
NSLog(@"并行分发队列同步执行");
while (true)
{
sleep(4);
if (gFinish)
{
return;
}
}
}
TEST(Async, GCD4)
{
Async *async = [[Async alloc] init];
[async TestGCD4];
}
int main(int argc, char * argv[])
{
testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
输出结果:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.GCD4
2015-10-20 16:01:49.930 test_asynchronous[1709:303] 当前在主线程中工作
2015-10-20 16:01:49.933 test_asynchronous[1709:303] task0:当前在主线程中工作
2015-10-20 16:01:50.935 test_asynchronous[1709:303] task1:当前在主线程中工作
2015-10-20 16:01:51.937 test_asynchronous[1709:303] task2:当前在主线程中工作
2015-10-20 16:01:52.939 test_asynchronous[1709:303] task3:当前在主线程中工作
2015-10-20 16:01:53.941 test_asynchronous[1709:303] task4:当前在主线程中工作
2015-10-20 16:01:54.943 test_asynchronous[1709:303] 并行分发队列同步执行
[ OK ] Async.GCD4 (9015 ms)
[----------] 1 test from Async (9015 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (9015 ms total)
[ PASSED ] 1 test.
尽管是并发队列,但只要是用同步调用里面的任务都是按FIFO顺序执行。
void Test()
{
if ([NSThread isMainThread]) {
NSLog(@"task%d:当前在主线程中工作");
}
else
{
NSLog(@"task%d:当前在工作线程中工作");
}
sleep(1);
}
- (void)TestGCD5
{
gFinish = NO;
int a = 1;
if ([NSThread isMainThread]) {
NSLog(@"task%d:当前在主线程中工作");
}
else
{
NSLog(@"task%d:当前在工作线程中工作");
}
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async_f(concurrentQueue, NULL, &Test);
sleep(2);
}
TEST(Async, GCD5)
{
Async *async = [[Async alloc] init];
[async TestGCD5];
}
int main(int argc, char * argv[])
{
testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Async
[ RUN ] Async.GCD5
2015-10-21 15:43:35.240 test_asynchronous[1357:303] task-1880889215:当前在主线程中工作
2015-10-21 15:43:35.242 test_asynchronous[1357:1403] task-1880889215:当前在工作线程中工作
[ OK ] Async.GCD5 (2002 ms)
[----------] 1 test from Async (2002 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (2003 ms total)
[ PASSED ] 1 test.
使用perform的理由:
- 当你只想执行一个简单的异步操作而不需要控制任务状态。
- 当只有较少异步操作的时候。
使用 NSOperation 的一些理由:
- 当你需要取消线程任务时,GCD无法提供取消任务的操作。而NSOperation提供了取消任务的操作;;
- 当你需要更细的粒度地观察任务改变了状态时,由于NSOperation是一个对象,比较GCD使用的block而言,通过对NSOperation对象进行键值观察(KVO)能很容易观察到任务的状态改变;
- 当你需要重用线程任务时,NSOperation作为一个普通的Objective-C对象,可以存储任何信息。对象就是为重用而设计的,这时,NSOperation比GCD使用的block要更方便
- GCD 虽然在很多地方值得提倡,但并不是任务管理和多线程地唯一解决方案,并不是说所有的地方都应该使用 GCD。GCD是一个纯C API,NSOperation是Objective-C类,在一些地方对象编程是有优势的。NSOperation也提供了一些GCD无法实现,或者GCD所没有的功能。
- Apple公司宣称其在GCD技术中为更好地利用多核硬件系统做了很多的优化。所以,在性能方面GCD是不用担心的。而且GCD也提供了相当丰富的API,几乎可以完成绝大部分线程相关的编程任务。所以,在多线程相关主题的编程中,GCD应该是首选。
参考了《os x 10.7官方文档》,还有一篇博客:http://www.infoq.com/cn/articles/os-x-ios-multithread-technology