在球拍中使用序列长度、序列引用、序列映射等,而不是对列表(长度列表-引用等)、字符串(字符串长度、字符串-引用等)、向量等使用不同的函数,有什么缺点吗?
发布于 2016-08-19 20:06:06
性能.
考虑一下这个小小的基准:
#lang racket/base
(require racket/sequence)
(define len 10000)
(define vec (make-vector len))
(collect-garbage)
(collect-garbage)
(collect-garbage)
(time (void (for/list ([i (in-range len)])
(vector-ref vec i))))
(collect-garbage)
(collect-garbage)
(collect-garbage)
(time (void (for/list ([i (in-range len)])
(sequence-ref vec i))))
这是我机器上的输出:
; vectors (vector-ref vs sequence-ref)
cpu time: 1 real time: 1 gc time: 0
cpu time: 2082 real time: 2081 gc time: 0
是的,相差三个数量级。
为什么?嗯,racket/sequence
并不是一个非常“聪明”的API,即使向量是随机访问,sequence-ref
也不是。结合Racket优化器对原始操作进行严重优化的能力,sequence是一个非常糟糕的接口。
当然,这有点不公平,因为向量是随机访问的,而像列表这样的东西则不是。然而,执行与上面的测试完全相同的测试,但使用列表而不是向量仍然会产生相当可怕的结果:
; lists (list-ref vs sequence-ref)
cpu time: 113 real time: 113 gc time: 0
cpu time: 1733 real time: 1732 gc time: 0
序列API是缓慢的,主要是由于高度的间接。
现在,性能本身并不是直接拒绝API的理由,因为在更高层次的抽象中工作有具体的优势。尽管如此,我认为序列API不是一个很好的抽象,因为它:
如果您想使用更高级别的API,一种可能的选择是使用 package,它尝试提供类似于racket/sequence
的API,但可以容纳更多类型的数据结构,并且具有更完整的功能集。免责声明:我是collections
软件包的作者。
考虑到上面的基准,性能仍然比直接使用底层函数差,但至少更易于管理:
; vectors (vector-ref vs ref)
cpu time: 2 real time: 1 gc time: 0
cpu time: 97 real time: 98 gc time: 10
; lists (list-ref vs ref)
cpu time: 104 real time: 103 gc time: 0
cpu time: 481 real time: 482 gc time: 0
你是否负担得起费用取决于你到底在做什么,这取决于你自己打电话。只要执行某种动态调度,专门操作总是比服从它们的操作要快一些。和往常一样,记住性能优化的规则:不要猜测,度量。
https://stackoverflow.com/questions/39050201
复制相似问题