代码之家  ›  专栏  ›  技术社区  ›  Joseph Garvin

为什么Racket中gvector中的保留容量会使性能变差?

  •  3
  • Joseph Garvin  · 技术社区  · 8 年前

    在Racket 6.6中使用以下简单基准:

    #lang racket
    (require data/gvector)
    (define (run)
      ;; this should have to periodically resize in order to incorporate new data
      ;; and thus should be slower
      (time (define v (make-gvector)) (for ((i (range 1000000))) (gvector-add! v i)) )
      (collect-garbage 'major)
      ;; this should never have to resize and thus should be faster
      ;; ... but consistently benchmarks slower?!
      (time (define v (make-gvector #:capacity 1000000)) (for ((i (range 1000000))) (gvector-add! v i)) )
      )
    
    (run)
    

    适当保留容量的版本 为什么?这肯定不是我预期的结果,并且与您在C++(std::vector)或Java(ArrayList)中看到的结果不一致。我的基准测试是否有误?

    示例输出:

    cpu time: 232 real time: 230 gc time: 104
    cpu time: 228 real time: 230 gc time: 120
    
    2 回复  |  直到 8 年前
        1
  •  3
  •   Ryan Culpepper    8 年前

    一个基准评注:使用 in-range 而不是 range 在您的微基准中;否则,您将在度量中包含构建百万元素列表的成本。

    我在你的微基准测试中添加了一些额外的循环,以使它做更多的工作(并且我修复了 范围 问题)。以下是一些结果:

    使用 #:capacity 对于 大容量 速度较慢。

    == 5 iterations of 1e7 sized gvector, measured 3 times each way
    with #:capacity
    cpu time: 9174 real time: 9169 gc time: 4769
    cpu time: 9109 real time: 9108 gc time: 4683
    cpu time: 9094 real time: 9091 gc time: 4670
    without
    cpu time: 7917 real time: 7912 gc time: 3243
    cpu time: 7703 real time: 7697 gc time: 3107
    cpu time: 7732 real time: 7727 gc time: 3115
    

    使用 #:容量 对于 小容量 更快。

    == 20 iterations of 1e6 sized gvector, measured three times each way
    with #:capacity
    cpu time: 2167 real time: 2168 gc time: 408
    cpu time: 2152 real time: 2152 gc time: 385
    cpu time: 2112 real time: 2111 gc time: 373
    without
    cpu time: 2310 real time: 2308 gc time: 473
    cpu time: 2316 real time: 2315 gc time: 480
    cpu time: 2335 real time: 2334 gc time: 488
    

    我的假设是:这是GC开销。当支持向量发生变异时,Racket的分代GC会记住该向量,以便在下一个次要集合中扫描它。当支持向量非常大时,在每个次要GC上扫描整个向量会超过重新分配和复制的成本。如果GC具有更好的记忆集粒度(但……权衡),则不会产生开销。

    顺便说一句,通过查看gvector代码,我发现了一些改进的机会。不过,它们并没有改变大局。

        2
  •  1
  •   soegaard    8 年前

    用因子10增加向量大小,我在DrRacket中得到以下结果 (关闭所有调试):

    cpu time: 5245 real time: 5605 gc time: 3607
    cpu time: 4851 real time: 5136 gc time: 3231
    

    注意:如果第一个基准测试留下了垃圾,它可能会影响下一个基准测试。因此,在再次使用之前,使用收集垃圾(三次)。

    另外…不要像我一样在DrRacket中进行基准测试-使用命令行。