Tôi đang cố gắng tìm ra một số vấn đề về hiệu suất mà tôi đã gặp phải với Haskell. Là một phần trong đó, tôi đã viết một chương trình so sánh nhỏ để so sánh C và Haskell. Cụ thể, tôi đã dịch chương trình C sang Haskell với ít thay đổi nhất có thể. Phần đo tốc độ của chương trình Haskell sau đó được viết theo một phong cách rất bắt buộc.Tại sao Haskell thực hiện quá kém khi thực thi các mã giống như C? (trong trường hợp này ít nhất)
Chương trình tạo hai danh sách các số ngẫu nhiên trong một số phạm vi, sau đó tính tích phân của biểu đồ được hình thành bằng cách kết nối các điểm đó với một danh sách là x-giá trị và một danh sách là giá trị y. Về cơ bản, nó là trapezoidal rule.
Dưới đây là hai mã:
main.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 5000000
#define maxY 1e5f/N
#define maxXgap 1
int main(){
int i;
float *y, *x;
float xaccum, area;
clock_t begin, end;
double time_spent;
y = (float*)malloc(sizeof(float)*N);
x = (float*)malloc(sizeof(float)*N);
srand(50546345); // change seed for different numbers
//populate y and x fields with random points
for(i = 0; i < N; i++){
y[i] = ((float)rand())/((float)RAND_MAX)*maxY;
}
xaccum = 0;
for(i = 0; i < N; i++){
x[i] = xaccum;
xaccum += ((float)rand())/((float)RAND_MAX)*maxXgap;
}
begin = clock();
//perform a trapezoidal integration using the x y coordinates
area = 0;
for(i = 0; i < N-1; i++){
area += (y[i+1]+y[i])/2*(x[i+1]-x[i]);
}
end = clock();
time_spent = (double)(end - begin)/CLOCKS_PER_SEC * 1000;
printf("%i points\n%f area\n%f ms\n", N, area, time_spent);
}
Main.hs
{-# LANGUAGE BangPatterns #-}
module Main where
import Data.Array.Unboxed
import Data.Array.IO
import Data.List
import System.Random
import System.CPUTime
import Text.Printf
import Control.Exception
main :: IO()
main = do
(x,y) <- initArrays
area <- time $ integrate x y
print area
n :: Int
n = 5000000
maxY :: Float
maxY = 100000.0/(fromIntegral n)
maxXgap :: Float
maxXgap = 1
--initialize arrays with random floats
--this part is not measured in the running time (very slow)
initArrays :: IO (IOUArray Int Float, IOUArray Int Float)
initArrays = do
y <- newListArray (0,n-1) (randomList maxY n (mkStdGen 23432))
x <- newListArray (0,n-1) (scanl1 (+) $ randomList maxXgap n (mkStdGen 5462))
return (x,y)
randomList :: Float -> Int -> StdGen -> [Float]
randomList max n gen = map (abs . ((*) max)) (take n . unfoldr (Just . random) $ gen)
integrate :: IOUArray Int Float -> IOUArray Int Float -> IO Float
integrate x y = iterative x y 0 0
iterative :: IOUArray Int Float -> IOUArray Int Float -> Int -> Float -> IO Float
iterative x y !i !accum = do if i == n-1
then return accum
else do x1 <- readArray x i
x2 <- readArray x (i+1)
y1 <- readArray y i
y2 <- readArray y (i+1)
iterative x y (i+1) (accum + (y2+y1)/2*(x2-x1))
time :: IO t -> IO t
time a = do
start <- getCPUTime
v <- a
end <- getCPUTime
let diff = (fromIntegral (end-start))/(10^9)
printf "Computation time %0.5f ms\n" (diff :: Double)
return v
Việc tích hợp C chạy trong khoảng 7 ms và sự hội nhập Haskell trong khoảng 60 ms trên hệ thống của tôi. Tất nhiên phiên bản Haskell sẽ chậm hơn, nhưng tôi tự hỏi tại sao nó lại chậm hơn nhiều. Rõ ràng có rất nhiều sự thiếu hiệu quả trong mã Haskell.
Tại sao mã Haskell chậm hơn rất nhiều? Làm thế nào có thể sửa chữa nó?
Cảm ơn mọi câu trả lời.
Lệnh 'gói array' có 'unsafeRead' và' unsafeWrite' quá, không có cần phải chuyển sang 'vector' cho điều đó. –
Ồ, được rồi. Tôi đã có một cái nhìn nhanh chóng nhưng không thể nhìn thấy chúng. Rõ ràng quá nhanh –
@DanielFischer Tôi không thấy những phương thức đó trong giao diện MArray. Chúng có thực sự được thực thi khi các mảng có thể được lập chỉ mục bởi bất kỳ phần tử nào đang triển khai 'Ix' không? –