Google が作成した言語である Golang (または Go) の主な利点の 1 つは、競争管理、つまり複数のタスクを同時に実行できることです。
現代の言語には、同時実行性に対処するツールが備わっています。 Go の特徴は、ランタイムがスレッドと並列処理に関する詳細のほとんどを抽象化し、この処理がはるかに単純になることです。オペレーティング システムのスレッドにゴルーチンを割り当てる方法と、スレッドが利用可能な CPU コアとどのように対話するかを定義するのは、オペレーティング システムのカーネルではなくランタイムです。
開発者は Go で同時実行 (インターリーブ実行) と並列処理 (同時実行) を同時に使用でき、プログラム内の同時スレッドの制限である GOMAXPROCS プロパティを決定することで明示的に使用することもできます。したがって、Go は複数のコアにゴルーチンをマッピングして実際の並列処理を実現し、このアーキテクチャを備えたマシンを処理できます。ただし、デフォルトでは、ランタイムがすでにこの抽象化を行っています。
import ( "runtime" ) func main() { runtime.GOMAXPROCS(4) // Permitir até 4 threads para paralelismo }
他のプログラミング言語も並行性と並列性のためのツールを提供していますが、抽象化と単純さのレベルは大きく異なります。たとえば、Java には、同時実行 API (java.util.concurrent) と、同時実行性と並列処理を管理するための Thread、ExecutorService、ForkJoinPool などのツールがあります。
ただし、開発者はスレッド プールを手動で構成するか、CompletableFuture などの特定のツールを使用して非同期操作を簡素化する必要があります。
Java では、スレッド プールを使用してマルチコア マシンでの並列実行も可能です。ただし、対照的に、Java のスレッドはオペレーティング システムのスレッドに直接マップされているため、より重くなります。
オペレーティング システムのスレッドは、システム カーネルによって管理されます。これは、スレッドの作成、破棄、コンテキストの切り替え、および管理がカーネルによって実行されるタスクであることを意味し、追加のオーバーヘッドが発生します。各オペレーティング システム スレッドは、大量のメモリ (通常、Java では約 1 MB) を消費します。システムがスレッド間を切り替えるとき、プロセッサの状態 (レジスタ、スタックなど) を保存および復元する必要がありますが、これは高価なプロセスです。
Go では、この管理を行うのは言語ランタイムです。 Go は、ゴルーチンごとにオペレーティング システム スレッドを作成しません。代わりに、Go ランタイムは、はるかに少ない数のオペレーティング システム スレッドで複数のゴルーチンを管理します。技術的には M:N スケジューリング (N スレッド上の M ゴルーチン) と呼ばれます。これにより
が可能になります
オペレーティング システムに過負荷をかけることなく、同じ数のスレッドを持つ何千もの goroutine を実行できます。
これがこの言語の「利点」であり、高性能の分散システムやリアルタイム データ処理アプリケーションの管理にこの言語が人気を集めています。
ただし、現代の言語はどれも並行性と並列性で動作できることを強調することが重要です。
違いは軽さと加工コストです。
こうすることで、私たちは言語の FlaxFlu にとどまる必要がなくなります。各言語にはそれぞれの魔法、長所と短所があります。
どの言語でもこれらのタスクをどのように実行できるかを示すために、同じプログラムがそれぞれ独自の特徴を持ってコード化される方法を Go と Java で例を挙げて説明します。考え方は単純です。同時実行性と並列性で実行されるタスクをシミュレートし、両方の場合の実行時間とメモリ使用量を出力します (数値はマシンごとに異なります)。
比較をより「免除」するために、chatgpt に以下のコードを生成するように依頼しました。
import ( "runtime" ) func main() { runtime.GOMAXPROCS(4) // Permitir até 4 threads para paralelismo }
実行時間: 141.886206ms
使用メモリ: 43909120 バイト
package main import ( "fmt" "runtime" "sync" "time" ) func tarefa(id int) { // Simula algum processamento leve time.Sleep(10 * time.Millisecond) } func main() { // Configura a quantidade de tarefas numTarefas := 100000 // Medindo o tempo de execução start := time.Now() var wg sync.WaitGroup wg.Add(numTarefas) // Calculando a quantidade de memória usada var m runtime.MemStats runtime.ReadMemStats(&m) initialMemory := m.Sys // Criando as goroutines para simular o trabalho for i := 0; i < numTarefas; i++ { go func(id int) { defer wg.Done() tarefa(id) }(i) } wg.Wait() // Espera todas as goroutines terminarem // Calculando o tempo total de execução e a memória usada elapsed := time.Since(start) runtime.ReadMemStats(&m) finalMemory := m.Sys // Printando os resultados fmt.Printf("Tempo de execução: %s\n", elapsed) fmt.Printf("Memória utilizada: %d bytes\n", finalMemory-initialMemory) }
実行時間: 10238 ミリ秒
使用メモリ: 106732888 バイト
とにかく、両方の言語でまったく同じタスクを実行できることは明らかです。それぞれが適切な目的でライブラリを使用します。 Go では実行が 98.61% 高速になり、使用されるメモリが 58.86% 少なくなったことがわかります。
しかし、他の言語より優れた言語はありません。
必要なのは、プロジェクトで抱えている問題の解決に役立つ言語を選択する際に、それぞれの長所と短所を理解することです。そして、各プロジェクトには、解決する必要がある特定かつ固有の問題が山積しています。
もちろん、Java で上記で提供されたコードのパフォーマンスを向上させる戦略を使用することも可能です。
私は chatgpt に、最初のコードにいくつかのトリックを組み込むよう再度依頼しました。
import ( "runtime" ) func main() { runtime.GOMAXPROCS(4) // Permitir até 4 threads para paralelismo }
メモリ消費を削減するために、より多くのスレッド (100) を備えた ForkJoinPool を使用して、高い同時実行性をより適切に処理します。これにより、デフォルトのスレッド プールが置き換えられ、より多くのタスクを同時に実行できるようになります。また、submit と join を呼び出して、プログラムを終了する前にすべてのタスクが完了していることを確認します。
これらの変更により、メモリ割り当てが 56.21% 削減されました:
実行時間: 11877 ミリ秒
使用メモリ: 46733064 バイト
このコードの最適化は興味深い課題です。 Java を使用してさらに改善することをお勧めします。この言語は、細部にかかわらず素晴らしいものであることはわかっているので、Java は常に可能です。
以上が競争と並列処理: この点で、Golang は Java よりも優れたパフォーマンスを発揮しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。