私はgoroutineとして関数を呼び出し、WaitGroupを使用して共用スキャナがすべて終了する前に閉じないようにします。 myfunc()
関数はファイルに対して反復処理を行います。私は、このファイルをメモリマップでマップし、毎回ディスクから読み込むというI/Oチョークポイントを持つのではなく、すべてのゴルーチン間で共有したかったのです。私はこのアプローチがうまくいくと言われましたin an answer to another question.しかし、この機能はスタンドアロンで機能していましたが、同時に動作していませんでした。混乱しているpanic:ランタイムエラー:同時にゴルーチンとして実行するとスライス境界が範囲外になる
panic: runtime error: slice bounds out of range
が、私は(ないスライス上)Scan()
メソッドを呼び出したときにエラーがある:私は、エラーが発生します。ここで
MWEです:
// ... package declaration; imports; yada yada
// the actual Sizes map is much more meaningful, this is just for the MWE
var Sizes = map[int]string {
10: "Ten",
20: "Twenty",
30: "Thirty",
40: "Forty",
}
type FileScanner struct {
io.Closer
*bufio.Scanner
}
func main() {
// ... validate path to file stored in filePath variable
filePath := "/path/to/file.txt"
// get word list scanner to be shared between goroutines
scanner := getScannerPtr(&filePath)
// call myfunc() for each param passed
var wg sync.WaitGroup
ch := make(chan string)
for _, param := range os.Args[1:] {
wg.Add(1)
go myfunc(¶m, scanner, ch)
wg.Done()
}
// print results received from channel
for range os.Args[1:] {
fmt.Println(<-ch) // print data received from channel ch
}
// don't close scanner until all goroutines are finished
wg.Wait()
defer scanner.Close()
}
func getScannerPtr(filePath *string) *FileScanner {
f, err := os.Open(*filePath)
if err != nil {
fmt.Fprint(os.Stderr, "Error opening file\n")
panic(err)
}
scanner := bufio.NewScanner(f)
return &FileScanner{f, scanner}
}
func myfunc(param *string, scanner *FileScanner, ch chan<-string) {
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
// ... do something with line (read only)
// ... access shared Sizes map when doing it (read only)
ch <- "some string result goes here"
}
}
私はもともと問題が共有サイズのマップへの同時アクセスだと思ったが、myfunc()
内側に移動する(そして非効率的にそれを毎回再定義/再宣言は)まだ同じになりましたエラーは、Scan()
を呼び出すことと関連しています。私はここでパニックの完全なスタックトレースだ、私はin this answer.
を受けた指導に従うことをしようとしています:
panic: runtime error: slice bounds out of range
goroutine 6 [running]:
bufio.(*Scanner).Scan(0xc42008a000, 0x80)
/usr/local/go/src/bufio/scan.go:139 +0xb3e
main.crack(0xc42004c280, 0xc42000a080, 0xc42001c0c0)
/Users/dan/go/src/crypto_ctf_challenge/main.go:113 +0x288
created by main.main
/Users/dan/go/src/crypto_ctf_challenge/main.go:81 +0x1d8
exit status 2
ライン81は、次のとおりです。
go myfunc(¶m, scanner, ch)
ライン113は、次のとおりです。
for scanner.Scan() {
これは確かにスキャンを使用する適切な方法ですが、読み込みを開始する前にgoルーチンを作成することをお勧めします。そうしないと、チャネルをいっぱいにしてデッドロックが発生することがあります。また、 'wg.Done()'はメインにあるべきではありません。 – Verran
バイトチャネルのスライスを扱う 'myfunc'に問題はありますか?linesチャネルは文字列を受け取ると宣言されましたか? – Dan
@veranスキャナが別のゴルーチンにあるため、デッドロックしません。それは座り、消費者が現れるまで待つ。 @Dan、バイトスライスと文字列は簡単に変換可能ですが、それはallocを引き起こします。 'Scanner.Text()'が返すものなので、私は文字列を使いました。 – Adrian