最近被一个android大量数据计算过程的提速问题困扰了一个星期,在尝试了各种办法之后,最终拜倒在了GPU的强大运算力面前。

我尝试过的实现一共有三种。

1. 平铺直叙的单线程java实现

这个主要是为了快速实现逻辑,用来检验代码正确性的,效率不是他需要考虑的问题,所以慢一点我也没什么意见。

2. jni调用C++,越过JVM,在native层实现运算逻辑

一开始实现完发现比java版快了10倍,顿时对native的效率赞叹不已。但之后总感觉哪里不对头,因为我记得java比C++只慢一点点,差距绝不会是一个数量级那么多。

后来检查发现是实现有误,纠正后整个运算竟然比java版还稍微慢了一点点。原因可能是java版里使用了android自己的jni版RGBtoHSV函数,而我无法从NDK平台直接调用android内置的实现,所以找了一个native版的实现,这个实现比java版慢了。

不管怎么说jni比java慢还是太反直觉了,可是用android-ndk-profiler测了一圈也没看出什么异常来,似乎纯粹的数字运算就是要耗费这么多时间。

这里需要强调的是,我的整个运算过程只调用了一次jni函数,慢不是因为频繁的跨语言通信导致的。

3. 借用GPU的力量进行运算。android平台强大的renderscript!

实在不行就试试GPGPU这招我一开始就想到了,但是没想到实现起来会这么方便。这里真的要给android平台点个赞。

说来惭愧,游戏行业从业三年,我的3D编程能力还仅停留在对照教材实现示例的程度。本来这次都做好了3天入门OpenGL的打算了,没想到android自己内置了直接使用GPU的能力。启动运算传递数据的过程都可以直接从java中做到,我只需要额外学一个用来在GPU中执行的renderscript文件的写法就可以了。而这个renderscript语法类似C语言,比swift还好学啊。

renderscript最大的坑在于从出现到现在写法有变动。本来指导教程就少,里面还有很多已经变成了错误示范,无形坑人,最为致命。在跨过了这些教程坑以后路就平坦多了,业务逻辑的移植和结果验证一天搞定。

需要注意的是,renderscript本身并不保证一定会使用GPU,老版本的android好像只会用多线程CPU实现代替。不过我们项目的目标平台API LEVEL够高,不用太在意这个问题。

还有一点要说的是,renderscript目前只能做互不相干的大量运算,而像累加求和啊求最大值最小值之类各个运算结果之间会互相影响的密集计算要等android 7.0(API LEVEL24)以后才能支持,而且直觉上来说也不会有纯粹无关的运算那么快,不能过高估计他的效率。

以上,android版的优化总算是有惊无险的完成了。之后要研究iOS平台的同类问题,可能还会再写一篇总结。

其实我已经稍微调查了一下,遗憾的是iOS上似乎并没有android的renderscript这么方便的GPGPU支持,那到头来我还是要去入门一下OpenGL了,唉。(咦?我怎么还有点小高兴?!)