对Android中的多图片异步加载的重新思考
现在想来,Android SDK把并行执行改为串行执行也并不无道理。
起因
不知道大家有没有发现,在2.0.4.1(37)版本之前的开源中国客户端首次加载图片的时候,会很慢,尤其是动弹列表中的图片。甚至网速慢的时候感觉图片根本加载不出来。
原因是在下载网络图片的时候使用了多线程并发执行的方式,什么意思呢,也就是开启了多个线程同时去下载多张图片。按照正常的思维来想,做图片加载操作使用多线程,这应该是很正常的,因为在我们的思维中,多线程资源利用率更高,程序响应更快。
举个例子:一个应用程序需要从本地文件系统中读取和处理文件的情景。比方说,从磁盘读取一个文件需要5秒,处理一个文件需要2秒。处理两个文件则需要
5秒读取文件A 2秒处理文件A 5秒读取文件B 2秒处理文件B --------------------- 总共需要14秒
从磁盘中读取文件的时候,大部分的CPU时间用于等待磁盘去读取数据。在这段时间里,CPU非常的空闲。它可以做一些别的事情。通过改变操作的顺序,就能够更好的使用CPU资源。看下面的顺序
5秒读取文件A 5秒读取文件B + 2秒处理文件A 2秒处理文件B --------------------- 总共需要12秒
CPU等待第一个文件被读取完。然后开始读取第二个文件。当第二文件在被读取的时候,CPU会去处理第一个文件。记住,在等待磁盘读取文件的时候,CPU大部分时间是空闲的。总的说来,CPU能够在等待IO的时候做一些其他的事情。这个不一定就是磁盘IO。它也可以是网络的IO,或者用户输入。通常情况下,网络和磁盘的IO比CPU和内存的IO慢的多。
既然采用多线程并发执行可以提高CPU的利用率,可是为什么反倒用在Android的图片加载上变得更慢了?
看到这里,你应该已经想到原因了。就好像我们写代码,一个人同时写两个Android应用,并发布上线。假设应用发布不需要上线审核,且A与B的功能几乎相同。如果我们去先写应用A的一个功能,当A某一个功能写完的时候再去写应用B相同的功能,那么写起来自然是要快很多。这就是并发执行,同时去执行A与B。但是这样A与B完成的总时间是缩短了,可以单个A应用完成的时间却被拉长了。因为写到一半的时候被迫去完成B应用。
所以这也是为什么你会发现37版本之前的OSC客户端图片几乎是同时出来的。
回到Android上,我之前的博客曾讲过:AsyncTask在android2.3的时候线程池是一个核心数为5线程,队列可容纳10线程,最大执行128个任务,这存在一个问题,当你真的有138个并发时,即使手机没被你撑爆,那么超出这个指标应用绝对crash掉。 后来升级到3.0,为了避免并发带来的一些列问题,AsyncTask竟然成为序列执行器了,也就是你即使你同时execute N个AsyncTask,它也是挨个排队执行的。 这一点请同学们一定注意,AsyncTask在3.0以后,是异步的没错,但不是并发的。不知道的同学可以去看看《Thread并发请求封装——深入理解AsyncTask类》,《一套完善的Android异步任务类》
现在想来,Android SDK把并行执行改为串行执行也并不无道理。
也许你会担心,那改回串行以后会不会又出现同时加载129个图片的时候崩溃的问题。当然,是不会的。在图片加载的时候已经做了下载任务取消的设计,在listView中加载图片的时候,如果滚动出这一屏,图片的下载任务会马上停止,而去加载新的图片下载。总不会一个屏幕就显示129张图吧。
/** * 取消一个下载请求 * * @param view */ public void cancle(View view) { for (BitmapWorkerTask task : taskCollection) { if (task.imageView.equals(view)) { task.cancelTask(); taskCollection.remove(task); break; } } }
建议继续学习:
- 关于IO的同步,异步,阻塞,非阻塞 (阅读:14456)
- fsockopen 异步处理 (阅读:9016)
- 配合jquery实现异步加载页面元素 (阅读:5368)
- 使用django+celery+RabbitMQ实现异步执行 (阅读:5005)
- 异步编程与响应式框架 (阅读:3890)
- 多核与异步并行 (阅读:3863)
- redis源代码分析 - event library (阅读:3159)
- Google Analytics 异步代码详解 (阅读:3139)
- 异步完成后新开窗口 (阅读:2938)
- php的异步http请求类 (阅读:2907)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:开源实验室 来源: 开源实验室
- 标签: 异步
- 发布时间:2016-04-02 23:13:01
- [67] Go Reflect 性能
- [67] Oracle MTS模式下 进程地址与会话信
- [67] 如何拿下简短的域名
- [61] IOS安全–浅谈关于IOS加固的几种方法
- [60] 图书馆的世界纪录
- [59] 【社会化设计】自我(self)部分――欢迎区
- [58] android 开发入门
- [56] 视觉调整-设计师 vs. 逻辑
- [49] 给自己的字体课(一)——英文字体基础
- [47] 界面设计速成