Пожалуйста, рассмотрите этот скрипт:
https://play.golang.org/p/o4ZhuB3GJ0s (важная часть ниже)
Он создает случайные (ish) строки, которые выглядят как «foo | foo» (где «foo» - случайный, но повторяется).
Я читаю их с Scanner.Bytes()
во входной канал, затем 16 рабочих потоков преобразуют их в строки и помещают в выходной канал.
В выходном канале я разбил строки на |
, чтобы убедиться, что обе стороны одинаковы (без повреждения данных).
Вот часть кода, которая сканирует входной буфер:
// Send input into channel
go func() {
// Normally os.Stdin
s := bufio.NewScanner(simulatedStdin)
start = time.Now()
for s.Scan() {
thisLine := s.Bytes()
line := make([]byte, len(thisLine))
// Copy the slice so it's not changed on the next iteration
copy(line, thisLine)
lines <- line
// Works, but perhaps the least efficient way to do it
// lines <- []byte(string(s.Bytes()))
// lines <- []byte(s.Text())
// Fails
// lines <- []byte(s.Bytes())
// lines <- s.Bytes()[:]
// lines <- s.Bytes()
}
close(lines)
}()
Версия выше работает правильно, но если я просто сделаю lines <- s.Bytes()
(или другие, которые я протестировал), данные будут повреждены, потому что Scanner.Bytes () всегда возвращает один и тот же слайс, и я пропускаю этот слайс через канал, но он мутирует, пока рабочие его читают.
У меня вопрос: как правильно / идиоматически поставить Scanner.Bytes()
на канал, чтобы предотвратить это повреждение? Способ, который я опубликовал выше, работает, но это довольно уродливо, ИМХО, и взлом строк короток, но это действительно ужасный способ копирования данных.
В конечном счете, я использую этот метод для чтения миллиардов строк данных, поэтому, если можно удалить лишнюю []byte
копию, я полностью за нее. Работа на рабочих выполняется медленно (JSON Unmarshaling и т. Д.), Но сканер ввода представляет собой один поток, поэтому я стараюсь разбить его на строки как можно быстрее.