diff --git a/bench/vector-filter.scm b/bench/vector-filter.scm new file mode 100644 index 00000000..b530a63b --- /dev/null +++ b/bench/vector-filter.scm @@ -0,0 +1,67 @@ +;; vector-filter 性能基准测试 +;; 测试当前实现的性能,为后续优化提供基准数据 + +(import (liii timeit) + (liii vector) + (scheme base) +) + +;; 运行单次 benchmark +(define (bench name stmt number) + (let ((elapsed (timeit stmt '() number))) + (display name) + (display ": ") + (display elapsed) + (display " 秒 (") + (display number) + (display " 次)\n") + ) +) + +;; 性能测试 +(define (run-benchmarks) + (display "=== vector-filter 性能测试 ===\n\n") + + ;; 空向量 + (let ((empty #( ))) + (bench "空向量 " + (lambda () (vector-filter (lambda (x) #t) empty)) + 100000) + ) + + ;; 小向量 (10 元素),全部匹配 + (let ((small #(1 2 3 4 5 6 7 8 9 10))) + (bench "小向量(10)全匹配" + (lambda () (vector-filter (lambda (x) #t) small)) + 100000) + ) + + ;; 小向量 (10 元素),匹配一半 + (let ((small #(1 2 3 4 5 6 7 8 9 10))) + (bench "小向量(10)半匹配" + (lambda () (vector-filter even? small)) + 100000) + ) + + ;; 中向量 (100 元素),匹配一半 + (let ((medium (list->vector (iota 100)))) + (bench "中向量(100)半匹配" + (lambda () (vector-filter even? medium)) + 100000) + ) + + ;; 大向量 (1000 元素),匹配一半 + (let ((large (list->vector (iota 1000)))) + (bench "大向量(1000)半匹配" + (lambda () (vector-filter even? large)) + 10000) + ) + + ;; 超大向量 (10000 元素),匹配一半 + (let ((xlarge (list->vector (iota 10000)))) + (bench "超大向量(10000) " + (lambda () (vector-filter even? xlarge)) + 1000)) + ) + +(run-benchmarks) diff --git a/devel/0025.md b/devel/0025.md new file mode 100644 index 00000000..8b61288e --- /dev/null +++ b/devel/0025.md @@ -0,0 +1,70 @@ +# [0025] 优化 vector-filter 性能(perf/033) + +## 任务相关的代码文件 +- `goldfish/liii/vector.scm` +- `bench/vector-filter.scm` +- `tests/liii/vector/vector-filter-test.scm` + +## 如何测试 +```bash +# 1. 构建 +xmake b goldfish + +# 2. 运行功能测试 +bin/gf tests/liii/vector/vector-filter-test.scm + +# 3. 运行性能基准测试 +bin/gf bench/vector-filter.scm +``` + +## 2026-05-11 优化 vector-filter 性能 + +### What +1. 新增 `bench/vector-filter.scm` 性能基准测试,覆盖空向量、小向量(10 元素)、中向量(100 元素)、大向量(1000 元素)、超大向量(10000 元素)等场景。 +2. 优化 `vector-filter` 实现,将 `vector-fold` + `length` + 反向 `vector-set!` 替换为 `vector-fold-right` + `list->vector`。 +3. 功能测试全部通过(5 correct, 0 failed)。 + +### Why +原始实现存在以下性能问题: +- `vector-fold` 从左到右遍历,`cons` 累积产生倒序列表 +- 需要额外调用 `length` 计算结果长度 +- 最后通过 Scheme 层循环从末尾反向 `vector-set!` 填充结果向量 + +新实现利用 `vector-fold-right` 从右到左遍历,`cons` 自然产生正序列表,再经 C 层 `list->vector` 一次性转换,消除了 `length` 遍历和反向填充循环。 + +### How + +**优化前实现:** +```scheme +(define (vector-filter pred vec) + (let* ((result-list (vector-fold (lambda (elem acc) + (if (pred elem) (cons elem acc) acc)) + '() vec)) + (result-length (length result-list)) + (result-vec (make-vector result-length))) + (let loop ((i (- result-length 1)) (lst result-list)) + (if (null? lst) + result-vec + (begin + (vector-set! result-vec i (car lst)) + (loop (- i 1) (cdr lst))))))) +``` + +**优化后实现:** +```scheme +(define (vector-filter pred vec) + (list->vector (vector-fold-right (lambda (elem acc) + (if (pred elem) (cons elem acc) acc)) + '() vec))) +``` + +**性能对比:** + +| 测试场景 | 优化前 | 优化后 | 提升 | +|---|---|---|---| +| 空向量 (10万次) | 0.0345s | 0.0228s | 34% | +| 小向量(10)全匹配 (10万次) | 0.1755s | 0.1206s | 31% | +| 小向量(10)半匹配 (10万次) | 0.1465s | 0.1096s | 25% | +| 中向量(100)半匹配 (10万次) | 1.1292s | 0.9248s | 18% | +| 大向量(1000)半匹配 (1万次) | 1.1055s | 0.8814s | 20% | +| 超大向量(10000) (1千次) | 1.2926s | 0.9898s | 23% | diff --git a/goldfish/liii/vector.scm b/goldfish/liii/vector.scm index abddb7f8..1c7ff1b8 100644 --- a/goldfish/liii/vector.scm +++ b/goldfish/liii/vector.scm @@ -42,23 +42,7 @@ (begin (define (vector-filter pred vec) - (let* ((result-list (vector-fold (lambda (elem acc) (if (pred elem) (cons elem acc) acc)) '() vec) - ) ;result-list - (result-length (length result-list)) - (result-vec (make-vector result-length)) - ) ; - (let loop - ((i (- result-length 1)) (lst result-list)) - (if (null? lst) - result-vec - (begin - (vector-set! result-vec i (car lst)) - (loop (- i 1) (cdr lst)) - ) ;begin - ) ;if - ) ;let - ) ;let* - ) ;define + (list->vector (vector-fold-right (lambda (elem acc) (if (pred elem) (cons elem acc) acc)) '() vec))) (define (vector-contains? vec elem . args) (let ((cmp (if (null? args) equal? (car args))))