Сценарий: Я хочу быстро прочитать большой текстовый файл (например, lorem.txt
с 4,5 миллионными строками в примере ниже).Я попробовал три различных способа в приведенном ниже коде.
- Одновременная последовательная обработка
- Каналы и goroutines
- Waitgroup и goroutines
Псевдо-тесты: Вот типичный вывод, который я получаю, когда запускаю это ниже;ниже приводятся быстрые и грязные дельты времени, а не полноценное профилирование / стендовая разметка / тестирование.
sequential: 43.541828091 secs 4714074 lines
queued channel: 80.986544385 secs 4714074 lines
wait group: 260.200473751 secs 4712266 lines
Вопрос: Почему последовательные циклы быстрее, чем два других метода ниже?Я что-то упустил?
Обновление Я запустил пример кода для намного большего текстового файла (см. Сценарий ).Я также «сбрасываю» регистратор для каждого примера, на случай, если это не будет сделано, возникнет некоторая проблема с памятью между примерами функций.Также, как отмечали другие, мой компьютер является двухъядерным, что может быть одной из многих проблем с моим кодом.Спасибо за все отзывы / ответы.
package main
import (
"bufio"
"bytes"
"fmt"
"log"
"os"
"sync"
"time"
)
var (
textFile = "lorem.txt"
buf bytes.Buffer
l = log.New(&buf, "logger: ", log.Lshortfile)
wg sync.WaitGroup
delta1 float64
delta2 float64
delta3 float64
cnt1 = 0
cnt2 = 0
cnt3 = 0
)
func main() {
// Wait Group Example
exampleWaitGroup()
// Queued Channel Example
exampleQueuedChannel()
// Sequential Loop Example
exampleSequentialLoop()
benchmarks := fmt.Sprintf("sequential:\t%v secs %v lines\nqueued channel:\t%v secs %v lines\nwait group:\t%v secs %v lines\n",
delta1, cnt1,
delta2, cnt2,
delta3, cnt3,
)
fmt.Println(benchmarks)
}
func exampleSequentialLoop() {
buf.Reset()
l = log.New(&buf, "logger: ", log.Lshortfile)
start := time.Now()
file1, err := os.Open(textFile)
if err != nil {
log.Fatal(err)
}
defer file1.Close()
scanner := bufio.NewScanner(file1)
for scanner.Scan() {
cnt1++
l.Println(scanner.Text())
}
end := time.Now()
delta1 = end.Sub(start).Seconds()
}
func exampleQueuedChannel() {
buf.Reset()
l = log.New(&buf, "logger: ", log.Lshortfile)
start := time.Now()
queue := make(chan string)
done := make(chan bool)
go processQueue(queue, done)
file2, err := os.Open(textFile)
if err != nil {
log.Fatal(err)
}
defer file2.Close()
scanner := bufio.NewScanner(file2)
for scanner.Scan() {
queue <- scanner.Text()
}
end := time.Now()
delta2 = end.Sub(start).Seconds()
}
func exampleWaitGroup() {
buf.Reset()
l = log.New(&buf, "logger: ", log.Lshortfile)
start := time.Now()
file3, err := os.Open(textFile)
if err != nil {
log.Fatal(err)
}
defer file3.Close()
scanner := bufio.NewScanner(file3)
for scanner.Scan() {
wg.Add(1)
go func(line string) {
defer wg.Done()
l.Println(line)
cnt3++
}(scanner.Text())
}
wg.Wait()
end := time.Now()
delta3 = end.Sub(start).Seconds()
}
func processQueue(queue chan string, done chan bool) {
for line := range queue {
l.Println(line)
cnt2++
}
done <- true
}