POSTD PRODUCED BY NIJIBOX

POSTD PRODUCED BY NIJIBOX

ニジボックスが運営する
エンジニアに向けた
キュレーションメディア

POSTD PRODUCED BY NIJIBOX

POSTD PRODUCED BY NIJIBOX

ニジボックスが運営する
エンジニアに向けた
キュレーションメディア

FeedlyRSSTwitterFacebook

本記事は、原著者の許諾のもとに翻訳・掲載しております。

質問 なぜ”B”と表示するのは”#”と表示するよりも著しく遅いのでしょうか?

1000 x 1000 のマトリックスを2つ作りました。

1つ目のマトリックス: O #
2つ目のマトリックス: O B

次に示すコードを使うと、1つ目のマトリックスは出力が完了するまでに8.52秒かかりました。

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("#");
        }
    }

   System.out.println("");
 }

以下のコードで、2つ目のマトリックスは出力が完了するまでに259.152秒かかりました。

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("B"); //only line changed
        }
    }

    System.out.println("");
}

これほど実行時間に著しい差異が生じたのは、なぜでしょうか?


コメントで示されている通り、 System.out.print("#"); だけの表示ならば、かかる時間は7.8871秒なのですが、 System.out.print("B"); を含むと still printing... となってしまいます。

自分の環境では問題がなかったと指摘する方々もいらっしゃるように、この2つのコードを試しに Ideone.com で実行してみたところ、同じ速さで実行できました。

テスト条件は次の通りです。

  • 実行環境はNetBeans 7.2でのコンソール出力
  • 計測に使用したのは System.nanoTime()

asked by Kuba Spatny

Answer(s)

Answer 1

まったくの推測 なのですが、使っている端末が、文字単位の折り返しではなく ワードラップ を行っており、 B は単語を構成する文字として、 # は単語を構成しない文字として扱っているのではないでしょうか。つまり、行末に達して、折り返すべき位置を探す際、 # であればほぼ即時に適切にその位置で折り返すことができます。それに比べると、 B の方が折り返し位置を探す時間は長くなりますし、折り返すべきテキストも多くなるかもしれません(これは端末によっては、コストの高い処理となる可能性があります。例えば、バックスペースを出力したあと、折り返されている文字の部分を上書きするためのスペースを出力するかもしれません)。

ただし、上記はあくまでも推測です。

community wiki by T.J. Crowder

Answer 2

EclipseとNetBeans 8.0.2の両環境でテストしてみました。いずれもJavaのバージョンは1.8で、計測には System.nanoTime() を使いました。

Eclipse

どちらの場合も同じ時間 がかかりました。 1.564秒 ぐらいです。

NetBeans

  • “#”を使用: 1.536秒
  • “B”を使用: 44.164秒

つまり、NetBeansではコンソール表示のパフォーマンスが悪いようです。

さらに調べた結果、NetBeansでは 行折り返し が最大バッファで行われることが問題であると分かりました(これは System.out.println コマンドに限りません)。以下のコードで確認できます。

for (int i = 0; i < 1000; i++) {
    long t1 = System.nanoTime();
    System.out.print("BBB......BBB"); \\<-contain 1000 "B"
    long t2 = System.nanoTime();
    System.out.println(t2-t1);
    System.out.println("");
}

試した結果、かかった時間は例外を除いてどの繰り返しでも1ミリ秒未満となり、 5回目ごとの繰り返し の際に限って225ミリ秒ぐらいかかりました。次のような状況です(単位はナノ秒)。

BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
.
.
.

以下、続いていきます。

まとめ

  1. Eclipseでは”B”でも問題なく動作する。
  2. NetBeansでは行折り返しが問題となるが、解決策はあるはず(Bの後ろにスペースを入れて”B “としなくても、Eclipseでは同じ問題が起きていないため)。

answered by Roy Shmuli

監修者
監修者_古川陽介
古川陽介
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
複合機メーカー、ゲーム会社を経て、2016年に株式会社リクルートテクノロジーズ(現リクルート)入社。 現在はAPソリューショングループのマネジャーとしてアプリ基盤の改善や運用、各種開発支援ツールの開発、またテックリードとしてエンジニアチームの支援や育成までを担う。 2019年より株式会社ニジボックスを兼務し、室長としてエンジニア育成基盤の設計、技術指南も遂行。 Node.js 日本ユーザーグループの代表を務め、Node学園祭などを主宰。