objc.io issue2 并发编程 笔记1

原文链接 http://www.objc.io/issue-2/concurrency-apis-and-pitfalls.html

已经有中文版了: http://beyondvincent.com/blog/2013/07/16/104/ 

本来想自己一边翻译一遍看的,结果发现量有点大,还要调整配图,麻烦,就算了。就记下要点吧。

1. 并发包含单核的分时系统和真正的多核系统

2. OS X/iOS 包含一组API: GCD, NSOperationQueue, pthread/NSThread (NSRunLoop只是非常相关)

3. 可以使用Instruments的 CPU strategy view来观察CPU cores的利用情况

4. pthread兼容POSIX, NSThread是pthread的外包类, 写起来相对复杂,不推荐直接使用

5. 如果自己也使用pthread,所用的库的实现也用了pthread,那么和可能来个乘法效应,比如库探测出硬件有4核,于是生成4个线程;每个线程里面插入了自己的干活代码,这里也分配了4个线程..等等。冗余的线程是有内存和内核开销的。

6. 基于队列的API, 创建一个线程池来控制

6.1 GCD 

    直接考虑干活的block代码,而非关注线程本身。具体参考图。

    主线程  ---  主队列(串行队列)

    GCD线程池   ---  高中低以及背景优先级队列(以默认的中优先级队列为例,可以设置串行队列,也可以设置并行队列,后者再塞入串行队列)

    GCD很底层也很方便,但仍然要小心并发编程的各种警告和陷阱(见后文)

6.2 OperationQueue

    基于GCD之上,足够的弹性并且这种封装也避免了直接使用GCD容易产生的一些问题

    NSOperationQueue分两种,主线程上跑的main queue和别的线程上跑的自定义queue,工作任务被封装成NSOperation,可以重写NSOperation的main/start/finished

    NSOperationQueue也可以直接加入block。

    他们非常适合于调试: 重载description函数可以输入内部的各种细节状态

    其他有用的参数: maxConcurrentOperationCount  设置为1就是串行的队列,减少了任务之间的冲突。

    还可以在NSOperation之间 addDependency,控制启动顺序(以及更重要的,是不是必须等运行完毕了再启动!)

    小结: 相比直接使用GCD,代价轻微,非常实用,最优先的工具。

7 Run Loops 主线程有个默认的NSRunloop, 在操作时自动切换模式(优先处理输入)。给其他线程的Runloop做设置时要加一个source,否则直接退出。具体例子见本系列其他文章

8 并发编程的挑战(通用知识,可以自行找相关书籍看,比如深入理解计算机系统什么的)

    8.1 资源分享 资源可以是一个对象,通用内存,网络设备,文件等等。容易产生hazard, 比如A、B线程都给某个值为17的变量增加1,A增加之后尚未写回时,B读取后再增加,于是两次写入都是18,结果是18而不是期待的19,这就是race condition 竞态条件,由于现代cpu的乱序执行可能问题更加复杂。

    8.2 为了解决race condition,引入mutal exclusion,资源锁,锁定原子级(atomic)操作。锁本身还要支持乱序执行下的正确性,于是需要插入memory barrier保证cpu语意正确,所以本身开销就比较大。 锁的设计也有多种,有的是当没有锁上时,开销很小但一旦资源有锁,开销就很大;有些则是在基础情况下开销更高一些,但是在资源有锁的情况下的开销会相对好一些。如果几个线程在竞争使用某个资源,那么效率可能相当低。

    8.3 锁还带来了另一个严重问题: Dead lock 死锁。举例: 线程A 拿到资源1,等着拿到资源2后继续干活;线程B拿到资源2,等着拿到资源1继续干活。于是大家一直在等待。所以尽可能保持简单,避免死锁的出现。系列的其他文章会详述这些问题。

    8.4 饥饿/Starvation 一般情况下,对于一个资源可以有多个只读的锁和一个写的锁。有只读的锁的情况下可以继续加只读锁,结果导致写的锁一直在等待所有的只读锁退出后再去写。 readers-writers problem,解决办法是writers preference / read-copy-update 算法

    8.5 优先级反转 Priority Inversion  高中低三个线程。低优先级的线程锁住了高优先级的线程需要的资源,这时候高优先级的线程锁不上资源于是等着;低优先级的线程由于被中优先级的线程压制,没法获得运行时间释放资源。结论是别用不同的优先级啦,一不小心就优先级反转了。NASA在火星探路者上的遭遇表明,即使是很有经验的工程师也可能碰到这种问题。

9 总结 安全模式之一: 主线程丢出去数据,用操作队列在后台做实际的工作,做完后把结果回报给主线程的主队列main queue。 这样就避免了各种锁,减少错误的可能性。

 

2013.09.17

 

 

 

 

转载于:https://www.cnblogs.com/kurk/p/3325482.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值