多线程-线程安全(二)

之前写过一篇线程安全,简单介绍了保护数据安全的多种方式,以及其中一部分方式的原理。基于此基础,本文将介绍如何避免锁的性能浪费,以及如何实现无锁安全结构 避免锁的性能浪费 为了避免多个线程对数据的破坏,在使用锁保障线程安全的情况下,存在几个影响锁性能的重要因素: 上下文切换 临界区资源耗时 如果能够减少这些因素的损耗,就能有效的提高锁的性能 自旋锁 通常来说,当一个线程获取锁失败后,会被添加到一个等待队列的末尾,然后休眠。直到锁被释放后,依次唤醒访问临界资源。休眠时会发生线程的上下文切换,当前线程的寄存器信息会被保存到磁盘上,考虑到这些情况,能做的有两点: 换一个更快的磁盘 改用自旋锁 自旋锁采用死循环等待锁释放来替代线程的休眠和唤醒,避免了上下文切换...
Click to read more ...

开发笔记-mock in iOS

在面向对象编程中,有个非常有趣的概念叫做duck type,意思是如果有一个走路像鸭子、游泳像鸭子,叫声像鸭子的东西,那么它就可以被认为是鸭子。这意味着当我们需要一个鸭子对象时,可以通过instantiation或者interface两种机制来提供鸭子对象: @interface Duck : NSObject @property (nonatomic, assign) CGFloat weigh; - (void)walk; - (void)swim; - (void)quack; @end /// instantiation id duckObj = [[Duck alloc] init]; [TestCase testWithDuck: duckObj]; /// i...
Click to read more ...

WWDC-内存策略

尽管在进入后台之后,程序的工作受到大幅度的限制,但是我们总是不会希望应用突然被操作系统杀死,中断了重要的后台工作。后台应用被杀死,影响的不止是用户体验,比如正在播放的音乐戛然而止,正在导航的语音意外中断。由于操作系统杀死后台应用并不是任何一种异常、或者运行错误,应用失去响应意外的能力,极有可能破坏了单次运行中积累的重要数据。因此如何减少应用在后台运行被杀死,是一个值得思考的问题 后台应用如何被杀 抛开因为应用在后台停留太久被杀死之外,因为内存问题被杀死是最重要的原因。内存和其他硬件资源有很大的不同,区别在于: 当资源需求量多于资源所能供应的时,CPU表现为性能下降,而操作系统会为了回收内存杀死后台应用 我们可以把设备内存分成四块区域,包括system、background...
Click to read more ...

质量监控-监控启动崩溃

相较于正常的崩溃问题,启动crash造成的损失要远远大得多。正常来说,如果有足够强健的构建发布系统,大多数时候能在版本上线之前及时发现问题并且修复,但是仍然存在小概率的线上意外。启动crash一般同时具备损害严重以及难以捕获两大特点 启动过程 从应用图标被用户点击开始,直到应用可以开始响应发生了很多事情。正常来说,尽管我们希望crash监控工具启动的尽可能早,但接入方往往总是等到launch事件之后才能启动工具,而在这个时间之前发生的崩溃就是启动crash,下面列出了在应用直到launch时,存在的可能发生启动crash的阶段: 其中initialize的顺序可能在更早,但总是会在load和launch之间。从图中来说,如果我们想要监控启动crash,那么开始监控的时间点必须要...
Click to read more ...

多线程-被遗弃的线程

main函数作为程序运行的入口,正常情况下,函数会执行毫秒级别的操作,然后返回一个0表示程序正常终止。为了避免应用启动即终止,苹果设计了runloop机制来维持线程的生命,runloop在每一次的循环当中不断的去处理事件,或控制线程的休眠和唤醒。runloop还结合了libdispatch的任务派发机制,可以循环地处理async到队列中的任务 启动runloop 从runloop对外暴露的接口来看,启动方式一共存在三种: 无条件的启动。这种启动方式缺少停止runloop的手段,唯一的结束方式是kill掉线程 - (void)run; 设定超时时间。直接run会调用这个接口并且传入distantFuture,表示无限长的超时...
Click to read more ...

多线程-奇怪的GCD

多线程一直是我相当感兴趣的技术知识之一,个人尤其喜爱GCD这个轻量级的多线程解决方案,为了了解其实现,不厌其烦的翻阅libdispatch的源码。甚至因为太喜欢了,本来想要写这相应的源码解析系列文章,但害怕写的不好,于是除了开篇的类型介绍,也是草草了事,没了下文 恰好这几天好友出了几道有关GCD的题目,运行结果出于意料,仔细摸索后,发现苹果基于libdispatch做了一些有趣的修改工作,于是想将这两道题目分享出来。由于朋友提供的运行代码为Swift书写,在此我转换成等效的OC代码进行讲述。你如果了解了下面两个概念,会让后续的阅读更加容易: 同步与异步的概念 队列与线程的区别 被误解的概念 对于主线程和主队列,我们可能会有这么一个理解 主线程只会执行主队列的任...
Click to read more ...

分析实现-一对一设计

一对一one to one并不是某种业务上的具体需求,它仅仅是一种数据存储上的设计。one to one要求一个变量能且最多只能匹配一个变量,这听着很绕口,举个常见的结构例子就是key-value匹配。不同的编程语言提供了高层级的key-value存储结构,例如dictionary字典,被这些高层级的存储结构宠坏了的我们不知是否思考过这么一个问题: dictionary是怎么通过key来存储或者移除匹配的value的 应用程序的数据存储只存在连续存储和非连续存储这两种方式,并且非连续存储需要使用额外的内存来存储下一个数据的信息,因此非连续存储的内存开销是大于连续存储方式的。在dictionary的存储结构中,key和value可以完全不同且没有丝毫的关联性,这是否意味着字典...
Click to read more ...