Javaプログラマーの目を通す

この記事は、すでに出先で書いている人向けではありません。
これは、外出する時間を過ごすかどうかに興味のない他の言語のプログラマー向けです。
たとえば、goとgoの違いは何ですか?

Goの原則


むかしむかし、新しいプログラミング言語を取り入れて作成することができました。
現在、言語は、その作成者が従う明確な原則を持っている場合にのみ、何らかの場所をとる機会があります。 言い換えれば、あなた自身の顔。
Goの原則は、シンプルさと生産性です。

シンプルさの原則は次のとおりです。
何もせずにできるなら、それなしでやる必要があります。

生産性の原則:
最も価値のあることは、開発者が費やした時間です。 利用可能なすべての手段で最小化する必要があります。

シンプルさの原理を説明します。
goには言語構造がほとんどありません。 たとえば、1サイクルのみ。 Goは2晩で習得できます。
Goはライブラリの動的ロードを拒否しました-コンパイルの結果は1つの大きな実行可能ファイルです
コンパイル中に警告が表示されることはありません。 不正確または「冗長性」は、コンパイルエラーです。
Goには、言語自体のレベルでコード形式が組み込まれています。 goコードの正規形式は1つだけです。

生産性のいくつかの例:
goコードは、Javaの同様のコードよりも20から30パーセント短くなっています(たとえば、単に余分な単語はありません。たとえば、各文の最後にセミコロンはありません。条件やループ演算子などに括弧はありません)。
Goには非常に高速なコンパイラがあります(大規模なプロジェクトをコンパイルするのに数秒かかります)。

生産性は、言語そのものだけでなく、それに付属する標準ツールでもあります。

生産性向上ツール


プロファイラー


私は、Javaプログラマーであるgoがどのように使用されるようになったのかについて少し説明します。
ゲームプロジェクト-マルチプレイヤースペースシューティングゲームを行いました。
最初は、サーバーサイドをJavaで記述しました。 彼女は働いた。
しかし、すぐにすべてが生産性によって制限されました。
1台のサーバーで実行できるクライアントは300個まででした。
これは、ゲームが収益を上げるには小さすぎます。

Javaプログラマとしてこれで何ができますか?
実際には少し:

1)gazeメソッドを使用して、コード内の無効な場所を探し、それらの修正を試み、各変更後にストレステストを再度実行します。 この方法は明らかに非効率的です。

2)代替サーバーライブラリの研究に没頭し、さまざまなオプションを試してください。 また、これは何の保証も与えません-私自身のコード、あるいはJava言語自体にさえ問題があるかもしれません。

3)最後に、1つ以上の有料プロファイラーを購入し、それらからいくつかの情報を取得しようとすることができました。 しかし、問題があります。 オフィスでローカルサーバーを使用する場合、数千のクライアントを起動するために必要な数の空きマシンがオフィスにないため、必要な負荷を作成できませんでした。 外部サーバーを使用する場合、そこでプロファイラーを実行するにはかなり複雑な構成が必要でした。 最後に、プロファイラー自体を選択するのは簡単なことではありません。

移動中、この問題は非常に便利に解決されます。
プロファイラーは言語の一部です。
任意のサーバーで有効にすることができ、その作業の結果はマシンにダウンロードでき、非常に便利なツールを使用してゆっくりと探索できるファイルになります。
これらのツールは、どの特定のコード行が最もメモリとプロセッササイクルを消費するかを示します。
それらを使用すると、すべての問題領域を迅速かつ効率的に見つけて修正することができます。 (ちなみに、ほとんどの場合、最終的には期待する場所ではありません。)

私のプロジェクトでは、サーバーは最初に20クライアントのみを「プル」するためにコピーしました(Javaよりもはるかに悪い)。 プロファイラーを使用した後、この数値は2500に増加しました。

レースディテクター


すべてのマルチスレッドアプリケーション作成者にとってのもう1つの頭痛の種は、競合状態です。
これらは、星が特定の方法で集まった場合にのみ発生する、とらえどころのないバグです。 つまり、スレッドが1つの順序で開始された場合、他の順序である場合はバグがあります-いいえ。 そして、順序は予測不能です。
この問題を解決するための標準ツールがあります-レース検出器。 有効にすると、実行中のプログラムは、異なるスレッドから共有メモリへのすべての安全でないアクセスについてログに書き込みます。
レースディテクターを使用すると、問題のあるすべての領域をすばやく、意図的に見つけて排除できます。

興味深いデザイン


私はgoプログラミングを教えるという目標を持っていないので、その構成をすべて分析するつもりはありません。 私は3つの最も興味深いものについてのみ説明します。 それらはすべて、純粋なJavaにはないパラダイムを記述しています。 そして、これらのパラダイムは非常に便利です。

これらは、インターフェース、ゴルーチン、およびチャネルです。

インターフェース


goのインターフェースは、Javaまたはc#のインターフェースに似ています。 これはメソッドシグネチャのセットですが、実装はありません。
主な違いは、エンティティがインターフェースを実装することを宣言する必要がないことです。
エンティティに必要なメソッドがすべて揃っていれば十分です。
それは何を与えますか? デカップリング。
他の人のライブラリを使用できます。 いくつかのメソッドセットを持つエンティティを見つけ、同じセットを持つインターフェイスを作成し、このエンティティをこのインターフェイスとして使用します。 他の人のコードを変更する必要はありません。コードを他の人のエンティティに関連付ける必要もありません。また、古典的な定型コードであるアダプタを記述する必要もありません。 生産性の原則の別の図。

ゴルチン


