2017-03-09 3 views
0

異なるゴルーチンに匿名関数によって呼び出される方法https://play.golang.org/p/c_2GECIcrW
私はgetFileNamemain.goのようなものをプリントアウトすることを期待何:11しかし、私は何を取得asm_amd64p32.s:1014runtime.Callerによって実際のファイル名を取得するために、私は、この例のコードを持って

この場合、予期した結果を得るにはどうすればよいですか?
これをアーカイブしても、匿名機能を使用することはできますか?

+0

できません。ごめんなさい。 – Volker

+2

「シフト」で何が欲しいか不明です。 'runtime.Caller(0)'を使うと、新しいgoroutineとして開始された無名関数内のmain.go:17 "'を得ることができます。 – icza

+0

'main.go:11'(getFileNameの呼び出し側)を取得したい – nvcnvn

答えて

0

あなたの期待は間違っています。

私は説明を簡単にするためにここにコードを貼り付けてみましょう:

package main 

import (
    "fmt" 
    "path/filepath" 
    "runtime" 
    "time" 
) 

func main() { 
    getFileName(1) 
    time.Sleep(time.Hour) 
} 

func getFileName(shift int) { 
    go func() { 
     _, file, line, ok := runtime.Caller(shift) 
     if !ok { 
      file = "???" 
      line = 0 
     } else { 
      file = filepath.Base(file) 
     } 

     fmt.Printf("%s:%d", file, line) 
    }() 
} 

あなたの匿名関数がgetFileNameによって生成されたゴルーチンで実行されています。

各ゴルーチンは、getFileNameによって生成されたゴルーチンが新しくスタックから始まっても、独自のコールスタックを使用して実行されます。

スキップ値が0より大きいruntime.Caller(skip int)を呼び出すと、現在のゴルーチンのスタックフレームを歩くことができます。あなたの例では

  • runtime.Caller(0)プリントmain.go:それはあるので、1014:17これはruntime.Caller()が実際に、
  • runtime.Caller(1)プリントasm_amd64p32.sと呼ばれるラインであるため、現在のゴルーチンのスタックの最上部、
  • runtime.Caller(x) x> 1の戻り値はブール値okfalseに設定されています。スタック上部のメモリにアクセスすることができます。

あなたは何asm_amd64p32.s迷っている場合:1014を実際にそれが行く1.8のgoexitアセンブリ関数(ゴー遊び場が行くの最新の安定版リリースで実行)に対応して、表しています。その名前にもかかわらず、goexit関数は常にゴルーチンスタックの最上位にあります。ゴルーチンエントリポイント関数を呼び出し、関数が復帰した後にスタックをクリーンアップします。 goexitの実装はアーキテクチャ固有で、goroutinesスタックの詳細を処理するほとんどのコードであるためです。

戻るあなたの質問に、あなたはmain.go見ることを期待することはできません。主な機能は全くスタックではないので、getFileNameによって生成されたゴルーチンのスタックトレースで述べた11を。 main関数のスタックトレースを実際に印刷する必要がある場合は、goroutineを生成しないでください。

言われておられますが、言及すべきことがあります。 Goランタイムには、実際にゴルーチンが生成された場所に関する追加情報が実際に格納されます。

package main 

import (
    "time" 
    "runtime/debug" 
) 

func main() { 
    getFileName(1) 
    time.Sleep(time.Hour) 
} 

func getFileName(shift int) { 
    go func() { 
     debug.PrintStack() 
    }() 
} 

出力:

goroutine 5 [running]: 
runtime/debug.Stack(0x0, 0x0, 0x0, 0x0) 
    /usr/local/go/src/runtime/debug/stack.go:24 +0x80 
runtime/debug.PrintStack() 
    /usr/local/go/src/runtime/debug/stack.go:16 +0x20 
main.getFileName.func1() 
    /tmp/sandbox085104368/main.go:15 +0x20 
created by main.getFileName 
    /tmp/sandbox085104368/main.go:16 +0x40 

すべてのこれらの詳細は、実装に依存し、被写体までのビーイング(runtime.Stack()に基づいて順番にある)debug.PrintStack()機能はきれいにフォーマットスタックトレースでそれをプリントアウトすることができます異なるGoリリース間で変更すると、標準ライブラリを介して簡単にアクセスすることはできません。これらはデバッグ目的で提供されており、開発者はこれらの情報に頼るべきではありません。

関連する問題