2

私は 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. とにかくこれはラケットのやり方ですか?
  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)

3212ms 対 3690ms になります。50000 より小さいサイズの場合はfor/bytes負け、それより大きいサイズの場合は勝ちです。

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-incraに置き換えました。bstr-len

これにより、約 15% の改善が得られました。

2) すでに長さのチェックを行っているので、 を安全に使用できますunsafe-bytes-set!。これにより、処理速度がさらに 10% 向上します。

私のマシンでcustom-byte-testは、今では ~1200ms 対 ~1750msstandard-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 に答える