最初は、プログラミング言語のマルチタスクアプリケーション用のプロセスが発明されました。 彼らは重く、独自のアドレス空間を持ち、システムのリソースをすぐに「食べた」。 その後、スレッド(またはスレッド)が現れました。 彼らははるかに軽く、同じアドレス空間で動作しました。 プロセスが通常ユニットまたは数十によって開始された場合、数百がすでにスレッドを持っている可能性があります。 ただし、不注意に使用すると、システムのすべてのリソースが奪われる可能性があります。 ブロックされた場合でも、各スレッドはまだいくつかのリソースを占有していました。
スレッドの数を制限するために、スレッドプールの使用を開始しました。

Gorutinsは、1つの一般的な大きなスレッドプールによって実行されるタスクと考えることができます。 Goでは、ゴルーチンは非常に安価です。 パフォーマンスの問題なしで何百万ものゴルーチンを実行できます。 唯一の要件は、ゴルチンを「小さく」することです。 つまり、goroutinはすぐにそのジョブを実行し、終了またはブロックします(スケジューラーの観点からは同じことです)。

チャンネル


チャンネルは、ゴルーチン間の人種的に正しいコミュニケーション手段です。
goには重要なルールがあります:

共有状態で通信しないでください。 通信により状態を共有します。

その意味は、複数のゴルーチンがアクセスできる変数を使用しないことです。
代わりに、ゴルーチンが互いにデータを転送するようにします。
このデータ転送はチャネルを介して行われます。

進行中のチャネルは、一方の端でキュー(バッファ)であり、もう一方の端から書き込みおよび読み取りができます。
同時に、混雑したチャネルへの書き込みまたは空のチャネルからの読み取りを試みると、ゴルーチンはブロックされます。

しかし、最も興味深いのは、goには複数のチャネルから同時に読み取るためのデザインがあることです。
ゴルチンは、座ってメッセージが表示されるのを待つ複数のチャンネルをリストできます。 このメッセージを受信した後、ゴルーチンはロック解除されて処理され、(通常)次のメッセージを再び待機します。
したがって、たとえばチャットサーバーでは、goroutinはユーザーからのメッセージとチャットを終了する信号を待つことができます。 同時に。

依存関係管理


Mavenやgradleなどの依存関係管理ツールは、現在すべての主要言語に対応しています。
Goはさらに進んで、言語レベル自体で依存関係管理をサポートしました。
パッケージをインポートするとき(Javaでのインポートと同様の構成により)、最新バージョン管理システム(gitなど)でパッケージのローカル名とアドレスの両方を指定できます。

たとえば、「github.com/gorilla/websocket」

Goは、必要なパッケージを個別にダウンロードし、プロジェクトに含めます。 パッケージが以前にダウンロードされている場合は、単に使用されます。 すべてのパッケージを最新バージョンに更新するよう依頼することもできます。

ただし、ここで1つの不快な瞬間があります-goは常にパッケージの最新バージョンをダウンロードします。 複数の人がプロジェクトに取り組んでいる場合、これは異なる開発者からの異なるバージョンのパッケージにつながる可能性があります。

この問題を解決するには、外部ツール-パッケージマネージャーを使用します。
今日の最高の1つは滑空です。
Glideは2つのアクションに基づいています。
1)プロジェクトのすべての依存関係を見つけて、ファイルに書き込みます
2)これらの依存関係をダウンロードする

この場合、必要に応じて、パッケージの他のバージョン(最新以外)を指定して、ファイルを手動で編集できます。

GITはコミット識別子をバージョン識別子として使用します(他のバージョン管理システムはそれらに固有の識別子を使用します)。

弱点は行く


どの原則にも長所だけでなく弱点もあります。
私の意見では、単純化の原則に起因する悪いこととひどいことが1つあります。
悪いのは、ジェネリック医薬品の不足です。 恐ろしい-関数によって返されたコードをチェックすることによるエラー処理。

ジェネリックがないと、厳密な型指定を拒否する必要があります。
また、エラー処理により、同じ種類のコードが大量に発生します。 さらに、エラーを記述せずにそのままにしておくこともできます。

また、生産性の原則に従って、goにgoガベージコレクターを導入することが決定されました。 これ自体は悪くありません。 ただし、この同じコレクターは数秒ごとに起動し、システムの速度が著しく低下することを理解することが重要です。 ただし、これを使用すると、正常に戦うことができます。

結論


プログラマーは完全に移行する必要がありますか? いや とにかく、さようなら。 Javaは平均的に高速です。 より便利なライブラリと、アプリケーションを作成する実証済みの方法があります。

特定の問題を解決するためにgoを使用する価値はありますか? 間違いなく価値があります。

外出先で解決するのに最適なタスクは何ですか? スレッドが互いに多く通信するマルチスレッド高負荷サーバーソリューションの作成。

初心者にとって学習に適した言語は、goまたはJavaですか? 明確な答えはありませんが、時間の経過とともに、goを支持する議論が増えるでしょう。

舌の年齢が役割を果たします。 古い言語は「歴史的」なもので大きくなりすぎています。 かなり前に何かが追加され、今では誰もそれを必要としませんが、下位互換性が壊れているため、捨てることはできません。
以前は関連していた言語または標準ライブラリの一部の構成は、今では場違いに見えます。言語の標準の外側でこれらの要求されていないことを行うのは、より論理的なようです。
いくつかの標準的な問題については、さまざまな品質の多くの代替ソリューションが蓄積されています。 初心者にとって、これらはすべて、このスタイルでは役に立たないが必要な多数の知識です。「ここでは特に注意する必要があります。 ここに水たまりがあります。」

Goはずっと後に作成され、今日では、現在需要のあるものすべてが含まれています。

Source: https://habr.com/ru/post/J306768/


All Articles