【问题标题】:run haskell operations in parallel or multithreaded并行或多线程运行 haskell 操作
【发布时间】:2014-07-24 01:31:46
【问题描述】:

我刚开始学习函数式编程和 Haskell,我什至还没有完全理解语法及其工作原理,因为它与我以前习惯的(例如 ruby​​、php、C# 或 node)非常不同,哪些是 OOP 语言 - 或多或少)。

我正在尝试编写一个小程序来检查 Brocard's Problem 或所谓的 棕色数字 的解决方案,我首先用 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 或任何硬编码的数字,但我希望能够决定它应该经过的时间间隔,因此:

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 将是在不同时间间隔 ([1..1000] -&gt; [i..j]) 计算的相同函数 results

我将不胜感激,因为此时我自己无法做到这一点:)

【问题讨论】:

  • 如果您想自己解决,我建议您阅读 Simon Marlow 的 Parallel and Concurrent Programming in Haskell。您可以在该链接上购买这本书或在网上免费阅读。他很好地介绍了您可以在 Haskell 中使用的不同技术。

标签: multithreading haskell parallel-processing


【解决方案1】:

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

【讨论】:

  • 如果库是 Haskell 的内置模块,那就太好了,否则除非必要,否则我倾向于避免对这样一个简单的要求的 3rd 方依赖。
  • @rolandjitsu 您会发现 Haskell 的大部分内容都被打包成小的独立包。 base 仅包括 Haskell 开发所需的绝对基础库,但不包括 containers 之类的东西,它们具有 Maps、HashMaps 和其他标准结构。它们不一定是第 3 方,因为其中许多都带有 Haskell 平台。 Haskell 平台只是一组被认为稳定、广泛有用且无处不在的社区库。 parallel 库与 Haskell Platform 一起提供。
  • 如果您提供一个代码示例,说明如何将这两个库(异步和并行)与我在问题描述中添加的函数 pairs 结合使用,我将不胜感激
  • 我尝试了这个例子(导入Control.Parallel),但是当我在ghci:load file.hs 时编译失败。
  • @rolandjitsu 示例中的一些小错误现在应该修复,包括正确的导入。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-06
  • 1970-01-01
  • 2020-11-10
相关资源
最近更新 更多