ПОСЛЕДНЕЕ РЕДАКТИРОВАНИЕ
Это «построчное» решение проблемы, которое занимает тривиальное время, печатает всю соответствующую строку.
package main
import (
"bytes"
"fmt"
"io/ioutil"
)
func main() {
dat, _ := ioutil.ReadFile("./jumble.txt")
i := bytes.Index(dat, []byte("Iforgotmypassword"))
if i != -1 {
var x int
var y int
for x = i; x > 0; x-- {
if dat[x] == byte('\n') {
break
}
}
for y = i; y < len(dat); y++ {
if dat[y] == byte('\n') {
break
}
}
fmt.Println(string(dat[x : y+1]))
}
}
real 0m0.421s
user 0m0.068s
sys 0m0.352s
ОРИГИНАЛЬНЫЙ ОТВЕТ
Если вам просто нужно посмотреть, есть ли строка в файле, почему бы не использовать регулярное выражение?
Примечание: Iсохранял данные в виде байтового массива вместо преобразования в строку.
package main
import (
"fmt"
"io/ioutil"
"regexp"
)
var regex = regexp.MustCompile(`Ilostmypassword`)
func main() {
dat, _ := ioutil.ReadFile("./jumble.txt")
if regex.Match(dat) {
fmt.Println("Yes")
}
}
jumble.txt
- это 859 МБ перемешанного текста с включенными символами новой строки.
Запуск с time ./code
Я получаю:
real 0m0.405s
user 0m0.064s
sys 0m0.340s
Кпопробуйте ответить на ваш комментарий, я не думаю, что узкое место возникает в результате поиска построчно, Голанг использует эффективный алгоритм поиска строк / рун.
Я думаю, что узкое место возникает при чтениях ввода-вывода, когдапрограмма читает из файла, она обычно не первая в очереди в очереди чтения, поэтому программа должна ждать, пока она не сможет выполнить чтение, чтобы начать фактическое сравнение.Таким образом, когда вы читаете снова и снова, вы вынуждены ждать своей очереди в IO.
Чтобы дать вам некоторую математику, если ваш размер буфера равен 64 * 1024 (или 65535 байт), иВаш файл 1 ГБ.Разделение 1 ГБ / 65535 байт составляет 15249 операций чтения, необходимых для проверки всего файла.Где, как и в моем методе, я читаю весь файл "сразу" и проверяю этот построенный массив.
Еще одна вещь, о которой я могу подумать, это просто огромное количество циклов, необходимых для перемещения по файлу, и время, необходимое для каждого цикла:
Учитывая следующий код:
dat, _ := ioutil.ReadFile("./jumble.txt")
sdat := bytes.Split(dat, []byte{'\n'})
for _, l := range sdat {
if bytes.Equal([]byte("Iforgotmypassword"), l) {
fmt.Println("Yes")
}
}
Я рассчитал, что каждый цикл занимает в среднем 32 наносекунды, строка Iforgotmypassword была в строке 100000000 в моем файле, таким образом, время выполнения этого цикла составляло примерно 32 наносекунды * 100000000 ~ = 3,2 секунды.