我正在玩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))))))
我有一些相关的问题:
for/fold/derived
文档中的示例与宏观扩展的for/vector
可悲的是,它并不比(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
会损失,因为尺寸大于它赢得的尺寸。
答案 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