为什么不在Racket中为所有人提供序列功能

时间:2016-08-20 03:33:50

标签: scheme racket

使用序列长度,序列参考,序列映射等是否有任何缺点,而不是列表(长度列表-ref等),字符串(字符串长度,字符串-ref等),向量等的不同函数球拍?

1 个答案:

答案 0 :(得分:4)

<强>性能。

考虑这个微小的基准:

#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

是的,这是 3个数量级的差异

为什么呢?好吧,racket/sequence不是一个非常“智能”的API,即使向量是随机访问,sequence-ref也不是。结合Racket优化器大量优化基本操作的能力,序列API是一个相当差的接口。

当然,这有点不公平,因为矢量是随机访问,而列表之类的东西则不是。但是,执行与上面完全相同的测试,但使用列表而不是向量仍会产生相当严峻的结果:

; 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不是一个好的抽象,因为它:

  1. ...在实现中是不必要的有状态,这给接口的实现者带来了不必要的负担。

  2. ...不包含与列表不相似的内容,例如随机访问向量或哈希表。

  3. 如果您想使用更高级别的API,一种可能的选择是使用collections 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
    

    你是否能负担得起的开销取决于你究竟在做什么,而且由你来自己打电话。只要执行某种动态调度,专门操作将始终比推迟它们的操作快一些。一如既往,请记住性能优化规则:不要猜测,测量。

相关问题