如何在 Haskell 中创建通道列表(或数组),如 Go

2024-04-18

我试图将 Haskell 与 Go 进行比较以获得一些并发示例,以下代码是 Go 中使用 Goroutines 和通道的简单映射缩减示例。以下 Go 代码计算平方和:

1^2+2^2+3^2....1024^2

为了测试Go和Haskell的性能,我重复计算R次(10)的平方和。

package main

import "fmt"

func mapper(in chan int, out chan int) {
    for v := range in {out <- v*v}
}

func reducer(in1, in2 chan int, out chan int) {
    for i1 := range in1 {i2 := <- in2; out <- i1 + i2}
}

func main() {
    const N = 1024  // calculate sum of squares up to N; N must be power of 2
    const R = 10  // number of repetitions to fill the "pipe"

    var r [N*2]chan int
    for i := range r {r[i] = make(chan int)}
    var m [N]chan int
    for i := range m {m[i] = make(chan int)}

    for i := 0; i < N; i++ {go mapper(m[i], r[i + N])}
    for i := 1; i < N; i++ {go reducer(r[i * 2], r[i *2 + 1], r[i])}

    go func () {
        for j := 0; j < R; j++ {
            for i := 0; i < N; i++ {m[i] <- i + 1} 
        }
    } ()

    for j := 0; j < R; j++ {
        <- r[1]
    } 
}

问题是如何在 Haskell 中有效地实现这个 mapreduce 示例。以下 Haskell 代码尝试在 main 函数中计算 10^2 + 7^2。我的问题是如何创建一个通道数组(或列表),例如 Go,然后在主函数中将映射器和减速器线程连接在一起。

import Control.Concurrent
data MRchannel = MRchannel !(MVar MRcmd)
data MRcmd = Pass !Int | Add !Int
  deriving (Show)

mapper:: MRchannel -> MRchannel -> IO ()
mapper left_C@(MRchannel left) right_C@(MRchannel right) = do
    v <- takeMVar left
    case v of
        Pass x -> do
            putMVar right (Add (x*x))
            mapper left_C right_C
        otherwise -> do
            putStrLn "Error!"
            return ()

reducer::  MRchannel -> MRchannel -> MRchannel -> IO ()
reducer left_1_C@(MRchannel left_1) left_2_C@(MRchannel left_2) 
right_C@(MRchannel right) = do
    v1 <- takeMVar left_1
    case v1 of
        Add x1 -> do
            v2 <- takeMVar left_2
            case v2 of
                Add x2 -> do 
                    putMVar right (Add (x1+x2))
                    reducer left_1_C left_2_C right_C
                otherwise -> do
                    putStrLn "Error!"
                    return ()
        otherwise -> do
            putStrLn "Error!"
            return ()

main = do
m1_l <- newEmptyMVar
m2_l <- newEmptyMVar
r1_l1 <- newEmptyMVar
r1_l2 <- newEmptyMVar
r1_r <- newEmptyMVar
    let m1_input = MRchannel m1_l
    let m2_input = MRchannel m2_l
    let r1_input1 = MRchannel r1_l1
    let r1_input2 = MRchannel r1_l2
    let r1_output = MRchannel r1_r
    forkIO $ mapper m1_input r1_input1
    forkIO $ mapper m2_input r1_input2
    forkIO $ reducer r1_input1 r1_input2 r1_output

    putMVar m1_l (Pass 10)
    putMVar m2_l (Pass 7)

    y <- takeMVar r1_r
    case y of 
        Add kvalue  -> do
            putStrLn $ show kvalue
        otherwise -> do
            putStrLn "Error"
            return () 

这是一个替代方案。在我看来,它不是非常优雅,但比原始代码简单一些。

主要变化:

  • 我们不需要两个列表MVars并使用慢速!!
  • We use forkAll它产生了映射器/减速器的整个二叉树(它的参数是深度:2^10 = 1024)
  • forkAll仍然不是最理想的,因为它使用++虽然速度很慢
  • 主要变化:做时putMVar,我们使用强制值$!,这样我们就不会将未计算的表达式存储在MVar。这是一个重大的性能提升。
  • 我们不打印所有结果,而是只打印它们的总和。否则,文本 IO 会降低基准测试速度。 (注意,原来的repeats does n+1循环,所以我不得不使用10241代替10240下面,以匹配结果。)

