for / list vs自定义/ Racket中的/ bytes

时间:2014-02-15 21:31:05

标签: racket list-comprehension for-comprehension

我正在玩Racket而错过了字节串理解。当我在文档中找到for/fold/derived示例时,我决定使用自己的字节串理解宏,就像任何初学者一样:

(define-syntax (for/bytes stx)
    (syntax-case stx ()
      ((_ clauses . defs+exprs)
       (with-syntax ((original stx))
         #'(let-values
             (((bstr i max-length)
               (for/fold/derived original ((bstr (make-bytes 16)) (c 0) (ln-incr 32)) clauses
                 (define el (let () . defs+exprs))
                 (let-values (((new-bstr new-ln-incr)
                           (if (eq? c (bytes-length bstr))
                       (values (bytes-append bstr (make-bytes ln-incr)) (* ln-incr 2))
                       (values bstr ln-incr))))
                   (bytes-set! new-bstr c el)
               (values new-bstr (+ c 1) new-ln-incr)))))
     (subbytes bstr 0 i))))))    

我有一些相关的问题:

  1. 无论如何这是Racket方式吗?
  2. 宏可以吗?基本上我将for/fold/derived文档中的示例与宏观扩展的for/vector
  3. 结合起来
  4. 是否有明显的性能优化?
  5. 可悲的是,它并不比(list->bytes (for/list ...微观基准测试快得多:

    (define size 50000)
    (define (custom-byte-test) (for/bytes ((i (in-range size))) (modulo i 256)))
    (define (standard-list-test) (list->bytes (for/list ((i (in-range size))) (modulo i 256))))
    (profile-thunk custom-byte-test #:repeat 1000)
    (profile-thunk standard-list-test #:repeat 1000)
    

    给出3212ms对比3690ms。对于小于50000的尺寸,我的for/bytes会损失,因为尺寸大于它赢得的尺寸。

2 个答案:

答案 0 :(得分:2)

我的回答:

  

无论如何这是Racket方式吗?

  

宏可以吗?基本上我将for / fold / derived文档中的示例与/ vector

的宏展开相结合

是的,我觉得它看起来不错。

  

是否有明显的性能优化?可悲的是,它并不比(list->bytes (for/list ...

我不知道怎么做得更快。这里的“胜利”是缓冲区大小调整的复杂性对for/bytes的用户隐藏。

答案 1 :(得分:2)

我把你的代码加了一点。

1)由于您已经知道当前长度,因此不需要内循环中的bytes-length计算。我将ln-incr替换为bstr-len,代表当前长度和数量,以增加长度。

这提高了约15%。

2)由于你已经进行了长度检查,你可以安全地使用unsafe-bytes-set!,这可以加快另外10%的速度。

在我的机器上,custom-byte-test现在约为1200毫秒vs {17}毫米{。}}。

standard-list-test