APP下载

移动终端加载网络图片的算法研究

2013-04-29王晋东

科协论坛·下半月 2013年9期
关键词:多线程移动算法

王晋东

摘 要:随着移动设备的普及,越来越多的互联网应用都对加载图片的速度有很高的要求。在简要对比传统的同步和多线程两种加载图片方式后,给出相应地实现算法和评价。

关键词:移动 图片 多线程 算法

中图分类号:TP316 文献标识码:A 文章编号:1007-3973(2013)009-102-03

1 前言

iOS、Android、Windows Phone及Symbian等主流的移动操作系统现在均已支持加载jpg、png等常见格式的图片,随着应用对网络依赖程度的加强,这些操作系统也已支持直接从网络直接读取图片。而读取只要给出该图片的http地址(URL)即可。

对用户界面响应速度要求较高的应用而言,图片的加载速度不宜过慢。而随着如今终端屏幕分辨率的增加,用户对手机的图片质量也有了很高的要求。就单一服务器模式而言,以前流行的分布式算法显然达不到要求。

2 同步方式

同步方式十分简单。由客户端向服务器提交请求,服务器对此做出应答——应答的结果就是从远程向客户端返回符合要求的图片代码,图片接收完毕后再由客户端作解码、还原。同步方式的算法如下。

客户端:

BEGIN

Activate webservice

Send request to server

Wait for response

Download complete

END

服务器:

BEGIN

Receive reqests

Create response queue

While queue is not empty

dequeue

handle every request

END

这种方式的优点是简单,缺点也很明显:客户端增多时,服务器压力会陡然增大,而此种方式要求图片必须是连续加载,即客户端需要等待自己的加载要求出服务器队列时才会收到应答。图片一般比较大,所以它们都是在基本框架加载后才逐渐加载上的,整个加载的过程非常不雅观,或者是从模糊逐渐变清晰,或者是从上往下拓展开(当然你也可以认为这些都是不错的特效)。

3 多线程方式

3.1 统一需求

除了不能满足快速加载网络图片的要求以外,同步方式还存在诸多缺点。多线程方式通过采用不同的机制,不仅保证了快速加载图片的基本要求,更从流量上等方面具有较大的优势。

3.2 多线程与线程池

由于程序的代码中存在着数据和控制依赖关系,单线程只能很有限地满足当今处理能力的要求。为了增加处理器的处理能力而一味地强化指令的执行顺序和细化分支,有时也不见得能事半功倍。因此,现代微处理器多采用硬件多线程技术来发掘线程之间的线程级并行潜力。移动终端所采用的处理器多为ARM架构,很好地满足了多线程的处理要求。

多线程技术主要解决处理器单元内多个线程并行执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。但如果对多线程应用不当,会增加对单个任务的处理时间。可以举一个简单的例子:

假设在一台服务器完成一项任务的时间为T,它包括创建线程T1、执行任务T2、线程同步T3以及线程销毁的时间T4。显然,在理想状况下,T必然是这几部分的时间之和。

可以看出T1,T4是多线程本身的带来的开销,我们渴望减少T1,T4,从而减少T的时间。但是如果在程序中频繁地创建或销毁线程,会导致T1和T4在T中占有相当大比例,从而使整个执行的时间变长。这显然并没有很好地利用线程的并发性。

线程池技术正是关注如何缩短或调整T1,T4时间的技术,从而提高服务器程序性能的。它把T1,T4分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T4的开销了。另外,线程池不仅调整T1,T4产生的时间段,而且它还显著减少了创建线程的数目。

3.3 常见系统的线程类

Java中线程类Thread的继承关系为java.lang.Thread,在C#中是System.Threading.Thread,而iOS 支持NSThread等多个层次的多线程编程,层次越高的抽象程度越高,使用起来也越方便,也是苹果最推荐使用的方法。

这些系统的线程类使用起来都非常方便,它将作为我们快速加载图片的基础。

3.4 多线程模式的算法

为了不失一般性,我们约定,采用一种类似C#(当然也可以是Java)的语言来实现算法。

3.4.1 线程池的构造

class ThreadPool

