将Haskell线程与内核线程进行比较 - 我的基准是可行的吗?

时间:2011-05-08 08:55:54

标签: multithreading haskell pthreads

这个实际上是我的大学项目。在我的文章中,我需要提供证据证明Haskell线程的创建速度比普通内核线程快。我知道最好参考一些研究论文,但重点是我必须自己做基准测试。

这是我想出来的。我用C语言(使用pthreads)和Haskell编写了两个程序,它们创建了许多线程,但这些线程绝对没有做任何事情。我只需要测量创建线程的速度。

这是C程序的源代码:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

void* thread_main(void*);

int main(int argc, char* argv[])
{
   int n,i;
    pthread_t *threads;
    pthread_attr_t pthread_custom_attr;

    if (argc != 2)
    {
        printf ("Usage: %s n\n  where n is no. of threads\n",argv[0]);
       return 1;
   }

    n=atoi(argv[1]);

    threads=(pthread_t *)malloc(n*sizeof(*threads));
    pthread_attr_init(&pthread_custom_attr);

    for (i=0; i<n; i++)
    {
        pthread_create(&threads[i], &pthread_custom_attr, thread_main, (void *)(0));
    }

    for (i=0; i<n; i++)
    {
        pthread_join(threads[i],NULL);
    }
}

void* thread_main(void* p)
{
   return 0;
}

和Haskell计划:

module Main (main) where

import System.IO.Unsafe
import System
import Control.Concurrent
import Control.Exception

children :: MVar [MVar ()]
children = unsafePerformIO (newMVar [])

waitForChildren :: IO ()
waitForChildren = do
   cs <- takeMVar children
   case cs of
      []   -> return ()
      m:ms -> do
         putMVar children ms
         takeMVar m
         waitForChildren

forkChild :: IO () -> IO ThreadId
forkChild io = do
   mvar <- newEmptyMVar
   childs <- takeMVar children
   putMVar children (mvar:childs)
   forkIO (io `finally` putMVar mvar ())

forkKids :: Int -> IO ()
forkKids 0 = return ()
forkKids n = do
   forkChild (threadMain)
   forkKids (n-1)

threadMain = return ()

main = do
   args <- getArgs
   forkKids (read (head args))
   waitForChildren

现在,我所做的是用相同的参数运行每个程序(例如10000)并用time -f%e测量它们的运行时间,然后取运行时间的算术平均值。它表明创建Haskell线程的速度要快一些。

现在,我的问题是:这是一个正确的基准吗?或者是否有一些因素需要我考虑以获得准确的结果?

由于

2 个答案:

答案 0 :(得分:4)

你的基准测试可能会让你得到你想要的结果,但却有很多噪音。你测量的不是“创建一个线程需要多长时间”,而是“启动和运行一个创建多个线程的程序需要多长时间,然后在终止之前等待它们返回”。

在实践中答案可能或多或少相同,但在进行基准测试时,您应该尝试将其缩小,以便对您感兴趣的内容进行基准测试,并尽可能减少外部噪音。

为什么不围绕pthread_create / forkIO来电打一个计时器,因为它们是您想要衡量的?

您对启动程序所需的时间不感兴趣,所以不要花时间。你对之后加入线程需要多长时间不感兴趣,所以不要花时间。

答案 1 :(得分:0)

根据线程数量,pthread_create()可能会在某个时刻停止创建线程;在基准测试时应该注意这一点。