ソースを参照

perf(readingtime): don't allocate words to count them

The function strings.Fields will allocate every single word it's creating,
meaning that for a text of 10k words, 10k allocations will be made, only for
them to be counted an discarded. We can do much better by counting the words
ourself via a small countWords helper function, and write a test to prove that
it doesn't allocate anything.
jvoisin 2 週間 前
コミット
6b06c9f4f4

+ 9 - 1
internal/reader/readingtime/readingtime.go

@@ -21,7 +21,15 @@ func EstimateReadingTime(content string, defaultReadingSpeed, cjkReadingSpeed in
 	if isCJK(sanitizedContent[:truncationPoint]) {
 		return int(math.Ceil(float64(utf8.RuneCountInString(sanitizedContent)) / float64(cjkReadingSpeed)))
 	}
-	return int(math.Ceil(float64(len(strings.Fields(sanitizedContent))) / float64(defaultReadingSpeed)))
+	return int(math.Ceil(float64(countWords(sanitizedContent)) / float64(defaultReadingSpeed)))
+}
+
+func countWords(s string) int {
+	n := 0
+	for range strings.FieldsSeq(s) {
+		n++
+	}
+	return n
 }
 
 func isCJK(text string) bool {

+ 11 - 0
internal/reader/readingtime/readingtime_test.go

@@ -86,3 +86,14 @@ func BenchmarkEstimateReadingTime(b *testing.B) {
 		}
 	}
 }
+
+func TestCountWordsZeroAllocs(t *testing.T) {
+	allocs := testing.AllocsPerRun(10, func() {
+		for _, sample := range samples {
+			countWords(sample)
+		}
+	})
+	if allocs != 0 {
+		t.Errorf("countWords allocated %v times, expected 0", allocs)
+	}
+}