3

アプリケーションを「スクリプト化」できるようにしたいと思います。スクリプト言語は、Cのように入力する必要があります。通常の制御ステートメント、プリミティブ型、配列、および演算子が含まれている必要があります。これらは、CとJavaの両方にあります。スクリプトは、関数を定義し、sin()などの事前定義されたAPI関数を呼び出すことができる必要があります...私が提供することを選択します。スクリプトが構文チェックに合格すると、アプリケーションによってJavaに変換され、その場でコンパイルされますが、C / C ++に変換して、ネイティブにコンパイルすることも可能です。構文チェックとJava/Cへの変換は、JVMで実行する必要があります。常にJava/Cに翻訳されるので、通訳は必要ありません。構文チェッカーとトランスレーターのみ。

そこにそのような言語はありますか?そうでない場合、コンパイラ/インタプリタプログラミングに精通していないことを考慮して、JVMでこれを行う最も簡単な方法は何ですか?(もしそうなら、この質問をする必要はありません...)

「Scala」ソリューションがある場合は、実際にJavaコードをScalaに移動しているので、それでも問題ありません。

[編集]C/C++変換が必要な唯一の理由はパフォーマンスです。配列に対する多くの「ビット操作」を期待していますが、特にすべての配列インデックス操作での範囲チェックのため、Javaはあまり適していません。また、GCサイクルで間接的にコストがかかる多くのオブジェクトも期待しています。

