맵 단계
각 토큰의 위치 정보를 나타내는 partial 타입을 다음과 같이 정의한다.
import "text/scanner" type partial struct { token string scanner.Position }
text/scanner 패키지가 제공하는 타입인 scanner.Position은 토큰의 위치 정보를 담고 있다.
Note scanner.Position 타입
// http://golang.org/pkg/text/scanner/#Position type Position struct { Filename string // 파일명 Offset int // 오프셋(byte 단위, 0부터 시작) Line int // 줄 번호(1부터 시작) Column int // 칼럼 번호(1부터 시작) }
mapper() 함수는 각 파일의 토큰과 토큰의 위치 정보를 추출하여 out 채널로 전달한다.
func mapper(path string, out chan<- partial) { file, err := os.Open(path) if err != nil { return } defer file.Close() // 정상적인 파일이 아닌 경우 바로 반환 if info, err := file.Stat(); err != nil || info.Mode().IsDir() { return } var s scanner.Scanner s.Filename = path s.Init(file) // 파일의 모든 토큰을 스캔하여 out 채널로 전송 tok := s.Scan() for tok != scanner.EOF { fmt.Println(s.Pos()) out <- partial{s.TokenText(), s.Pos()} tok = s.Scan() } }
다음은 매퍼(mapper)를 실행하는 함수이다.
func runMap(paths <-chan string) <-chan partial { out := make(chan partial, BUF_SIZE) go func() { for path := range paths { mapper(path, out) } close(out) }() return out }
파일 목록은 paths 채널을 통해 runMap() 함수 내부로 전달된다. 각 path에 mapper()를 실행하는 작업은 고루틴으로 동작한다. 이때 CPU의 코어 수만큼 여러 개의 고루틴을 만들어 동시에 동작하게 했다. mapper() 함수로 추출된 토큰 정보는 out 채널을 통해 외부로 전달된다.
전체 코드는 map.go를 참고하기 바란다.