WaitGroups リファレンスのポインターまたは変数
同期パッケージ内では、WaitGroups の Add、Done、および Wait 関数はすべて、 WaitGroup へのポインタ。ただし、次のコードはこの規則に矛盾しているようです。
package main import ( "fmt" "sync" "time" ) func worker(id int, wg *sync.WaitGroup) { defer wg.Done() fmt.Printf("Worker %d starting\n", id) time.Sleep(time.Second) fmt.Printf("Worker %d done\n", id) } func main() { var wg sync.WaitGroup for i := 1; i <= 5; i++ { wg.Add(1) go worker(i, &wg) } wg.Wait() }
このコードでは、Done はポインター変数を使用して呼び出されますが、Add と Wait は (ポインターではなく) 変数を使用して呼び出されます。
説明:
変数宣言 var wg sync.WaitGroup にもかかわらず、 Add、Done、および Wait 関数には、ポインター レシーバー (*WaitGroup) を介してアクセスします。 wg の値は、Go コンパイラーによって暗黙的にポインターに変換されます。これが必要なのは、次の関数宣言に見られるように、メソッドがポインター レシーバーとして定義されているためです。
Add -------> func (wg *WaitGroup) Add(delta int) Done ------> func (wg *WaitGroup) Done() Wait ------> func (wg *WaitGroup) Wait()
ポインター以外の値をポインター レシーバー メソッドに渡すと、コンパイラーは自動的にそのアドレス (ポインター値に)。したがって、wg が変数として宣言されている場合でも、3 つの関数はすべて wg へのポインターで呼び出されます。
ポインター レシーバーを使用する主な理由は、データの不必要なコピーを避けることです。ポインターを渡すことにより、関数は基になる WaitGroup のコピーを作成するのではなく、直接変更できます。これにより、特に頻繁に変更される WaitGroups のパフォーマンスが向上します。
提供されたコードでは、wg のアドレスをワーカーに渡すことが重要です。これは、wg が値として (& なしで) 渡された場合、Done 関数が各ワーカーは、メイン関数の Add および Wait とは異なるポインターを参照します。これにより、誤った動作が発生します。
以上がWaitGroup の Add、Done、および Wait 関数は、変数として宣言されている場合でもポインターを使用して呼び出されるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。