mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-24 15:28:54 +00:00
26f31ff6ce
Hugo's build process is roughly divided into three steps: 1. Process content (walk file system and insert source nodes into content tree) 2. Assemble content (assemble pages and resources according to sites matrix) 3. Render content In #13679 we consolidated the page creation logic into one place (the assemble step). This made it much simpler to reason about, but it lost us some performance esp. in big content trees. This commit re-introduces parallelization in the first step in the assemble step by handling each top level section in its own goroutine. This gives significant performance improvements for content trees with many sections. Compared to master: ``` AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=6/pagesPerSection=100-10 19.26m ± ∞ ¹ 14.54m ± ∞ ¹ -24.52% (p=0.029 n=4) AssembleDeepSiteWithManySections/depth=2/sectionsPerLevel=2/pagesPerSection=100-10 19.74m ± ∞ ¹ 16.45m ± ∞ ¹ -16.71% (p=0.029 n=4) AssembleDeepSiteWithManySections/depth=2/sectionsPerLevel=6/pagesPerSection=100-10 106.18m ± ∞ ¹ 71.23m ± ∞ ¹ -32.91% (p=0.029 n=4) AssembleDeepSiteWithManySections/depth=3/sectionsPerLevel=2/pagesPerSection=100-10 38.85m ± ∞ ¹ 30.47m ± ∞ ¹ -21.59% (p=0.029 n=4) ```
67 lines
1.4 KiB
Go
67 lines
1.4 KiB
Go
package hiter
|
|
|
|
// Common iterator functions.
|
|
// Some of these are are based on this discsussion: https://github.com/golang/go/issues/61898
|
|
|
|
import "iter"
|
|
|
|
// Concat returns an iterator over the concatenation of the sequences.
|
|
// Any nil sequences are ignored.
|
|
func Concat[V any](seqs ...iter.Seq[V]) iter.Seq[V] {
|
|
return func(yield func(V) bool) {
|
|
for _, seq := range seqs {
|
|
if seq == nil {
|
|
continue
|
|
}
|
|
for e := range seq {
|
|
if !yield(e) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Concat2 returns an iterator over the concatenation of the sequences.
|
|
// Any nil sequences are ignored.
|
|
func Concat2[K, V any](seqs ...iter.Seq2[K, V]) iter.Seq2[K, V] {
|
|
return func(yield func(K, V) bool) {
|
|
for _, seq := range seqs {
|
|
if seq == nil {
|
|
continue
|
|
}
|
|
for k, v := range seq {
|
|
if !yield(k, v) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lock returns an iterator that locks before iterating and unlocks after.
|
|
func Lock[V any](seq iter.Seq[V], lock, unlock func()) iter.Seq[V] {
|
|
return func(yield func(V) bool) {
|
|
lock()
|
|
defer unlock()
|
|
for e := range seq {
|
|
if !yield(e) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lock2 returns an iterator that locks before iterating and unlocks after.
|
|
func Lock2[K, V any](seq iter.Seq2[K, V], lock, unlock func()) iter.Seq2[K, V] {
|
|
return func(yield func(K, V) bool) {
|
|
lock()
|
|
defer unlock()
|
|
for k, v := range seq {
|
|
if !yield(k, v) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|