저는 Goroutine으로 함수를 호출하고 WaitGroup을 사용하여 공유 스캐너가 모두 종료되기 전에 닫는 것을 방지합니다. myfunc()
함수는 파일을 반복 실행합니다. 필자는이 파일을 메모리 맵핑하고 매번 디스크에서 읽는 것의 I/O 문제가 아니라 모든 goroutine 사이에서 공유하려고했습니다. 이 접근 방식이 작동 할 것이라고 나는 들었다. in an answer to another question. 그러나이 기능은 독립적으로 잘 작동했지만 동시에 작동하지는 않습니다. 혼동되는패닉 : 런타임 오류 : goroutine으로 동시에 실행될 때 슬라이스 경계가 범위를 벗어납니다
panic: runtime error: slice bounds out of range
하지만 난 (안 슬라이스에서) Scan()
메서드를 호출 할 때 오류가 있습니다 : 나는 오류가 발생하고있다. 내가 원래 myfunc()
내부를 이동하기 (비효율적으로 그것을마다 재정/재 선언) 문제가 공유 크기지도에 대한 동시 액세스라고 생각하지만,
// ... 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"
}
}
여전히 같은 결과 : 여기
은 MWE입니다 오류는
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() {
이것은 실제로 스캔을 사용하는 적절한 방법이지만, 읽기 전에 시작 루틴을 작성하는 것이 좋습니다. 그렇지 않으면 아무것도 채우지 않아 채널을 채우고 교착 상태가 발생할 수 있습니다. 또한'wg.Done()'은 main에 있으면 안된다. – Verran
바이트 채널 슬라이스 채널을 사용하는'myfunc '에 문제가있는 반면, 라인 채널은 문자열을 가져 오기로 선언 되었습니까? – Dan
@veran 스캐너가 별도의 goroutine에 있기 때문에 교착 상태가되지 않습니다. 그것은 앉아서 소비자가 올 때까지 기다릴 것이다. @Dan, 바이트 슬라이스 및 문자열은 쉽게 변환 가능하지만 alloc이 발생합니다. Scanner.Text()가 반환하는 것이기 때문에 string을 사용했다. – Adrian