为什么我的Clojure项目在Raspberry Pi上很慢?

问题描述:

我一直在为我的Raspberry Pi编写一个简单的Clojure框架来播放音乐(以及其他一些其他的东西)。该程序解析给定的音乐目录中的歌曲,然后通过TCP接口开始监听控制命令(如开始,停止,下一首歌曲)。为什么我的Clojure项目在Raspberry Pi上很慢?

代码通过GitHub上可用: https://github.com/jvnn/raspi-framework

当前版本适用于我的笔记本电脑就好了,它开始播放时将指示音乐(使用JLayer库),改变歌曲,只是停止,因为它应该。 uberjar也需要几秒钟的时间才能开始使用笔记本电脑,但是当我尝试在Raspberry Pi上运行时,情况变得非常缓慢。

只需启动程序,以便所有类都加载并且实际程序代码开始执行需要一分多钟。我尝试使用-verbose:class开关来运行它,而且似乎jvm一直花费大量的类(用于Clojure和其他所有类)。

当程序最终启动时,它确实对给定的命令作出反应,但回放非常滞后。有一个短暂的亚秒声音,然后暂停几乎一秒钟,然后是另一个声音,另一个暂停等等...所以该程序正在尝试播放某些内容,但它不能足够快。 CPU使用率接近98%。

现在,拥有一部Android手机和所有的手机,我相信Java可以在这样的硬件上执行,足以播放一些mp3文件而不会有任何麻烦。我知道JLayer(或其中的一部分)在gdx游戏开发框架(也可以在Android上运行)中使用,所以它也不应该是一个问题。

所以,一切都指向我是问题。有没有什么我可以用leiningen(aot已经启用所有文件),Raspberry Pi或我的代码可以使事情变得更快?

谢谢你的时间!

UPDATE:

(ns test.core 
    (:import [javazoom.jl.player.advanced AdvancedPlayer]) 
    (:gen-class)) 

(defn -main 
    [] 
    (let [filename "/path/to/a/music/file.mp3" 
     fis (java.io.FileInputStream. filename) 
     bis (java.io.BufferedInputStream. fis) 
     player (AdvancedPlayer. bis)] 
    (doto player (.play) (.close)))) 

的project.clj:

(defproject test "0.0.1-SNAPSHOT" 
    :description "FIXME: write description" 
    :dependencies [[org.clojure/clojure "1.5.1"] 
       [javazoom/jlayer "1.0.1"]] 
    :javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"] 
    :aot :all 
    :main test.core) 

我做了一个小测试案例,以排除一些可能性和存在的问题仍与以下Clojure的代码存在所以,没有core.async和无线程。回放确实变得更平滑,但它仍然是大约200ms的音乐和200ms的暂停。

+0

我认为这可能与pi的CPU上较小的缓存大小有关。 Clojure非常棒,但对于大多数其他语言来说,Clojure对缓存流失的要求要高得多(尤其是因为它使用了不可变的数据结构)。 – noisesmith

+0

我认为这不能解释播放问题(不是我猜想的启动速度很慢)。因为(至少如果代码的工作原理,我的意思是工作),这是由java库处理,所有Clojure代码应该停放并等待一些异步通道输入。 –

+0

该停车可能涉及一些上下文切换。上下文切换会摧毁您的缓存,这很昂贵(特别是在总线速度较慢的情况下)。一旦你的媒体流直接从RAM(甚至是磁盘)直接从输出设备传输到输出设备而没有修改,那么跳过的内容就是上下文切换,并且上下文切换需要的缓存越多,跳过问题越严重将会。 – noisesmith

对我来说最明显的是你有很多un-hinted interop代码,导致非常昂贵的运行时反射。尝试运行lein check(我认为这是内置的,但也许你需要一个插件)并修复它指出的反射问题。

+0

感谢您的回答。 Lein检查没有告诉我什么,但唯一的输出是“编译命名空间...”。但是,我猜即使在运行时使程序运行速度较慢,反射也不能成为启动时间较长的原因吗? –

+0

重新启动时间... Clojure只是很大,而树莓派很小。如果你看到一大堆时间在启动时加载类,那可能是因为需要加载很多类。我想你的jar文件相当庞大,与pi想要看的相比。 – amalloy

+0

好吧,这是我害怕听到的。我希望会有东西(优化,不同的Java版本等),可以做的更好。 –