5

Go とはまったく関係のないこの興味深いブログ投稿を読みましたが、著者が言ったことの 1 つが私の注意を引きました。次の引用です。

... たとえば、関数 all のパラメーターとしてチャネルを渡すと効率的です。これは、Go のチャネルは C で実装されたチャネル データ構造へのポインタと同じくらい単純であるためです。種類。しかし、配列や構造体を渡すのは効率的ではありません。代わりに、これらの型へのポインターを渡す必要があります。

一部の Go 内部型または構造体を使用するときにポインターを渡すのが非効率なのはなぜですか?

4

2 に答える 2

13

コンテキストはここで関連しています:

ただし、Go の型システムは非常に複雑です。プログラマーは、標準型を正しく使用する前に、標準型の実装に関するすべての詳細を知る必要があります。たとえば、それは効率的です...

作成者は、マップとチャネルは値のように見えますが、コピーされるとポインターのように機能すると言っています。

他のデータ型の場合、パラメーターには が*含まれています。これは、その場で変更できることを明確に示しています。多くの場合、引数の&前にも があります。これは、引数が変更されていることを示す別のシグナルです。

マップとチャネルを渡すとき、それらの構文シグナルは存在しません。これは、次のような予期しない結果につながります。

http://play.golang.org/p/lS1FXZnxb8

[256]byte同様の批判は、 のような配列と のようなスライスの大きな違いにも当てはまります[]byte。ここでは、サイズが存在しないことが、異なるコピー動作の唯一のシグナルです。

これらすべては別として、著者はコピー非効率性を誤って同一視しています。確かに、コピーには、ポインターを渡すよりも多くの CPU サイクルまたはメモリ アクセスが必要になる場合があります。ただし、常にそうであるとは限りません。これは、構造体のサイズとコンパイラーによって実行される最適化によって異なります。

コピーする、つまり値を渡すか、ポインターを渡すかの決定は、引数が関数によって変更される可能性があるかどうかにも関係します。

関数によって変更されることを意図していない小さな構造体と配列の場合は、それらを値で渡します。これにより、偶発的な変更によって引き起こされるバグのクラス全体が排除され、constごまかして回避する方法がないため、他の言語で使用されるよりもさらに優れています。もちろん、マップやスライスを含む埋め込みポインターには常に注意してください。それらは関数内で変更される可能性があるためです。

于 2013-11-04T03:58:42.663 に答える
6

ポインターを渡すことは非効率的ではありません。しかし、著者は正しいです。配列と構造体はデフォルトで値渡しされるため、それらの内容は新しい関数呼び出しごとにコピーされます。これは非効率的です。

Go slices: usage and internalsによると、配列は値渡しされます。(スライスは内部で配列へのポインターを使用するため、より効率的に渡すことができます。)

makeスライスと同様に、チャネルは(少なくとも暗黙的に)によって割り当てられるため、チャネルは実際のデータ構造への参照として機能します

したがって、構造体と実際の配列を操作する場合は、通常、代わりにそれらの参照を渡します。(これに関する詳細については、ショーンの回答を参照してください。彼は、コピーが常に非効率的であるとは限らないことを適切に指摘しています。時にはそれが望ましい場合もあります。)

于 2013-11-04T03:34:37.750 に答える