IOS并发编程笔记

1.传统的并发编辑模型是线程,但线程模型可扩展性依赖程序员经验(要用多少个线程及如何调度它们),且编写正确的代码困难,因此mac和ios采用“异步设计方式”来解决并发问题,异步设计方式是指提供简单的方式让用户可异步执行代码,只需要提供异步执行的代码块,由系统自动帮助创建管理和启动线程,引入的异步技术有两个:
1)GCD:将执行任务的代码块创建好,添加到dispatch queue,GCD会帮你创建线程并调度任务,系统提供线程管理,比应用实现更高效;线程顺序严格FIFO;
2)Operation Queue:Objective-C对象,类似于dispatch queue,特点在于可动态调配任务的执行顺序,配置任务间的依赖关系,比如a任务可在b任务执行后再执行;同时其是oc的接口,gcd是c的函数接口;
2.dispatch queue分为serial dispatch queue(也称为private dispatch queue)和concurrent dispatch queue(也称为global dispatch queue),前者串行,后者并发;同时还有全局的串行queue——main dispatch queue,这是主线程所在的queue,它与应用的run loop交叉运行;
3.通过确保主线程自由响应用户事件,并发可以很好地提升用户的响应性。将工作分配 到多核还能提升应用处理的性能,但并发也带来一定额外开销,并使代码更复杂,因此设计阶段就要考虑用发,设计出任务及其对应所需要的数据结构;
4.Operation object是NSOperation类的实例,封装了需要执行的任务和对应的数据,NSOperation本身是基类,必须实现其子类,系统有两个可现成使用的子类:NSInvocationOperation和NSBlockOperation,前者由一个实例和其方法来进行封装,适用于有现成方法的情况下使用,类似于target:action;后者则无现有方法情况下,使用块来进行封装;operation objects都支持关键的特性:
1)允许设置任务间的依赖;
2)支持可选的completion block,在任务完成后调用;
3)支持应用KVO通知来监控operation执行状态;
4)支持operation优先级设置,影响相对的执行顺序;

5)支持取消,中止正在执行的任务;

6)NSOperation对象可重用;

