iOS编程中throttle那些事
不知道大家对throttle这个单词是否看着眼熟,还是说对这个计算机基础概念有很清晰的了解了。今天就来聊聊和throttle相关的一些技术场景。
定义
我经常有一种感觉,对于英语这门语言的语感,会影响我们对于一些关键技术概念的理解。有时候在学习新技术知识的时候,我会先花一些时间去了解术语英文单词的各种语义,在形成强烈清晰的语感之后,再去深入具体的技术语境。throttle也算是个生僻的单词,至少在口语中毕竟少用到,先来看看词义:
a device controlling the flow of fuel or power to an engine.
中文翻译是节流器,一种控制流量的设备。对应到我们计算机世界,可以理解成,一种控制数据或者事件流量大小的机制。这么说可能还是有些抽象,再来看看一些具体的技术场景加深理解。
场景一:GCD Background Queue
话说GCD几乎是iOS面试的必问题,也是个送分题:)。
我一般会机械式的先问:GCD有哪几种Queue?回答:串行Queue和并行Queue。
我继续问:Global Queue有哪几种优先级?回答:有几种吧,大概记得Default,Low,High吧。
我双眉一挑,进一步试探:不知道少侠有没有研究过DISPATCH_QUEUE_PRIORITY_BACKGROUND作何用?问完立即竖起耳朵,殷殷期盼萦绕于心的关键字。如果能听到「I/O Throttle 呀!」,我会瞬间觉得面试气氛被点亮了。
当然啦,答不出I/O Throttle并不能说明技术不扎实,但能答出来,至少表明对待技术是有好奇心的,加分!
官方文档如是说:
Items dispatched to the queue run at background priority; the queue is scheduled for execution after all high priority queues have been scheduled and the system runs items on a thread whose priority is set for background status. Such a thread has the lowest priority and any disk I/O is throttled to minimize the impact on the system.
那Disk I/O Throttle做什么用呢?按照上面这段描述,Disk I/O会impact system performance。
理解Disk I/O的影响需要补充一些大学课本上的知识。一次磁盘读写操作涉及到的硬件资源主要有两个,CPU和磁盘。任务本身由CPU触发和调度,读操作发生时,CPU告知Disk去获取某个地址的数据,此时由于Disk的读操作存在寻址延迟,CPU是处于I/O wait状态,一直维持到Disk返回数据为止。处于I/O wait状态的CPU,此时并不能把这部分等待的时间用来处理其他任务,也就是说这一段等待的CPU时间被“浪费”了。而CPU是公共的系统资源,这部分资源的损耗自然会对系统的整体表现产生负面影响。即使Global Queue使用的是子线程,也会造成CPU资源的消耗。
如果把任务的Priority调整为DISPATCH_QUEUE_PRIORITY_BACKGROUND,那么这些任务中的I/O操作就被被控制,虽然具体的控制策略并没有官方文档描述(一种可能的策略是并发的Disk I/O变为串行的),但我们能确认的是,部分I/O操作的启动时间很有可能被适当延迟,把更多的CPU资源腾出来处理其他任务(比如说一些系统资源的调度任务),这样可以让我们的系统更加稳定高效。简而言之,对于重度磁盘I/O依赖的后台任务,如果对实时性要求不高,放到DISPATCH_QUEUE_PRIORITY_BACKGROUND Queue中是个好习惯,对系统更友好。
实际上I/O Throttle还分为好几种,有Disk I/O Throttle,Memory I/O Throttle,和Network I/O Throttle。语义类似只不过场景不同,继续往下看。
场景二:ASIHttpRequest Network Throttle
早几年读ASIHttpRequest源码的时候,读到过一段有意思的代码:
1
2
3
4
5
6
|
- (void)handleNetworkEvent:(CFStreamEventType)type { //... [self performThrottling]; //... } |
在AFNetworking中也有类似的代码:
1
2
3
4
5
6
7
8
9
10
|
/** Throttles request bandwidth by limiting the packet size and adding a delay for each chunk read from the upload stream. When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted". Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize` and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth. Unfortunately, there is no definite way to distinguish between a 3G, EDGE, or LTE connection over `NSURLConnection`. As such, it is not recommended that you throttle bandwidth based solely on network reachability. Instead, you should consider checking for the "request body stream exhausted" in a failure block, and then retrying the request with throttled bandwidth. @param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 16kb. @param delay Duration of delay each time a packet is read. By default, no delay is set. */ - (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes delay:(NSTimeInterval)delay; |
原谅我贴了一大段注释,这段英文描述对于加深我们对于一些网络行为的理解很有帮助。
这些知名的第三方网络框架都有对Newtork Throttle的支持,你可能会好奇,我们为什么要对自己发出的网络请求做流量控制,难道不应该尽可能最大限度的利用带宽吗?
此处需要科普一点TCP协议相关的知识。我们通过HTTP请求发送数据的时候,实际上数据是以Packet的形式存在于一个Send Buffer中的,应用层平时感知不到这个Buffer的存在。TCP提供可靠的传输,在弱网环境下,一个Packet一次传输失败的概率会升高,即使一次失败,TCP并不会马上认为请求失败了,而是会继续重试一段时间,同时TCP还保证Packet的有序传输,意味着前面的Packet如果不被ack,后面的Packet就会继续等待,如果我们一次往Send Buffer中写入大量的数据,那么在弱网环境下,排在后面的Packet失败的概率会变高,也就意味着我们HTTP请求失败的几率会变大,类似这样:
大部分时候在应用层写代码的时候,估计不少同学都意识不到Newtork Throttle这种机制的存在,在弱网环境下(丢包率高,带宽低,延迟高)一些HTTP请求(比如上传图片或者日志文件)失败率会激增,有些朋友会觉得这个我们也没办法,毕竟网络辣么差。其实,作为有追求的工程师,我们可以多做一点点,而且弱网下请求的成功率其实是个很值得深入研究的方向。针对弱网场景,我们可以启用Newtork Throttle机制,减小我们一次往Send Buffer中写入的数据量,或者延迟某些请求的发送时间,这样所有的请求在弱网环境下,都能「耐心一点,多等一会」,请求成功率自然也就适当提高啦。
那么,再看AFNetworking中的这个函数,是不是更能理解了呢?
1
2
|
- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes delay:(NSTimeInterval)delay; |
Network Throttle体现了一句至理名言「慢即是快」。
场景三:Event Frequency Control
不知道大家在写UI的时候,有没有遇到过用户快速连续点击UIButton,产生多次Touch事件回调的场景。以前机器还没那么快的时候,我在用一些App的时候,时不时会遇到偶尔卡顿,多次点击一个Button,重复Push同一个Controller。有些工程师会在Button的点击事件里记录一个timestamp,然后判断每次点击的时间间隔,间隔过短就忽略,这也不失为一种解决办法。
再后来学习RxSwift的时候,看到:
1
2
3
4
5
6
|
button.rx_tap .throttle(0.5, MainScheduler.instance) .subscribeNext { _ in print( "Hello World" ) } .addDisposableTo(disposeBag) |
终于有了优雅的书写方式。发现没有,throttle又出现了,这里throttle控制的是什么呢?不是disk读写,也不是network buffer,而是事件,把事件本身抽象成了一种Data,控制这种数据的流量或者产生频率,就解决了上面我们所说重复点击按钮的问题,so easy。
总结
当然还会有更多的场景,throttle其实是个基础的计算机知识。理解throttle相关的技术概念,需要在不同场景下去抽象出一个flow被节流的画面。现在,如果让你来解释一些具体的技术场景下,throttle是怎么回事,是不是可以信手拈来了:)
iOS编程中throttle那些事的更多相关文章
- iOS编程中比较两个日期的大小
转自:http://www.myext.cn/other/a_30922.html 比较日期大小是任何编程语言都会经常遇到的问题,再iOS编程中,通常用NSDate对象来存储一个时间(包括日期和时间. ...
- iOS编程中遇到的问题
1.应用在iPhone6plus 系统iOS9.1安装时没遇到问题,在iPhone4s 系统iOS 7时bulid success 但是安装失败提示 There was an internal API ...
- IOS 编程中引用第三方的方类库的方法及常见问题
方法一:直接复制全部源文件到项目中 这样的方法就是把第三方类库的全部源文件拷贝到项目中,直接把全部.h和.m文件拖到XCode项目中就可以. 注意: 1. 假设第三方类库引用了一些系统自带类库,那么在 ...
- iOS编程中的音频知识(二):那么多种格式我应该用哪一个?
iPhone支持不少格式,比如AAC,HE-AAC,AMR,IMA4等等,你可以在以下网址看到比较全的格式和简要介绍: http://www.raywenderlich.com/69365/audio ...
- iOS编程中的音频知识(一):文件格式和数据格式,哦!天哪
要明白实际上每个音频文件都有2各部分组成:它的文件格式(或称之为音频容器),和它的数据格式(或称之为音频编码). 文件格式(audio containers)描述文件自身的格式.实际内部的音频数据可以 ...
- Cocoa编程中视图控制器与视图类详解
iPhone编程规则是:一个窗口,多个视图.UIView是iPhone屏幕上很多控件的基础类.每个iPhone用户界面都是由显示在UIWindow(这其实也是个特殊的UIView)内的众多UIView ...
- 简述 Ruby 与 DSL 在 iOS 开发中的运用
阅读本文不需要预先掌握 Ruby 与 DSL 相关的知识 何为 DSL DSL(Domain Specific Language) 翻译成中文就是:"领域特定语言".首先,从定义就 ...
- iOS 开发中遇到的问题
1. 关于纠结很久的KVO崩溃问题,其真正原因是,在删除roomItem的KVO之前,将这个对象已经赋值为nil,所以实际上并没有删除他的observer,因此而崩溃:长时间纠结的原因是受.cxx_d ...
- iOS编程之前
iOS编程之前 更新:帖子已经重新被更新过,以便能更好的兼容Xcode 5和iOS 7. 至今为止,已经超过6000位读者加入了这个iOS免费教程.首先,我要感谢这些加入我们社区的朋友.在 ...
随机推荐
- 【实用技巧】去除BootStrap所有圆角效果
满屏的圆角有没有审"美"疲劳啊?教你一键去除所有圆角效果: * { -webkit-border-radius: 0 !important; -moz-border-radius: ...
- 框架基础:ajax设计方案(三)---集成ajax上传技术
之前发布了ajax的通用解决方案,核心的ajax发布请求,以及集成了轮询.这次去外国网站逛逛,然后发现了ajax level2的上传文件,所以就有了把ajax的上传文件集成进去的想法,ajax方案的l ...
- 两行代码实现微信小程序联系人sidebar
话不多说,先给你们看看核心数据和结构: 一.数据: city的json array,letter的array (city的json array里的首字母是我手工放置进去的,你也可以通过for循环获得c ...
- VS超强调试技巧--忍不住想赞一下
你是否曾遇到一个项目启动都要半分钟? 启动后调试或突然看到有行代码写错了?然后开始了: 处理步骤:停止运行->修改代码->重新启动(10-30秒)->又写错了->又要修改-&g ...
- 【Zookeeper】源码分析之持久化--FileSnap
一.前言 前篇博文已经分析了FileTxnLog的源码,现在接着分析持久化中的FileSnap,其主要提供了快照相应的接口. 二.SnapShot源码分析 SnapShot是FileTxnLog的父类 ...
- 消息队列NetMQ 原理分析1-Context和ZObject
前言 介绍 NetMQ是ZeroMQ的C#移植版本,它是对标准socket接口的扩展.它提供了一种异步消息队列,多消息模式,消息过滤(订阅),对多种传输协议的无缝访问. 当前有2个版本正在维护,版本3 ...
- H5 拖放事件详解
拖放事件 H5的拖放事件提供了多个接口: 1.drag:当元素或者选中的文本被拖动时触发(每几百毫秒触发一次),应用在被拖拽元素上 2.dragend:当拖动操作结束时触发(通过释放鼠标按钮或者点击转 ...
- 【Java每日一题】20170116
20170113问题解析请点击今日问题下方的"[Java每日一题]20170116"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...
- 第一百三十五节,JavaScript,封装库--拖拽
JavaScript,封装库--拖拽 封装库新增1个拖拽方法 /** tuo_zhuai()方法,将一个弹窗元素实现拖拽功能 * 注意:一般需要在css文件将元素里的某一个区块光标设置成提示可以拖拽, ...
- 如何对Javascript代码进行二次压缩(混淆)
如何对Javascript代码进行二次压缩(混淆) 对Javascript代码进行压缩(混淆),可以有效减少传输和加载时间.但是,不是所有的变量(方法)都能被混淆的,一般来说,只有非属性的变量(方法) ...