10

私は数日前に Go の勉強を始め、その CGO と gccgo コンパイラーにたどり着きました。私の理解では、これにより、Go プログラムは Go コンパイラを使用してコンパイルし、C コンパイラを使用して C ライブラリをコンパイルし、Go プログラム内からそれらのライブラリを参照できます。これにより、(必要に応じて) C のパフォーマンスをメイン プログラムからほとんどオーバーヘッドなしで活用できるようになるため、これは私にとって非常に興味深いことです。

しかし、それがどれほど少ないか分からないので、ここで質問しています:

Go アプリケーション内から使用するためだけに C ライブラリを作成する場合はありますか? それとも、この機能は既存の C コードの再利用を容易にするためだけのものですか?

PS: 現時点では CGO は C++ をサポートしていないと思いますが、C 関数を使用して C++ コードをラップし、それらを正常に呼び出すことができた人の投稿がここにありました。

4

2 に答える 2

13

Cgo はかなり遅いです。なぜなら、Go はC 関数を呼び出すために特定の方法でランタイムと呼び出し規則をいじる必要があるからです。それが本当に価値がある唯一の場所は、計算時間がこのコストを大幅に小さくする場合です。並列、分散、GPU などのプログラミングに似ていますが、起動コストはわずかに低くなります。

Go の呼び出し規則を使用するアセンブリを記述でき、それ以外の場合はネイティブの Go コードのように扱われるため、アセンブリの方がはるかに優れていますが、アセンブリは移植性がはるかに低く、読み取りが難しく、メンテナンスがより重くなります。実際、Go 標準ライブラリはPlan 9 スタイルのアセンブリでmathおよびパッケージの一部を記述しています。big

Gonumは、これらの両方の例です。より迅速に実行できる一部の機能には共通のアセンブリを使用しますが、blas および lapack エンジンも活用します。それはGo-blas実装を提供しますが、C-blas (通常は最終的には Fortran-blas) の方が高速であり、大規模な行列計算の場合、ほとんどの場合、Go を離れるコストが小さくなります。

一般的に、cgo は可能な限り避けたいものです。かなりの計算時間が必要な場合、またはグラフィックスやオーディオ ドライバーなど、純粋な Go で対話するのが自明ではないものと対話する必要がある場合、または OpenCV などの一般的なライブラリにアクセスする必要がある場合にのみ使用してください。それでも、パフォーマンスが本当に気になる場合は、可能であれば、Go 側から複数の呼び出しをスケジュールし、C への単一のコンテキスト スイッチでそれらをすべて一度に実行できる、何らかの「呼び出しプーリング」を実装する価値があるかもしれません。

編集: C++ に関しては、いくつかの重要な問題があります。いくつかの抽象化層なしで特定のライブラリをラップするのは難しい場合があります (cgo は含まれている C++ ヘッダーを適切に処理できないため)。さらに、デストラクタを持つ C++ クラスは実際には値で返すことができず、ヒープに割り当てる必要があります。Go ではリソースの決定論的なファイナライズが許可されていないため、メモリを明示的に解放する関数を提供する必要があり、Go ユーザーはリソースを解放することを覚えておく必要があります。(と呼ばれるドキュメントで読むことができる関数がありますが、runtime.SetFinalizer誰かがそれを使用しているのを見たことがないとは言えません。ドキュメント自体には多くの注意事項があります)

のような機能deferはこれをより管理しやすくしますが、最新の C++ プラクティスをより安全にする RAII のような多くのものを台無しにします。

于 2016-06-22T07:37:16.437 に答える
1

C ライブラリが 1 回の呼び出しで多くの作業を行う場合を除いて、パフォーマンスのためだけに C コードを書くことはありません。私は、cgo は古いコードとのインターフェースのためだけのものだと考えています。

その理由は cgo のオーバーヘッドです。現在、cgo 関数への関数呼び出しは、Go コードへの関数呼び出しよりも 50 倍から 100 倍遅くなります。cgo 関数呼び出しのオーバーヘッドは衝撃的です。

于 2016-06-22T07:32:48.903 に答える