首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在非类型化模块中使用类型化/球拍模块中的类会产生不好的性能?

为什么在非类型化模块中使用类型化/球拍模块中的类会产生不好的性能?
EN

Stack Overflow用户
提问于 2017-11-27 09:12:02
回答 1查看 223关注 0票数 5

有关更新,请参见编辑1、2和3。我把整个研究过程留在这里。

我知道我们可以从非类型化的球拍中使用typed/racket模块(反之亦然)。但是当这样做时,typed/racket模块的行为就好像它是typed/racket/no-check,它禁用优化并将其作为一个普通的非类型化模块使用。

例如,如果您有这样一个typed/racket模块:

代码语言:javascript
复制
#lang typed/racket
(require math)
(provide hello)
(define (hello [str : String])
  (define result : (Matrix Flonum) (do-some-crazy-matrix-operations))
  (display (format "Hello ~a! Result is ~a" str result)))

您想在这样的非类型化程序中使用它:

代码语言:javascript
复制
#lang racket/base
(require "hello-matrix.rkt")
(hello "Alan Turing")

您将得到非常糟糕的性能结果(在我的例子中,我正在做大约600000个矩阵乘法,程序甚至没有完成),而使用#lang typed/racket使我的程序在3秒内完成。

缺点是我的非类型化代码会被类型感染,迫使我用TR编写所有的程序,很快就把我逼疯了。

但我的救世主不在那么远。我偶然发现了一个有趣的、像四月一样愚笨的包裹,Jay McCarthy是在一个阴天的黑夜里写的,名叫live-free-or-die,几乎就是这样写的:

http://docs.racket-lang.org/live-free-or-die/index.html

代码语言:javascript
复制
#lang racket/base
(require (for-syntax racket/base
                     typed-racket/utils/tc-utils))