{

Assume:isClosed,Queue,poolId and wait;

//是否关闭,队列,id,是否等待状态

//构造函数,参数为线程池大小

ThreadPool(size)

Initialize Queue as a queue; //创建新队列

For i:= 0 to size

Create and start a new thread; //启动一个新线程

//是否等待状态

bool isWait return wait

//设置为等待

void setWait(_wait) wait := _wait;

// 向队列里加入一个新的任务,由工作线程去执行任务

synchronized void execute(task)

//如果线程池已关闭,抛出异常,否则

if(task != null) then

While wait=true

Try

wait;

Catch

//Throw an exception

Add task to Queue;

Notify Queue;

synchronized Runnable getTask(threadId)

While Queue is not null

If isClosed then return null;

wait();

return First element in Queue // 返回队列中第一个元素

synchronized void closePool()

If !isClosed then

waitFinish(); // 等待工作线程执行完毕

isClosed := true;

Queue.clear();

interrupt();

//让线程池处于等待状态

synchronized void waitPool() this.wait := true;

//唤醒线程池

synchronized void notifyPool() this.wait := false;

// 等待工作线程把所有任务执行完毕

void waitFinish

synchronized;

isClosed := true;

notifyAll;

threads[] := new Thread[activeCount()]; // activeCount() 返回该线程组中活动线程的估计值

count := number of active threads

for I := 0 to count

if thread[i] is not interrupted then

set thread[i] to interrupted

}

3.4.2 工作线程类

class WorkThread

{

Assume:id;

WorkThread(_id)

Create a thread;

Id := _id;

void run()

While thread is not interrupted

Task := null;

Try

task = getTask(id);

catch

//Throw an exception

// 如果getTask()返回null或者线程执行getTask()时中断,则结束此线程

If task is not null then

try

Run the task;

catch

Throw an exception;

}

3.4.3 加载图片类

class LoadImage

{

Assume size;

void run()

Try

while true

//wait until images come into queue

if size = 0 then

wait for photoqueue;

else

create and initialize an instance;

Create a BitMapLoad instance;

threadPool.execute(bdd);

if Thread is interrupted then break

Catch

// Exit the Thread

}

3.4.4 BitMapLoad 类

// 本类用来支持多线程

class BitmapDownAndDisplay

{

Assume photoToLoad,Activity;

BitmapDownAndDisplay(photoToLoad, activity)

this.photoToLoad := photoToLoad;

this.activity := activity;

oid run()

create a bitmap;

synchronized (this)

bitmap := getBitmap(photoToLoad.url);

if bitmap is not null then

add bitmap to system cache;

if photoToLoad.imageView.getTag() is not null &&

photoToLoad.imageView.getTag() =photoToLoad.url then

set bitmap to UI thread to show

else

if wait=false

// 非阻塞线程则加会队列末尾

Add photoLoad to photoQueue;

}

4多线程与同步方式的比较

我们采用相同的实验平台:Windows Phone 7.5系统的模拟器,运行两段代码,一段为同步加载图片,另一段为多线程方式,在系统内部均没有缓存的情况下进行测试。网络图片来自http://pivotstudio.org,加载的效果如图2。

很明显,多线程方式的加载时间要大大优于同步方式。

5 多线程方式的优点总结

(1)在加载图片时使UI不至于阻塞太久,缩短了加载时间;

(2)多个图片控件同时加载,速度更快;

(3)实现算法具有通用性,主流平台均受支持;

(4)运用线程池以防止开启过多的线程,从而增大CPU的压力;

(5)可扩展性:在此基础上加入内存管理的机制,可以提高终端内存的使用率。

6 总结

在实际的应用中,越来越多的应用和游戏需要从网络获取很多的图片,本文所讨论的多线程加载图片的机制就很好地满足了上述要求。当然,尽管算法是通用的,在具体的项目和开发环境中还需要根据语言和平台的特点灵活编写程序,方能发挥出算法最佳地性能。

参考文献:

[1] 黄天柱,涂时亮.iOS开发UITableView加载图片的内存管理[J].计算机系统应用,2012(09).

[2] 沙博.基于Android手机平台的应用研究[D].吉林大学,2012.

[3] (美)马克,拉马赫.著.iPhone 3开发基础教程(第1版)[M].漆振,等.译.北京:人民邮电出版社,2009.

[4] 伏英娜.Windows Phone 7应用开发指南(第1版)[M].北京:电子工业出版社,2011.

[5] 佘志龙,陈昱勋,郑名杰,等.Google Android SDK开发范例大全(第3版)[M].北京:人民邮电出版社,2011.

猜你喜欢

多线程移动算法
基于MapReduce的改进Eclat算法
Travellng thg World Full—time for Rree
进位加法的两种算法
Java并发工具包对并发编程的优化
移动有声阅读让儿童文学回归故事本身
如何有效发挥课间操的锻炼作用
纪录片中摄影机的移动对动态布局的影响
移动版教学督导听课评价系统建设初探
基于多线程文件传输关键技术研究与实现
网页爬虫技术的关键技术研究探索