[編集#2]わかりました、具体的にしなければならないようです。「ビジネスコンピューティング」から抜け出すための演習として、Minecraftのクローンをプログラミングすることを検討しています。私はゲームプレイではなく、エンジンについて話している。そして、私は「サーバーガイ」なので、3Dよりもサーバーサイドに興味があります。フライトウェイトパターンを使用して数百万のオブジェクト(ブロック/ボクセル)を表し、1秒間に何度もそれらにアクセスすることについて話しています。これは、JVMの目的ではありません。私が意味する例については、この記事を参照してください。JavaではなくCPPを選択した理由

すべてをC/C ++でプログラムしたくはありませんが、これが優れたパフォーマンスを得る唯一の方法だと思います。私が言っているもう1つの例は、VoltDBです。これは、間違いなく、そこにある最速のSQLデータベースです。彼らはそれをJavaとC/C ++で記述し、I / OとネットワークにJavaを使用し、大量のメモリ操作とビット操作にCを使用しました。ユーザー作成のストアドプロシージャはJavaですが、そうである必要はないと思います。クライアントとテストビルドでJavaにコンパイルし、完全な開発環境を構成できるサーバーでCにコンパイルできるはずだと思います。

4

9 に答える 9

4

たぶんHaxeはあなたのニーズに合うでしょう。これは、C++ソースコードにコンパイルできる中級高級言語です。Javaターゲットは開発中です。

于 2011-07-07T11:12:04.983 に答える
3

2 つの言葉: 時期尚早の最適化。

パフォーマンスが心配です。しかし、Minecraft のクローンを作りたいと考えると、これは、ゲームの世界を 3 次元配列でうまく表現できることを意味します。これらへのアクセスは、前述のすべてのプログラミング言語でかなり高速です。ゲーム ロジックの実行には、何百万もの配列エントリにアクセスするよりもはるかに時間がかかるはずです。では、最小限の作業バージョンを作成する前に、とにかく計算時間の大部分を必要としない部分を最適化する必要はありません。

ゲームの世界を表す Java インターフェースまたは Scala トレイトを作成したい場合があります。ゲーム世界のブロックのコンテンツを取得して保存するメソッドを提供します。後で一括メソッドを追加して、パフォーマンスをさらに最適化することもできます。たとえば、特定の立方体のすべてのブロックが空かどうかをチェックしたり、木のブロックの数を数えたり、それらの線に沿ったものです。ただし、最初は、これらのメソッドを除外するか、抽象メソッドを繰り返し呼び出すことに依存する単純な実装を作成することをお勧めします。後で最適化できます。

次に、実際に 3 次元配列を使用する、そのインターフェースの非常に単純な Java/Scala 実装を提供できます。代替案は、キーが座標で、値がブロックの状態であるマップです。利点は、ゲーム世界のサイズに実際の制限がなく、空のブロックがメモリを消費しないことです (空のブロックを含む座標の場合、マップにエントリはありません)。不利な点は明らかにパフォーマンスです。

その時点で、メモリを消費しすぎる場合は、データをより密にパックすることを検討してください。ビットセットを使用できます。その段階に到達したら、JNI を使用して、C または C++ で記述されたコードを JVM に挿入することは実際には理にかなっています。したがって、ゲーム ロジックは Java/Scala に保持し、メモリ パッキングとルックアップは C で行います。

コードのネイティブ部分の Java/Scala および C/C++ バージョンを作成できる共通の「スクリプト」ソースを作成しても意味がありません。ネイティブの C/C++ 関数は、Java に直接変換できない最適化に大きく依存します。「純粋な Java/Scala モード」でサーバーを起動する場合、つまり JNI 関数を使用しない場合は、前の手順で作成した他のクラスを使用するだけです。少し遅いかもしれませんが、純粋な JVM バイト コードです。そして、それらをシンプルに保っているので、乱暴に拡張したり、新しいバグを導入したりする必要があるという危険はありません。少なくとも、クロスプログラミング言語のコード ジェネレーターを作成または適応させるオーバーヘッドは、特に Java/Scala の実装が非常に単純な場合は、2 つの別個のコード ベースを保持するよりもはるかに大きくなります。

もちろん、ビット パッキングではここまでしかできません。ゲーム ワールドのいくつかの部分 (特に地表より上) はほぼ完全に空であり、他の部分には同じ種類のブロックで満たされた巨大なエリア (ほぼ石だけで構成されている地下エリアなど) が含まれていることに注意してください。それだけの冗長性を備えた巨大なメモリ構造を維持することは、実際にはメモリの無駄です。そのため、ゲーム ワールドをツリーに詰め込むことを検討することになるでしょう。各ノードはゲーム ワールドの大きな立方体領域を表し、子供たちはそれをさらに分割して、1 つの特定のゲーム ワールド座標の内容を記述する葉にします。1 つのノードに同じコンテンツ タイプの子しかない場合、子を格納する必要はありません。この時点でツリーを切り取り、ノードに「これ以上見る必要はありません。とても良いです!- もちろん、ツリーを変更可能にしておく必要があります。1 つのノードだけで表される世界の退屈な部分が変化した場合は、そのノードを分割して 2 つ以上の子に分割する必要があります。後でまた簡単になったら、また子供たちと一緒に木を切ることができます。

この時点で気付くかもしれないことの 1 つは、メモリのパッキングとアクセスの最適化は、ここではもはや実際の問題ではありません。このようなツリーは、ストレージ メソッドとルックアップ メソッドにネイティブ関数を使用しても合理的に最適化することはできません。そのような最適化から、たとえば 10% 以上を得ることができれば、これは非常にありそうもないことであり、非常に印象的です。(おそらく、これは、Java/Scala の対応物が適切に最適化されていなかったことを意味している可能性があります。) このような最小限の速度向上は、それに投入する必要がある膨大な追加の労力を正当化するものではありません。代わりに、より優れた CPU をマシンに搭載し、節約した時間をアイスクリームを食べたり、Dr. House を見たり、ゲームをさらに強化してプレイヤーにとってより面白く魅力的なものにしたりして楽しんでください。製品を本当に改善する価値のあるものを作成することによって.

しかし、これはまだそうではありません。私の記憶が正しければ、マインクラフトの世界の初期状態は手続き的に生成されます。フラクタル アルゴリズムを使用すると、瞬く間に複雑で自然な無限の領域を実際に作成できます。したがって、ゲーム ワールドのコンテンツを事前に計算して巨大なデータ構造に格納する代わりに、ワールド生成手順をルックアップ メソッドとして使用することをお勧めします。メモリから座標のコンテンツをルックアップする代わりに、アルゴリズム。このようにして、世界の初期状態を 4 バイト (アルゴリズムのシード値) に完全に格納できます。

もちろん、世界が常にこの状態にとどまるわけではありません。プレイヤー (または他の何か) が世界を変えるとき、これは保存する必要があるものです。したがって、ワールドのシード値とそれに加えられた変更のみを保存します。座標の内容を検索するときはいつでも、変更されたタイル ストレージで検索してみてください。そこにあるときは、その情報を使用してください。存在しない場合は、デフォルトで手続き型ワールド生成アルゴリズムを使用します。これにより、メモリ消費量が大幅に減少します。また、世界への変更は比較的小さく、巨大な空の領域が含まれているため、これらの変更を迅速かつ効率的に格納するデータ構造を作成するのは比較的簡単です。繰り返しますが、このためにネイティブ コードを記述しても、パフォーマンスが大幅に向上することはなく、努力する価値はありません。

ただし、他にも最適化できるものがあります。手続き型ワールド生成アルゴリズムです。これは、C または C++ で作成する必要がある主要なコンポーネントの 1 つです。比較的小さく、多くのコードは必要ありませんが、数学集約的であり、非常に頻繁に呼び出されます。したがって、それを適切に最適化し、それから小さな JNI ライブラリを作成してください。これにより、努力する価値のあるパフォーマンスが大幅に向上します。(もちろん、最初に Java/Scala の実装を行いたいと思うかもしれません。それがすでに十分に速い場合は、JNI の問題に取り掛かる必要はありません。)

ワールド生成手順がまだ遅すぎる場合は、キャッシュを実装できます。キャッシュは、JVM が遅延しているときに、プレイヤーの周囲の一部をプリエンプティブに生成することもできます。

この開発プロセスをいくつかのアイデアの繰り返しとして説明しましたが、前のアイデアよりも優れたものがあります。最初の段階で、最適化された C/C++ コードのライブラリを書き始めているイメージ。時間の無駄だったでしょう。後の段階ですべてを捨てることができたでしょう。C で記述された、ビット パッキングを使用する効率的な配列ストレージは優れた機能ですが、世界をバイナリ空間で分割されたツリーに再編成する場合は、まったく役に立ちません。

だから、無理しないでください。Java/Scala だけで最小限の動作をする (まだ遅くて最適化されていない) バージョンを作成できない場合、C/C++ またはクロスコンパイル スクリプト言語で最適化されたバージョンを作成することもできません。最初に単純なバージョンを実行してから、パフォーマンス テストを実行し、本当に必要な場合にのみ最適化します。最初に最適化のコンセプトを作ることからプロジェクトを始めないでください。この種の最適化は、あなたが取り組む最後のものであるべきです。

于 2011-07-08T01:52:27.373 に答える
2

そのような言語はありますか?... JVM でこれを行う最も簡単な方法は何ですか?

普通の Java を使用して、JVM にコードをネイティブ マシン コードにコンパイルさせます。これが必要な場合は、このコンパイルをより積極的にすることができます。

おそらく、JVM がまだ提供していない、何を獲得したいのかを明確にすることができます。


独自のミニ言語を真剣に開発したい場合は、何が必要かについて現実的な考えを持つ必要があります。コミットメントをしないと、あまり良くないものを思いつく可能性があります。

http://www.ohloh.net/p/openjdk/estimated_cost

OpenJDK: Project Cost Calculator

Include     
Codebase    4,782,885 lines
Effort (est.)   1451 person-years
Estimated Cost  $ 79,805,125
于 2011-07-07T11:04:30.283 に答える
2

JavaScript 構文は、C/C++ および Java に似ています。JavaScript エンジンにはさまざまなものがあり、Java でコーディングされているのはRhinoです。

コードを独自のバイトコードにコンパイルし、そこから機械語コードにコンパイルするコンパイラ エンジンであるLLVMもあります。また、JIT が統合されており、多数の言語フロントエンドが存在します。私はこのプロジェクトについてあまり知りませんが、面白そうです。

于 2011-07-07T11:19:33.333 に答える
1

Scala はオプションのように見えるので、それに固執してください。

インタープリター (REPL で使用される) を独自のコードから直接呼び出すことができます。それは、スクリプトを Java バイトコードにコンパイルしてから実行します。特に静的型付けの要件を考えると、パワーと柔軟性の点でこれに匹敵するソリューションを見つけるのは非常に難しいでしょう。

パフォーマンスに関しては、JVM はバイトコードをネイティブ コードにさらにコンパイルする役割を担い、この仕事もかなり得意です。C/C++ で大幅なパフォーマンスの向上が見られるとは思えません (特に、コンパイル時間は大幅に悪化します)。

于 2011-07-07T13:34:36.660 に答える
0

Groovyは、JVM上でCのようなスクリプト言語として非常にうまく機能することがわかりました。

それをC/C ++にどれだけうまく変換できるかはわかりませんが、呼び出す必要のあるC / C ++コードがある場合は、JNIを使​​用して簡単にリンクできます。

JVMベースのコードをC/C++に変換することに他の価値はないと思います。JVM JITは、明らかなコンパイルパス(JVM言語-> JVMバイトコード->ネイティブ)に対してすでに非常に優れたコンパイラであり、はるかに複雑な(JVM言語-> C / C ++)を実行しようとするあらゆるもののパフォーマンスをほぼ確実に上回ります。 ->ネイティブ)。

