2012-03-16 26 views
7

Các mã sau đây:Haskell: sự khác biệt về hiệu suất từ ​​thành phần chức năng khác nhau?

import Control.Exception 
import Data.List 

updateAverage :: (Fractional t) => (t, t) -> t -> (t, t) 
updateAverage (old_value, old_counter) x = 
    let new_counter = old_counter + 1 
    in 
     assert(new_counter /= 0) 
     old_value `seq` (old_value + (x - old_value)/new_counter, new_counter) 

average values = fst (foldl' updateAverage (0.0, 0.0) values) -- version I 

main = do 
    let v = [1 .. 1000000] 
    let a = average v 
    putStrLn (show a) 

trở nên nhanh hơn (tùy chọn biên dịch: ghc.exe -O3) khi tôi thay đổi định nghĩa của average chức năng với

average = fst . foldl' updateAverage (0.0, 0.0) -- version II 

gì có thể là lý do cho việc này? Tôi nghĩ rằng sự khác biệt giữa hai dòng này về cơ bản là cú pháp. Là phiên bản thứ hai (không có biến miễn phí values) dễ dàng hơn cho trình biên dịch để tối ưu hóa?

Vui vẻ đủ, khi được biên dịch mà không tối ưu hóa, phiên bản tôi trở nên nhanh hơn.

kết quả Thời gian:

lựa chọn: -O3

phiên bản I: 0.280s phiên bản II: 0.212s

lựa chọn: (không tối ưu hóa)

phiên bản I: 0.42s phiên bản II: 0.44s

Đo bằng cách sử dụng time lệnh shell trong Cygwin.

kết quả Timing với type = đúp:

đúp:

lựa chọn: O3

phiên bản I: 0.22s phiên bản II :: 0.212s

lựa chọn: (không tối ưu hóa)

phiên bản I: 0.34s phiên bản I I: 0.35s

Thông tin thêm: Tôi đang sử dụng trình biên dịch

> $ ghc -v Glasgow Haskell Compiler, Version 7.0.4, for Haskell 98, 
> stage 2 booted by GHC version 6.12.2 Using binary package database: 
> C:\Program Files\Haskell 
> Platform\2011.4.0.0\lib\package.conf.d\package.cache wired-in package 
> ghc-prim mapped to ghc-prim-0.2.0.0-e1f7c380581d61d42b0360d440cc35ed 
> wired-in package integer-gmp mapped to 
> integer-gmp-0.2.0.3-91607778cf3ae8f3948a50062b4f8479 wired-in package 
> base mapped to base-4.3.1.0-f520cd232cc386346843c4a12b63f44b wired-in 
> package rts mapped to builtin_rts wired-in package template-haskell 
> mapped to template-haskell-2.5.0.0-7d9b1443ac5ab69e5ed705a487990deb 
> wired-in package dph-seq not found. wired-in package dph-par not 
> found. Hsc static flags: -static 
> *** Deleting temp files: Deleting: 
> *** Deleting temp dirs: Deleting: ghc.exe: no input files Usage: For basic information, try the `--help' option. 
under Cygwin.* 
+0

Tôi sẽ đánh giá cao nếu các downvoters thêm bình luận giải thích những gì họ không thích trong câu hỏi. –

+2

+1 để khôi phục số dư của lực – Landei

+0

Bạn có thể cho biết sự khác biệt về tốc độ giữa hai phiên bản và các mức O khác nhau không? Làm thế nào bạn đo được nó? – Sarah

Trả lời

3

Tôi phỏng đoán rằng một cái gì đó có thể xảy ra với dòng phản ứng tổng hợp hoặc vòng lặp phản ứng tổng hợp. Có lẽ có một quy tắc viết lại bị chôn vùi sâu trong Prelude đang bắn trong một trường hợp hay không trong trường hợp khác. Hoặc, bởi vì bạn không nói mức độ nhanh hơn bao nhiêu là, bạn có thể thấy hiệu ứng bộ nhớ cache đơn giản.

Nếu bạn muốn tìm hiểu thêm, học cách cá:

  • Sử dụng ghc -ddump-simpl để xem mã đó là thực sự được tạo ra và so sánh nó.

  • Sử dụng valgrind để đếm số lượng lệnh được thực thi.

Nếu không có gì khác, những công cụ này sẽ cung cấp cho bạn đủ thông tin mà bạn có thể đặt câu hỏi chi tiết, chi tiết hơn.

+0

Cảm ơn! Phiên bản II có ít chuyển đổi loại hơn. Liệu tinh thần mà cú pháp không có điểm này giúp Haskell dễ dàng tối ưu hóa cách nó chuyển đổi các giá trị giữa các loại? –

+0

@quant_dev Nó có thể là như vậy. – fuz