(define-syntax (live-free-or-die! stx)
  (syntax-case stx ()
    [(_)
     (syntax/loc stx
       (begin-for-syntax
         (set-box! typed-context? #t)))]))
(provide live-free-or-die!
         (rename-out [live-free-or-die!
                      Doctor-Tobin-Hochstadt:Tear-down-this-wall!]))

在我的typed/racket模块中使用它,如下所示:

代码语言:javascript
复制
#lang racket
(require live-free-or-die)
(live-free-or-die!)
(require math)
(provide hello)
(define (hello str)
  (define result (do-some-crazy-matrix-operations))
  (display (format "Hello ~a! Result is ~a" str result)))

现在我的模块不再是#lang typed/racket了,但是运行它的结果是惊人的!它在3秒内运行,就好像它是一个typed/racket模块。

当然,我对这一攻击感到厌恶,这就是为什么我想知道是否有更好的解决方案,特别是为了使math中的矩阵操作可用。

Google小组讨论那个疯狂的模块,Jay写的是我唯一能得到的信息。

https://groups.google.com/forum/#!topic/racket-users/JZoHYxwwJqU

这个线程中的人似乎说模块不再有用了:

Matthias Felleisen 好吧,既然我们的年轻人已经轻易地揭穿了这个包裹,我们可以让它死掉,因为它不再想活下去了。

真的有更好的选择吗?

编辑1-一个可测试的示例

如果要测试性能差异,请尝试使用do-some-crazy-matrix-operations的以下定义

代码语言:javascript
复制
#lang typed/racket
(require math)
(provide hello)

(: do-some-crazy-matrix-operations : (-> (Matrix Flonum)))
(define (do-some-crazy-matrix-operations)
  (define m1 : (Matrix Flonum) (build-matrix 5 5 (lambda (x y) (add1 (random)))))
  (define m2 : (Matrix Flonum) (build-matrix 5 5 (lambda (x y) (add1 (random)))))
  (for ([i 60000])
    (set! m1 (matrix-map * m1 m2))
    (set! m2 (matrix-map * m1 m2)))
  (matrix+ m1 m2))

(define (hello [str : String])
  (define result : (Matrix Flonum) (do-some-crazy-matrix-operations))
  (display (format "Hello ~a! Result is ~a" str result)))

(time (hello "Alan Turing"))

使用#lang typed/racket,它在288 in中运行:

代码语言:javascript
复制
cpu time: 288 real time: 286 gc time: 16

使用#lang typed/racket/no-check,它在52秒内运行:

代码语言:javascript
复制
cpu time: 52496 real time: 52479 gc time: 396

使用#lang racketlive-free-or-die,它在280 in中运行:

代码语言:javascript
复制
cpu time: 280 real time: 279 gc time: 4

编辑2-这不是问题!

按照约翰·克莱门特的回答,我发现这些例子不足以再现真正的问题。在非类型化模块中使用typed/racket 模块的实际上运行良好.

我真正的问题是由一个类创建的边界契约的问题,该类从非类型化到类型化。

让我们考虑一下hello-matrix.rkt的这个实现

代码语言:javascript
复制
#lang typed/racket
(require math)
(provide hello crazy% Crazy)

(define-type CrazyClass (Class (field [m1 (Matrix Flonum)])
                               (field [m2 (Matrix Flonum)])
                               (do (-> (Matrix Flonum)))))
(define-type Crazy (Instance CrazyClass))
(: crazy% CrazyClass)
(define crazy%
  (class object%
    (field [m1 (build-matrix 5 5 (lambda (x y) (add1 (random))))]
           [m2 (build-matrix 5 5 (lambda (x y) (add1 (random))))])

    (super-new)

    (define/public (do)
      (set! m1 (matrix* (matrix-transpose m1) m2))
      (set! m2 (matrix* (matrix-transpose m1) m2))
      (matrix+ m1 m2))))

(: do-some-crazy-matrix-operations : Crazy -> (Matrix Flonum))
(define (do-some-crazy-matrix-operations crazy)
  (for ([i 60000])
    (send crazy do))
  (matrix+ (get-field m1 crazy) (get-field m2 crazy)))

(define (hello [str : String] [crazy : Crazy])
  (define result : (Matrix Flonum) (do-some-crazy-matrix-operations crazy))
  (display (format "Hello ~a! Result is ~a\n" str result)))

那么这两种用法:

代码语言:javascript
复制
#lang typed/racket
(require "hello-matrix.rkt")
(define crazy : Crazy (new crazy%))
(time (hello "Alan Turing" crazy))

cpu time: 1160 real time: 1178 gc time: 68

代码语言:javascript
复制
#lang racket
(require "hello-matrix.rkt")
(define crazy (new crazy%))
(time (hello "Alan Turing" crazy))

cpu time: 7432 real time: 7433 gc time: 80

使用contract-profile

代码语言:javascript
复制
Running time is 83.47% contracts
6320/7572 ms

BY CONTRACT

g66 @ #(struct:srcloc hello-matrix.rkt 3 15 50 6)
  3258 ms

(-> String (object/c (do (-> any/c (struct/c Array (vectorof Index) Index (box/c (or/c #f #t)) (-> Void) (-> (vectorof Index) Float)))) (field (m1 (struct/c Array (vectorof Index) Index (box/c (or/c #f #t)) (-> Void) (-> (vectorof Index) Float))) (m2 (struct/c Array (vectorof Index) Index (box/c (or/c #f #t)) (-> Void) (-> (vectorof Index) Float))))) any) @ #(struct:srcloc hello-matrix.rkt 3 9 44 5)
  3062 ms

编辑3-从类型化到非类型化的struct比传递class更具有性能。

使用结构而不是类可以修复以下问题:

hello-matrix.rkt:

代码语言:javascript
复制
#lang typed/racket
(require math)
(provide hello (struct-out crazy))

(struct crazy ([m1 : (Matrix Flonum)] [m2 : (Matrix Flonum)]) #:mutable)
(define-type Crazy crazy)

(define (crazy-do [my-crazy : Crazy])
  (set-crazy-m1! my-crazy (matrix* (matrix-transpose (crazy-m1 my-crazy))
                                   (crazy-m2 my-crazy)))
  (set-crazy-m2! my-crazy (matrix* (matrix-transpose (crazy-m1 my-crazy))
                                   (crazy-m2 my-crazy)))
  (matrix+ (crazy-m1 my-crazy) (crazy-m2 my-crazy)))

(: do-some-crazy-matrix-operations : Crazy -> (Matrix Flonum))
(define (do-some-crazy-matrix-operations my-crazy)
  (for ([i 60000])
    (crazy-do my-crazy))
  (matrix+ (crazy-m1 my-crazy) (crazy-m2 my-crazy)))

(define (hello [str : String] [my-crazy : Crazy])
  (define result : (Matrix Flonum) (do-some-crazy-matrix-operations my-crazy))
  (display (format "Hello ~a! Result is ~a\n" str result)))

使用:

代码语言:javascript
复制
#lang typed/racket
(require "hello-matrix.rkt")
(require math)
(define my-crazy (crazy (build-matrix 5 5 (lambda (x y) (add1 (random))))
                        (build-matrix 5 5 (lambda (x y) (add1 (random))))))
(time (hello "Alan Turing" my-crazy))

cpu time: 1008 real time: 1008 gc time: 52

代码语言:javascript
复制
#lang racket

cpu time: 996 real time: 995 gc time: 52

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-11-28 23:36:43

我把这写成“答案”让我格式化我的代码..。我想我们谈的有点过头了。具体来说,我可以在半秒钟内从一个非类型化模块运行您的类型化代码。按照您的建议,我将键入的代码文件命名为“hello-matx.rkt”,然后运行您提供的非类型化模块(需要TR模块的非类型化模块),它花费了相同的时间(大约半秒)。请允许我谨慎地说:

“hello-matx.rkt”的内容:

代码语言:javascript
复制
#lang typed/racket
(require math)
(provide hello)

(: do-some-crazy-matrix-operations : (-> (Matrix Flonum)))
(define (do-some-crazy-matrix-operations)
  (define m1 : (Matrix Flonum) (build-matrix 5 5 (lambda (x y) (add1 (random)))))
  (define m2 : (Matrix Flonum) (build-matrix 5 5 (lambda (x y) (add1 (random)))))
  (for ([i 60000])
    (set! m1 (matrix-map * m1 m2))
    (set! m2 (matrix-map * m1 m2)))
  (matrix+ m1 m2))

(define (hello [str : String])
  (define result : (Matrix Flonum) (do-some-crazy-matrix-operations))
  (display (format "Hello ~a! Result is ~a" str result)))

(time (hello "Alan Turing"))

然后,我从一个未键入的模块中调用它,就像您所说的:

代码语言:javascript
复制
#lang racket/base
(require "hello-matrix.rkt")
(time (hello "Alan Turing"))

结果是:

代码语言:javascript
复制
Hello Alan Turing! Result is (array #[#[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0] #[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0] #[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0] #[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0] #[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0]])
cpu time: 719 real time: 710 gc time: 231
Hello Alan Turing! Result is (array #[#[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0] #[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0] #[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0] #[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0] #[+inf.0 +inf.0 +inf.0 +inf.0 +inf.0]])
cpu time: 689 real time: 681 gc time: 184

也就是说,它需要同样的时间来调用它从非类型的球拍,它所做的从类型球拍。

这个结果可能在一定程度上取决于您使用的是哪个版本的DrRacket;我使用的是6.11。

所有这些都是为了证明TR代码仍然是TR代码,即使您从非类型化代码中调用它。我确实认为您存在性能问题,而且我确实认为它们与矩阵操作有关,但是这个特殊的例子并没有说明它们。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47507264

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档