当前位置: 移动技术网 > IT编程>移动开发>IOS > iOS编程学习中关于throttle的那些事

iOS编程学习中关于throttle的那些事

2019年07月24日  | 移动技术网IT编程  | 我要评论

睾丸图,凶冥十杀阵txt,韩国地方官登独岛

前言

不知道大家对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源码的时候,读到过一段有意思的代码:

- (void)handlenetworkevent:(cfstreameventtype)type
{
//...
 [self performthrottling];
//...
}

在afnetworking中也有类似的代码:

/**
 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中的这个函数,是不是更能理解了呢?

- (void)throttlebandwidthwithpacketsize:(nsuinteger)numberofbytes
         delay:(nstimeinterval)delay;

network throttle体现了一句至理名言「慢即是快」。

场景三:event frequency control

不知道大家在写ui的时候,有没有遇到过用户快速连续点击uibutton,产生多次touch事件回调的场景。以前机器还没那么快的时候,我在用一些app的时候,时不时会遇到偶尔卡顿,多次点击一个button,重复push同一个controller。有些工程师会在button的点击事件里记录一个timestamp,然后判断每次点击的时间间隔,间隔过短就忽略,这也不失为一种解决办法。

再后来学习rxswift的时候,看到:

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是怎么回事,是不是可以信手拈来了:)

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网