并行或多线程运行haskell操作

时间:2014-07-21 18:26:41

标签: multithreading haskell parallel-processing

我刚刚开始学习函数式编程和Haskell,我甚至不太了解语法及其工作原理,因为它与我之前习惯的非常不同(例如ruby,php,C#或node)这些是OOP语言 - 或多或少)。

我正在尝试整理一个小程序来检查Brocard's Problem或所谓的 Brown Numbers 的解决方案,我首先在ruby中创建了一个草稿,但我发现Haskell是更适合做数学表达式。我以前问过question,我很快就得到了如何将我的ruby代码翻译成Haskell的答案:

results :: [(Integer, Integer)] --Use instead of `Int` to fix overflow issue
results =  [(x,y) | x <- [1..1000], y <- [1..1000] , 1 + fac x == y*y]
    where fac n = product [1..n]

我稍微改变了一下,所以我可以从我想要的任何数字运行相同的操作,因为以上操作将从11000或任何硬编码的数字,但我想能够决定它应该经过的间隔,ergo:

pairs :: (Integer, Integer) -> [(Integer, Integer)]
pairs (lower, upper) =  [(m, n) | m <- [lower..upper], n <- [lower..upper], 1 + factorial n == m*m] where factorial n = product [1..n]

我问这个问题的原因是我在考虑是否可以并行(和/或在多个线程和/或核心上)运行此操作,并将结果附加到同一个变量。

我还没有理解Haskell或线程模型中的并行处理,但在ruby中,线程模型如何工作的一个很好的例子就像this

def func1
  i=0
  while i<=2
    puts "func1 at: #{Time.now}"
    sleep(2)
    i=i+1
  end
end

def func2
  j=0
  while j<=2
    puts "func2 at: #{Time.now}"
    sleep(1)
    j=j+1
  end
end

puts "Started At #{Time.now}"
t1=Thread.new{func1()}
t2=Thread.new{func2()}
t1.join
t2.join
puts "End at #{Time.now}"

就我而言,func1func2将是在不同时间间隔(results)计算的相同函数[1..1000] -> [i..j]

我很感激一些帮助,因为我现在无法自己做这件事:)

1 个答案:

答案 0 :(得分:2)

Parallel and Concurrent Programming in Haskell有很多很好的信息,async是一个很好的库。

但是在底层,你会发现forkIO来启动一个新的轻量级线程。

当然,并发,而不是确定性并行,parallel就是这个库,本书也对此进行了介绍。

您的示例转换为:

import Data.Time.Clock (getCurrentTime)

main = do
    start <- getCurrentTime
    putStr "Started At " >> print start
    _ <- forkIO func1
    _ <- forkIO func2
    end <- getCurrentTime
    putStr "End at " >> print end

func1 = helper "func1" 2

func2 = helper "func2" 1

helper name sleepTime = go 0
 where
    go 3 = return ()
    go n = do
        now <- getCurrentTime
        putStr name >> putStr " at: " >> print now
        threadDelay sleepTime
        go $ succ n

我建议学习上面提到的并行和/或异步库,而不是编写自己的线程内容,至少最初是这样。

这是使用并行在8-ish处理器上运行测试的一个不太好的例子:

import Control.Parallel.Strategies

factorial = product . enumFromTo 1
pairs (lower, upper) =  map fst . filter snd . withStrategy sparkTest
                     $ [ ((m, n), b)
                       | m <- [lower..upper]
                       , n <- [lower..upper]
                       , let b = 1 + factorial n == m*m
                       ]
sparkTest = evalBuffer 8 $ evalTuple2 rseq rpar