Androidでマルチスレッド処理による画像処理アプリを作っているときに気が付いたこと。 各ピクセルの色成分を取得し、Math.random()で乱数を加味して処理、といったプログラムを作っていたのですが、「マルチスレッドにすると速度が落ちる」現象に悩まされました。処理自体は、ピクセル毎に完全に独立していて、どう考えても「並列処理で速度が上がるプログラムの典型」だったのですけどね。 となると考えられるのはただ一つ。どこかに「大きなボトルネック」ができている、としか思えないですよね。で、コードの一部を無効化したりして速度を調べていると……各ピクセルの処理で2回呼び出すMath.random()をコメントアウトすると劇的に速度が向上することが判明。そう、Math.random()がコードの実行を止めていたわけです。 なんでこうなる、と思って調べてみると、Javaのリファレンスに答えがありました。
マルチスレッドでRandomを使うと速度が落ちるよ、と。試しにスレッド毎にRandomオブジェクトを生成して、そのRandomオブジェクトで乱数を生成すると、速度低下がなくなりマルチスレッドによる高速化が実現。 まさかRandomクラス(を使うと思われるMath.random)にこんな特性があるとは知らず、解決までにかなり試行錯誤してしまいました。スタティック関数では一つのオブジェクトを使いまわす実装が多いはずですから、注意が必要ですね。マルチスレッド処理のコードにスタティック関数やオブジェクトを組み込むなら、ライブラリのドキュメントでスレッドセーフであること、複数スレッドで呼び出したときに何が起こるか、確認するようにしなくては。 |