于 2011-07-07T11:12:49.803 に答える
0

これは完全なCですが、おそらくあなたの目的に役立ちます。シビル

于 2011-07-07T11:08:53.870 に答える
0

JavaScriptはどうですか?私はあなたの要件のすべてを満たしているわけではありません (型付けが弱いだけです) が、それらのかなりの数を満たしているようです: C のような通常の制御ステートメント、および演算子、配列、関数、独自の API を提供できます... Java にコンパイルすることもできますが、最新のインタープリターはとにかくジャストインタイムでコンパイルするのが得意です。Java で作成している場合は、 Rhinoを参照することを強くお勧めします。

于 2011-07-07T11:29:03.977 に答える
0

すべての回答を読んだ後、これが私がやろうと決心したことです。プロジェクトを有利に進めるために、最初はスクリプトを使用しません。私が代わりにやろうとしているのは、Java でプログラムすることですが、問題のある構造を使用することはありません。

最初に、必要なユーティリティ メソッドをすべて備えたAPIベース クラスを作成します。そのコードの 95% は、私のために作業を行うライブラリに委譲するだけです。この API クラスには、プリミティブ コレクション クラスのファクトリ メソッドがあります。また、Point、Event などのいくつかのユーティリティ クラスになります。

次に、API オブジェクトを拡張してゲーム コードを作成します。アクセス修飾子は使用しないので、すべてパッケージ パブリックです。「final」、「static」、「this」、「super」、「abstract」、「interface」、配列、汎用ジェネリック、class-cast、「instanceof」、「new」、または例外処理は使用しません。String クラスを除いて、何もインポートしたり、その標準 Java API にアクセスしたりしません。標準 Java API から必要なものはすべて、API ベース クラスにラップする必要があります。演算子には、特にビット単位の制限がいくつかあります。

ジェネリック、クラスキャスト、または "instanceof" を使用しないことによる制限を克服するために、制御の反転、依存性注入、および少しのリフレクションを使用して問題を解決します。

これは、比較的簡単かつ迅速にプログラムできるはずですが、実行されません。後で、エンジンが安定してデバッグされたら、元のアイデアに戻って、最適化された Java または C++ に変換するパーサーを作成できます。これらの特別なJava コンストラクトをすべて削除すると、パーサーの作成がはるかに簡単になります。また、標準の Java 構文を使用するので、定義済みのパーサーを使用して、必要に応じてカスタマイズすることができます。

于 2011-07-09T09:35:08.490 に答える