4

こんにちは、
入力から一連のトークンを受け取り、それらを私が設計した有限状態マシンに供給するプログラムを設計しています。私は、マシン自体の構造体と遷移などを使用して、オブジェクト指向スタイルでテスト用の有限状態マシンを設計しましたが、私が書いているアプリケーションは速度が非常に重要なものです。

これまでのところ、マシンの使用、新しい状態の追加などは簡単で、それほど複雑ではないことが証明されています。理解するのは簡単で、1 か月放置してコードに戻っても、それほど混乱することはありません。ただし、現在の OO アプローチと速度のトレードオフがどうなるかはわかりません。gotoオブジェクトの割り当て、データの保存などは、一連のラベルやステートメントを使用することで得られる速度の多くを奪いますか?

4

5 に答える 5

3

「ラベルとステートメントの束」よりも、よく構造化された、保守可能で、理解しやすい (1 か月間離れた後でも、それはかなりの品質です) コードを好みます。gotoそうは言っても、コードでプロファイラーを実行して、速度分析を行うときにボトルネックを検出します。

于 2010-09-30T04:29:06.823 に答える
3

オブジェクト指向が関数型プログラミングや手続き型プログラミングよりも遅いという観点から考えるのではなく、操作の観点から考えてください。関数の呼び出し、分岐、フェッチ、保存などはすべて時間がかかり、各ソリューションのパフォーマンスを把握するには、これらのそれぞれをどれだけ実行する必要があるかを集計する必要があります。

これを行う最善の方法は、OO テスト ソリューションを使用して、それが十分に高速かどうかを確認することです。そうでない場合は、プロファイルを作成し、最もコストがかかる支店や店舗を特定し、それらを回避または合理化できるかどうかを確認します。求めているパフォーマンス目標が達成されるまで、ソリューションをゆっくりと再構築してください。場合によっては、より機能的または手続き的なスタイルを採用する必要があるかもしれません。

最後に、数百のスタック変数で構成される単一の関数をコーディングして goto を実行した場合、それは間違っています。コードは常に読み取り可能で保守可能でなければなりません。

余分な考え: 開発コストの最適化に 50,000 ドルかかるのを避けるために、より良いハードウェアにさらに 5,000 ドルを費やすことはできますか?

于 2010-09-30T04:34:23.780 に答える
3

簡単に言えば、プロセッサはテーブル ルックアップ時にテーブル ルックアップを実行する方がブランチよりも高速です。テーブルが扱いやすく、キャッシュに収まるほど小さい限り、オブジェクト指向スタイルとして説明するものは高速になります。(ただし、どちらのパラダイムもどちらの実装にも関連付けられているとは言えません。)

やや技術的に言えば、プロセッサには 32 ~ 64 K の L1 キャッシュと、数メガバイトから数十メガバイトの L2 ~ L3 があります。ブランチ キャッシュは、せいぜい数キロバイトです。

于 2010-09-30T04:52:48.717 に答える
1

ステートマシンはどのくらいの頻度で変更されますか? しばらく変わらない場合は、好きな言語でハードコードされたルーチンに変換します。

ステートマシンの遷移図はどこから来たのですか? それは正規表現から来ていますか?最初にアークセットを構築しなくても、それを構造化コードに直接変換できることはご存知でしょう。実際、最初からそのコードを書く方が簡単かもしれません。

次に、アプリのその部分を作成するか、動的にコンパイルして dll にリンクし、動的にロードします。後者はほんの数秒かかります。

有限ステート マシンは非常に単純であるため、基本的には、I/O バッファーの読み込みにかかる時間のごく一部で実行する必要があります。不必要なメモリ割り当て、データ構造の構築、その OO ホーホーのいずれかを行うべきではありません。

ステートとアーク タプルのセットとして表される有限ステート マシンは理論モデルであることを思い出してください。チューリングマシンのように、それに関する定理を証明するために存在します。チューリング マシンと同様に、コードでの実装手法として必ずしも優れているとは限りません。


私が言いたいことを示すために、10 進整数の正規表現を考えてみましょう。

dd*

ここで、「d」は数字を意味します。有限状態マシン (タプル) としては、次のようになります。

A d -> B
B d -> B

コードとしては次のようになります。

char c = getc();
if (DIGIT(c)){
  c = getc();
  while(DIGIT(c)){
    c = getc();
  }
}

このコードが正規表現と似ていることがわかりますか? c = getc()「次の文字 c を取得する」と考えないでください。「現在の文字 c を受け入れる」と考えてください。コードがこれよりはるかに高速になることはないことがお分かりいただけると思います。

実際にアークセットから開始する場合は、次のように生成できます。

c = getc();

A:
if (DIGIT(c)){c = getc(); goto B;}
goto END;

B:
if (DIGIT(c)){c = getc(); goto B;}
goto END;

END:

これはスパゲッティ コードですが、アーク セット以上のものではなく、構造化コードと同じくらい高速です。(実際、これは多かれ少なかれコンパイラが構造化コードを変換するものです。)

于 2010-09-30T14:02:59.070 に答える