5.operation有两种执行方法,一是添加到operation queue,另一种是手动调用其start方法,前者不需要处理并发情况,系统会自动创建线程,实现并发;后者默认是同步执行,即是在调用start方法的线程中执行,因此若想并发执行则需要自己手动创建线程,再调用start才能保证并发;
6.创建NSInvocationOperation:
NSInvocationOperation* theOp = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(myTaskMethod:) object:data] autorelease];
7.NSBlockOperation可封装一个或多个Block,一般先创建时添加一个,后续再根据需要添加多个,调用方法addExecutionBlock:,operation对象执行时,会默认提交所有block到默认优先级的并发dispatch queue,全部block执行完才算operation完,因此可用BlockOperation来跟踪一组执行中的block;有点类似于线程的join,如果需要使block串行执行,则需要手动将operation提交到对应的dispatch queue。
8. NSBlockOperation创建示例:NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{ NSLog(@"Beginning operation.\n");
}];
9.定义自定义非并发operation只需要执行主任务,并正确地响应取消事件,NSOperation处理了其它所有事情。对于并发operation, 你必须替换某些现有的基础设施代码。
10.每个operation对象至少需要实现以下方法:
1)initialization方法:初始化,将operation对象设置为已知状态;
2)自定义main方法:执行任务的内容;
3)判断取消事件是通过调用isCancelled方法来实现的,可以在任务循环里一直调用该方法,因为它的开销并不大;
11.手动start方式执行operation时,如果想使之并发执行,则有几个方法需要特殊处理:
1)实现start方法,在其中实现并发,创建线程并执行之;
2)main方法实现可选;
3)isExecuting和isFinished必须实现,用来向外部报告当前任务是否已经在执行或已完成,这两个方法必须保证可在其它多个线程中同时调用,状态变化时也需要发了对应的KVO通知;
4)isConcurrent必须实现,用来标记当前的operation是否并发的operation;
5)你如果想单独处理依赖,还可以实现isReady方法,强制返回NO,直至我们想要的条件成立再返回YES等等;
12.使用NSOperation的addDependency:方法在两个operation对象之间建立依赖关系;依赖关系不局限于同一个queue中的operation,但是不能创建循环依赖,否则所有影响到的operations都将无法执行;配置依赖关系必须在operation添加到queue之前,之后添加的依赖关系可能不起作用;
13.setQueuePriority可以设置operation在queue里的优先级,不同的queue中的operation互不影响,依赖关系需要在优先级之前先满足;通过setThreadPriority方法可设置底层线程的优先级,该优先级只有main方法范围内有效,之前与之后的代码仍是默认优先级;
14.内存管理方面:operation对象需要用autoreleasepool包起来;避免Per-Thread storage来存储数据,即不要关联任何数据到非自己创建的线程上,系统管理的线程其周期不明确;自己需要处理operation start之后的所有异常与错误;
15.将operation加到queue中:
NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
[aQueue addOperation:anOp]; // Add a single operation
[aQueue addOperations:anArrayOfOps waitUntilFinished:NO]; // Add multiple operations
[aQueue addOperationWithBlock:^{ /* Do something. */
}];
16.setMaxConcurrentOperationCount: 方法可以配置operation queue的最大并发操作数量。设为1就表示 queue每次只能执行一个操作。不过operation 执行的顺序仍然依赖于其它因素,像操作是否准备好和优先级等。因此串行化的operation queue并不等同于 GCD中的串行dispatch queue。
17.只有你确定不再需要Operations对象时,才应该取消它。发出取消命令会将Operations对象设置为"Canceled"状态,会阻止它被执行。由于取消也被认为是完成,依赖于它的其它Operations对象会收到适当的KVO通知,并清除依赖状态,然后得到执行。
18.如果想临时挂起operations的执行,可以挂起对应的queue,调用方法setSuspended,挂起queue时不会导致正在执行的operation中途暂停,只会简单阻止调度新的operation执行。
19.dispatch queue的几个关键点:
1)dispatch queue之间中并发执行的,要串行只能在同一个queue中实现;
2)100个不同的queues启动100个任务,并不代表100个任务都在同时执行,具体取决于系统的核数;
3)系统在选择执行哪个任务时,会考虑queue的优先级;
4)queue中的任务是任何时候都准备好运行的,不像operation一样有isReady接口;
5)private dispatch queue是引用计数管理的,必须要retain与release语句,arc不需要;全局的不需要retain和release;
20.系统默认提供三个dispatch queue,它们的区别是优先级不同,通过如下方法可获取:
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
21.创建private queue语句为:dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
22.绝对不要在任务中调用dispatch_sync或dispatch_sync_f函数,并同步dispatch新任务到当前正在执行的queue。对于串行 queue这一点特别重要,因 为这样做肯定会导致死锁;
23.在dispatch queue中实现办法是:Completion Block是你dispatch到queue的另一段代码,在原始任务完成时自动执行。调用代码在启动任务时通过参数提供Completion Block。任务代码只需要在完成工作时提交指定的Block或函数到指定的queue就实现了回调。
24.如果每次迭代执行的任务与其它迭代独立无关,只是循环变量i++的值不同,而且循环迭代执行顺序也无关紧要的话,你可以调用dispatch_apply或dispatch_apply_f函数来替换循环。它会自动把i的值迭代,如:
dispatch_apply(count, queue, ^(size_t i) { printf("%u\n",i);

});

25.使用dispatch_semaphore_create函数创建semaphore,指定正数值表示资源的可用数量;在每个任务中,调用dispatch_semaphore_wait来等待Semaphore;当上面调用返回时,获得资源并开始工作;使用完资源后,调用dispatch_semaphore_signal函数释放和signal这个semaphore。
26.dispatch group用来阻塞一个线程,直到一个或多个任务处理完成:基本流程是创建一个group,dispatch任务到queue时使用方法dispatch_group_async,将group和queue关联起来,到后面需要等待任务处理完成的地方再调用dispatch_group_wait。
27.dispatch source用来在系统事件(定时器、系统信号量到达、文件与操作通知、进程相关事件等)触发时,帮你把你所指定的代码(块或函数)提交到指定的dispatch queue中执行,需要你指定代码块或函数、queue和事件类型,该绑定不会自动取消,会一直等系统的事件,除非显式取消关联,同时为了防止事件积压,dispatch source实现了事件合并机制,新事件会替代或更新老事件;
28.gcd可替代自定义的Run loop而且更方便。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章