新代码速度快了 54%。

import Control.Concurrent
import Control.Monad

mapper :: MVar Int -> MVar Int -> IO ()
mapper left right = forever $ do
    v <- takeMVar left
    putMVar right $! v*v

reducer :: MVar Int -> MVar Int -> MVar Int -> IO ()
reducer left_1 left_2 right = forever $ do
    v1 <- takeMVar left_1
    v2 <- takeMVar left_2
    putMVar right $! v1+v2

forkAll :: Int -> MVar Int -> IO [MVar Int]
forkAll 0 res = do
  v <- newEmptyMVar
  _ <- forkIO $ mapper v res
  return [v]
forkAll depth res = do
  v1 <- newEmptyMVar
  r1 <- forkAll (depth - 1) v1
  v2 <- newEmptyMVar
  r2 <- forkAll (depth - 1) v2
  _ <- forkIO $ reducer v1 v2 res
  return (r1++r2)

main :: IO ()
main = do
  v <- newEmptyMVar
  res <- forkAll 10 v

  nums <- replicateM 10241 $ do
     mapM_ (\ (r,i) -> putMVar r (i+1)) $ zip res [0..]
     takeMVar v
  print $ sum nums
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Haskell 中创建通道列表(或数组),如 Go 的相关文章

  • Haskell 将两个列表中不同索引处的元素组合起来

    对这个糟糕的标题表示歉意 我不太确定如何用语言描述它 但这就是我的意思 如果您知道更好的表达方式 请告诉我 假设我有 2 个长度相等的列表 a b c x y z 我想创建列表 a y z b x z c x y 本质上 对于 list1
  • 尝试以特殊行为渲染 Threepenny-gui 中的字段

    我想要做的是设置字段 当它们处于焦点时显示详细信息 而当它们不处于焦点时显示摘要 例如 A 当它失去焦点 变得模糊 时 我将值保存在 状态 映射中 然后将该值更改为旧值的函数 即汇总值 b 当它获得焦点时 我用我在地图中保存的旧值替换摘要值
  • 用户状态(秒差距)

    我正在使用秒差距解析一个表达式 并且我想使用秒差距中的用户状态来跟踪这些表达式中的变量 不幸的是我真的不知道该怎么做 给出以下代码 import Data Set as Set inp x y z data Var V String var
  • 如何更改java8中字符串列表中的项目

    我想更改中的所有项目list 正确的做法是什么java8 public class TestIt public static void main String args ArrayList
  • 主要:并非所有代码路径都会返回值

    我正在制作列表并想在控制台中查看它 我有一个错误 它说 Main 并非所有代码路径都会返回值 也许你可以帮助我 这是我的代码 namespace ConsoleApplication5 public class DocConfig publ
  • Parsec-Parser 工作正常,但是可以做得更好吗?

    我尝试这样做 解析以下形式的文本 一些文本 0 0 0 一些文本 0 0 0 0 0 0 更多文本 0 0 0 进入一些数据结构的列表 内部 一些文本 外部 0 0 0 内部 一些文本 外部 0 0 0 外部 0 0 0 内部 更多文本 外
  • 方案语言:合并两个数字

    如何将列表中的两个整数合并为一个 方案中 例子 11 223 gt 11223 假设列表恰好有两个元素 并且都是数字 define merge numbers lst let 1st number gt string first lst 2
  • List 和 List 之间的区别[重复]

    这个问题在这里已经有答案了 我读过很多这方面的内容 我知道 List listOfObject new ArrayList
  • Haskell - 无法将类型“PersistEntityBackend record0”与“SqlBackend”匹配

    我正在尝试通过 Yesod 中的 id 获取记录 我的代码是 getEditActorR Handler Html getEditActorR do actorId lt runInputGet ireq intField id actor
  • 枚举列表中的列表

    我有一个约会 并记录了那天发生的事件 我想枚举显示日历的日期的事件列表 我还需要能够从列表中删除事件 def command add date event calendar if date not in calendar calendar
  • Haskell 长度函数实现

    我正在学习 Haskell 编程 我试图理解列表是如何工作的 因此我尝试编写两个可能的length功能 myLength a gt Integer myLength foldr x gt 1 0 myLength1 a gt Integer
  • C# 排序列表 - 快速,具有可移动、重复的键

    我制作了一个带有压缩机制的应用程序 需要我自己的字典 我的应用程序中的每个 cicle 都会将新元素添加到 myDictionary 中并更新 向 myDictionary 中的一些先前元素添加一个字符 我用普通列表和快速排序函数来做到这一
  • 有没有办法从 IO monad 中解开类型?

    我有这个非常简单的功能 import qualified Data ByteString Lazy as B getJson IO B ByteString getJson B readFile jsonFile readJFile IO
  • 如何在 C# 中对包含日期的字符串数组进行排序?

    我不确定以前是否有人问过这个问题 但我有几个需要排序的字符串数组 这个想法是合并不同的字符串数组并按每个元素的日期字段对它们进行排序 我正在从 sql server 表中读回信息 我怎样才能去做这样的事情呢 数据示例可能如下所示 类型 字段
  • 在 VB.NET 中对对象列表进行排序

    我有一个乘客 对象 列表 它具有不同的属性 passenger name passenger age passenger surname 我想按年龄标准对这个列表进行排序 我该怎么做 我知道在整数 字符串列表中 List Sort 有效 但
  • python随机字典键,并访问它[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 import random Cards Spade 2 3 4 5 6 7 8 9 10 Jack Queen King
  • AttributeError:尝试删除字符时,“列表”对象没有属性“替换”

    我试图通过执行以下操作从字符串中删除字符 kickoff tree xpath id page div 1 div main div article div div 1 section 2 p 1 b 1 text kickoff kick
  • 在 Dart 中打印不带括号的列表

    我想在打印时从列表中删除括号 Dart Code void main var lst new List 3 for int i 0 i lt 3 i lst i i print lst 电流输出 0 1 2 预期输出 0 1 2 您可以使用
  • 以字符集安全的方式获取 Windows 上的进程列表

    这个帖子 https stackoverflow com questions 54686 how to get a list of current open windows process with java给出了一个在 Windows 下
  • 在列表列表中查找形状

    节目说明 该计划的目的 我的程序旨在计算 20X15 大小的平面中形状的位置 我有一个形状列表 其中包含形状类型 其 ID 半径或高度以及其在平面上的预期 X Y 位置 我有一个不同的二元运算列表 仅包含形状类型 其 id 及其与另一个形状

随机推荐

  • javascript - 按钮需要单击两次才能触发 onclick

    为什么我的按钮需要单击两次才能触发 onclick 事件 stackoverflow 上还有其他一些线程也存在同样的问题 但在我发现的所有线程中 原始发布者将事件处理程序放在函数内 我的代码不是这样的 Html ul li First ch
  • 在 JavaScript 中从具有任意基数的整数生成字符串

    在 JavaScript 中 您可以从数字生成字符串 如下所示 123 toString 36 gt 3f 如果你尝试做任意基础 123 toString 40 You get Uncaught RangeError toString ra
  • 如何使用 bootstrap-multiselect 动态隐藏/显示选项?

    我在用引导多选 http davidstutz github io bootstrap multiselect 为用户提供对两个按键菜单的良好控制 我的第一个菜单叫做groups和其他称为queues 队列中的每个选项都有一个 HTML5
  • Octave-'endfunction' 命令与 'endif' 匹配

    有人可以告诉我我的代码有什么问题吗 sinlaw 150 30 39 8 parse error near line 30 of file endfunction command matched by endif function phi
  • 仅当应用程序 100% 完成时,才能在仪器测试后正确清理/拆卸

    我有一堆端到端仪器测试 依赖于 Espresso 它们启动我们的启动器活动 然后在我们的应用程序中导航 最终创建多个活动 在 的最后each测试我们的 After带注释的拆卸方法执行一些清理工作 我们遇到的问题是 测试完成 成功或失败的断言
  • Xcode 不断展开项目导航器中的所有组

    从几天前开始 Xcode 不断扩展项目导航器中的所有组和子组 我反复折叠它们 这样我就可以专注于我正在做的事情 然后我回去 它们都再次展开 还有其他人经历过吗 我折叠一个组 移至 Xcode 中的另一个选项卡 然后返回 所有组都再次展开 这
  • Lambda 属性值选择器作为参数

    我需要修改一个方法 以便它有一个额外的参数 该参数将采用 lambda 表达式 该表达式将用于内部对象以返回给定属性的值 请原谅我可能错误地使用了术语 因为这是我第一次尝试 LINQ 表达式 我尝试寻找答案 但正如我所提到的 我的术语似乎不
  • 使用 paramiko 检查远程主机上是否存在路径

    帕拉米科的SFTP客户端 http www metasnark com paramiko docs paramiko SFTP class html显然没有exists方法 这是我当前的实现 def rexists sftp path os
  • JavaFX - 在 DirectoryChooser 中显示文件

    是否可以使 DirectoryChooser 显示文件 而不仅仅是目录 与此处描述的问题相同JFileChooser 选择目录但显示文件 https stackoverflow com questions 2883447 jfilechoo
  • 在reactjs中添加内联样式而不使用JSX

    我正在尝试使用reactjs向元素添加内联样式 我发现 var divStyle color white backgroundImage url imgUrl ReactDOM render div Hello World div moun
  • twitter bootstrap 下拉菜单在应该关闭时没有切换

    天哪 我一直在为这件事抓狂 4个小时的下拉菜单 我正在使用 Twitter Bootstrap 顶部的固定导航有一个下拉菜单 非常标准的东西 只是下拉菜单没有像平常那样关闭 仅当按下切换按钮本身时 它才会打开和关闭 而不是按下菜单中的项目或
  • 在 Outlook 2007 C# 中获取安全发件人列表

    我已经在 C NET 4 0 中创建了 Outlook 2007 加载项 我想读取 C 代码中的安全发件人列表 if oBoxItem is Outlook MailItem Outlook MailItem miEmail Outlook
  • 如何防止c#中对象的实例化

    我需要的是检查传递给构造函数的参数 并防止特定对象的实例化 以防它们被视为无效 我发现可以抛出异常 因此对象引用将按预期以 null 结束 例如 仅当传递给构造函数的整数为非负数时 才会实例化此类 class MyClass public
  • Bootstrap 3 并排容器

    我正在尝试制作一个网页 其中内容的左半部分尊重引导程序 container最大宽度大小 而我的右侧可以一直到页面的末尾 作为 container fluid会工作 像这样的图片 到目前为止 我已经尝试了几种方法 目前我正在使用以下代码 di
  • 如何从 for 循环构建和填充 pandas 数据框? [复制]

    这个问题在这里已经有答案了 这是我正在运行的代码的一个简单示例 我希望将结果放入 pandas 数据帧中 除非有更好的选择 for p in game players passing print p p team p passing att
  • AAD 团体声称某些用户的 JWT 令牌缺失

    我在 AAD 上遇到一些奇怪的行为 用户成功登录后 我们的 API 调用中某些用户收到未经授权的消息 结果发现 JWT 中的声明丢失了 一些用户获得 groups 声明 他所属的所有 groupId 的数组 一些用户获得 hasgroups
  • 如何在命令行中查看 git 存储库中的所有标签[重复]

    这个问题在这里已经有答案了 有类似 git show标签 之类的东西吗 git tag列出存储库中使用的标签 git tag l如果你使用 l您可以通过选项传递搜索模式来过滤掉标签
  • 在 django 中通过变量模型名称访问模型

    我有两个相同的模型 比如说 django 中的 X 和 Y 如下所示 class X models Model con models CharField max length 100 a models ForeignField FOO cl
  • Node/Busboy:获取文件大小

    我使用 Busboy 模块通过下面的 CoffeeScript 代码来解析多部分请求 有时 问题出在 数据 处理程序上 该处理程序针对包含一个文件的请求多次调用 这意味着我需要对每个尺寸进行求和才能得出整个尺寸 此外 文件 处理程序中的文件
  • 如何在 Haskell 中创建通道列表(或数组),如 Go

    我试图将 Haskell 与 Go 进行比较以获得一些并发示例 以下代码是 Go 中使用 Goroutines 和通道的简单映射缩减示例 以下 Go 代码计算平方和 1 2 2 2 3 2 1024 2 为了测试Go和Haskell的性能