2

我在玩球拍,错过了一个字节串理解。当我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. 无论如何,这是球拍方式吗?
  2. 宏好吗?基本上,我将for/fold/derived文档中的示例与宏扩展相结合for/vector
  3. 有没有明显的性能优化?

可悲的是,它并没有真正比(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)

给出 3212 毫秒与 3690 毫秒。对于远小于 50000 的尺寸,我for/bytes会输,对于大于 50000 的尺寸,我会赢。

4

2 回答 2

2

我的回答:

无论如何,这是球拍方式吗?

是的。

宏好吗?基本上,我将 for/fold/derived 文档中的示例与宏扩展 for/vector 结合在一起

是的,我认为它看起来不错。

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

我不知道如何更快地做到这一点。这里的“胜利”是缓冲区调整大小的复杂性对for/bytes.

于 2014-02-16T01:38:26.117 回答
2

我加快了你的代码速度。

1)bytes-length不需要内部循环中的计算,因为您已经知道当前长度。我ln-incr用一个bstr-len代表当前长度和增加长度的数量替换了你的。

这带来了约 15% 的改进。

2)由于您已经进行了长度检查,因此您可以安全地使用unsafe-bytes-set!,这可以将速度再提高约 10%。

在我的机器上,custom-byte-test现在是 ~1200 毫秒,而standard-list-test.

#lang racket
(require racket/unsafe/ops profile)

(define-syntax (for/bytes stx)
  (syntax-case stx ()
    [(_ clauses . defs+exprs)
     (with-syntax ([original stx])
       #'(let ([init-bstr-len 32])
           (let-values
             ([(bstr i max-length)
               (for/fold/derived 
                original 
                ([bstr (make-bytes init-bstr-len)]
                 [c 0]
                 [bstr-len init-bstr-len]) ; <-- use as curr len + extend len
                clauses
                (define el (let () . defs+exprs))
                (let-values 
                  ([(new-bstr new-bstr-len)
                    (if (= c bstr-len) ; <-- remove len calculation
                        (values 
                          (bytes-append bstr (make-bytes bstr-len))
                          (* bstr-len 2))
                        (values bstr bstr-len))])
                  (unsafe-bytes-set! new-bstr c el) ; <-- unsafe op
                  (values new-bstr (add1 c) new-bstr-len)))])
             (subbytes bstr 0 i))))]))

(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)
于 2014-02-19T21:40:10.460 回答