有人可以澄清一下 Joel On Software 引用的意思吗:(功能性程序没有副作用)

2024-04-01

我正在读书乔尔安软件 http://www.joelonsoftware.com/今天又遇到了这个报价 http://www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html:

不了解功能 编程,你不能发明 MapReduce,该算法使得 谷歌的可扩展性如此之大。这 术语“Map”和“Reduce”来自 Lisp 和函数式编程。映射减少 回想起来,对任何人来说都是显而易见的 谁还记得他们的 纯函数式程序具有的 6.001 等效编程类 没有副作用,因此微不足道 可并行化。

当他说函数式程序没有副作用时,他是什么意思?这如何使并行化变得微不足道?


他说的是什么意思 函数式程序没有边 影响?

大多数人认为编程就是创建变量、为其赋值、将内容添加到列表等。变量“变化”,因此得名。

函数式编程是一种消除变量的程序设计风格——一切都是常量或只读。

当 Joel 说函数式程序没有副作用时,涉及到很多挥手的内容,因为编写函数式程序非常容易,do修改变量——但很大程度上,当人们谈论函数式编程时,他们指的是不持有任何可修改状态的程序。

“但是朱丽叶!如果不能,如何编写一个有用的程序?修改任何东西"

好问题!

您可以通过创建具有修改状态的对象的新实例来“修改”事物。例如:

class Customer
{
    public string Id { get; private set; }
    public string Name { get; private set; }

    public Customer(string id, string name)
    {
        this.Id = id;
        this.Name = name;
    }

    public Customer SetName(string name)
    {
        // returns a new customer with the given name
        return new Customer(this.Id, name);
    }
}

因此,所有初始化都在构造函数中进行,并且我们无法再次修改该对象 - 我们将修改传递到构造函数中来创建新实例。

您会惊讶地发现这种编程风格能走多远。

“但是朱丽叶!?这么多的复制怎么可能有效呢?”

诀窍是意识到您不必复制整个对象图,只需复制已更改的部分。如果对象图的某些部分没有更改,可以在新对象中重用它(复制pointer,不要在图表的该部分新建任何对象的新实例)。

您会惊讶地发现这种编程风格能走多远。事实上,其极其轻松编写许多常见数据结构的不可变版本——例如不可变的 Avl 树、红黑树、多种堆等。请参阅here https://stackoverflow.com/questions/2437733/why-is-insertion-into-my-tree-faster-on-sorted-input-than-random-input用于实现不可变陷阱。

在大多数情况下,数据结构的不可变版本与可变版本具有相同的插入/查找/删除计算复杂性。唯一的区别是插入返回数据结构的新版本,而不修改原始数据结构。

这如何实现并行化 琐碎的?

想想看:如果您有一个不可变的树或任何其他数据结构,那么您可以使用两个线程插入、删除和查找树中的项目,而无需锁定。由于树是不可变的,一个线程不可能在另一个线程的鼻子下将对象置于无效状态 - 因此我们消除了与竞争条件相关的一整类多线程错误。由于我们没有竞争条件,因此不需要锁,因此我们还消除了与死锁相关的一整类错误。

因为不可变对象本质上是线程安全的,所以据说它们使并发变得“微不足道”。但这只是故事的一半。那里are有时我们需要一个线程中的更改对另一个线程可见 - 那么我们如何使用不可变对象来做到这一点?

诀窍是重新思考我们的并发模型。我们不是让两个线程彼此共享状态,而是将线程视为一种可以发送和接收消息的邮箱。

因此,如果线程 A 有一个指向线程 B 的指针,它可以将消息(更新后的数据结构)传递给线程 B,线程 B 将其副本与数据结构及其收到的消息中的副本合并。线程也可以通过itself作为消息,线程 A 将自身发送给线程 B,然后线程 B 通过它收到的指针将消息发送回线程 A。

相信我,上面的策略使并发编程比可变状态上的锁容易 1000 倍。因此,Joel 评论的重要部分是:“如果不了解函数式编程,你就无法发明 MapReduce,这种算法使 Google 具有如此大规模的可扩展性。”

传统的锁定不能很好地扩展,因为为了锁定一个对象,您需要对其指针的引用——锁定的对象需要与执行锁定的对象位于同一内存中。您无法跨进程获取对象的锁。

但想一想上面的消息传递模型:线程相互传递两个消息。将消息传递给同一进程中的线程与将消息传递给侦听某个 IP 地址的线程之间真的有区别吗?并不真地。正是因为线程可以跨进程边界发送和接收消息,消息传递才可以扩展,因为它不绑定到一台机器,所以您可以让您的应用程序根据需要在尽可能多的机器上运行。

(无论其价值如何,你can使用可变消息实现消息传递,只是没有人愿意这样做,因为线程在不锁定消息的情况下无法对消息执行任何操作 - 我们已经知道这充满了问题。因此,当您使用消息传递并发时,不可变是默认的方式。)

尽管其水平非常高并且掩盖了许多实际实现细节,但上述原则正是 Google 的 MapReduce 可以无限扩展的方式。

也可以看看:http://www.defmacro.org/ramblings/fp.html http://www.defmacro.org/ramblings/fp.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有人可以澄清一下 Joel On Software 引用的意思吗:(功能性程序没有副作用) 的相关文章

  • 访问Scheme中的调用堆栈深度

    为了演示尾递归的有效性 我想要一种在Scheme中动态访问调用堆栈深度的方法 有没有办法做到这一点 如果没有 有没有办法在其他主要函数语言 OCaml Haskell 等 中做到这一点 Racket 允许您在调用堆栈中存储值 您可以使用它来
  • 更新对象值 Ramda

    在上一个问题中 我尝试按父 ID 对数组进行分组 然后从每个对象中删除它们 按父 ID 对象 Ramda 对数组进行分组 https stackoverflow com q 58682137 9464680 但现在我有一个新问题 例如 我想
  • 移动语义对于 Rust 中的引用透明性意味着什么?

    我正在尝试弄清楚移动语义如何影响引用透明度 参考透明度 https stackoverflow com q 210835 5986907 RT 允许我们用结果替换任何表达式 而不改变程序的含义 释义自 例如 我可以替换1 1我的程序中的任何
  • 将其参数应用于自身的函数?

    考虑以下 SML 函数 fn x gt x x 这会产生以下错误 新泽西州标准 ML v110 72 stdIn 1 9 1 12 Error operator is not a function circularity operator
  • 为什么 OCaml 不允许函数匹配? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 理解 scala 中参与者的线程性

    有人告诉我 Scala Actors 实际上从来不会同时执行两个操作 这表明 act 或 React 或 receive 方法本质上是同步的 我知道 act 方法中的长操作可能会导致阻塞问题 并且我假设对消息队列的访问必须以某种方式同步 但
  • 如何在函数式编程中为AST节点生成稳定的id?

    我想将一个特定的 AST 节点替换为另一个节点 并且这个替换的节点是由交互式用户输入指定的 在非函数式编程中 可以使用可变数据结构 并且每个AST节点都有一个对象引用 因此当我需要引用特定节点时 我可以使用这个引用 但在函数式编程中 使用I
  • 未确定的泛型类型在 ghci 的运行时中如何表示

    我很清楚通用函数和通用数据类型 在泛型类型中 data SB forall x show x gt SB x instance Show SB where show SB x show x 所以对于任何给定类型x 如果它有一个签名Show
  • Erlang 参与者与 OOP 对象有何不同?

    假设我有一个 Erlang actor 定义如下 counter Num gt receive From increment gt From self new value Num 1 counter Num 1 end 同样 我有一个 Ru
  • scalaz 中的 Store 是什么

    我试图理解Lenses in scalaz 令人惊讶的是没有找到类似的东西cats core 我遇到了所谓的Store这是一个类型别名 type StoreT F A B IndexedStoreT F A A B type Indexed
  • 是否可以有效地计算 lambda 演算项?

    我最近用 lambda 演算编写了很多程序 我希望能够实时运行其中一些程序 然而 尽管趋势函数范式基于 lambda 演算和 B 约简规则 但我找不到一个不是玩具 不以效率为目的的评估器 函数式语言应该很快 但我所知道的那些语言实际上并不提
  • 计算 python 字典/数组数据结构的非空尾叶 - 递归算法?

    我正在寻找一个函数来查找一种复杂字典 数组结构的所有非空端点 我认为因为我不知道嵌套数组的数量或它们的位置 所以它必须是递归的 而我只是还没有完全理解这种思维方式 所以对于嵌套字典 x top middle nested value nes
  • 函数式编程是否需要新的命名约定?

    我最近开始使用 Haskell 学习函数式编程 并在 Haskell 官方 wiki 上发现了这篇文章 如何阅读哈斯克尔 http www haskell org haskellwiki How to read Haskell What t
  • 如何在 Perl 中以函数式风格进行编码?

    你如何 have a sub返回一个sub or 将文本作为代码执行 in Perl 另外 如何拥有匿名函数存储状态 子返回子作为coderef example 1 return a sub that is defined inline s
  • F# 编码练习

    我一直在 Visual Studio 2010 中涉足 F 我是一名在 C 和 Java 等面向对象语言方面拥有更多代码 架构设计经验的开发人员 为了扩展我的技能并帮助做出更好的决策 我正在尝试使用不同的语言来做不同的事情 特别是掌握使用函
  • 什么样的函数被认为是“可组合的”?

    维基百科文章函数组合 计算机科学 https en wikipedia org wiki Function composition computer science says 就像数学中通常的函数组合一样 每个函数的结果作为下一个函数的参数
  • “函数是第一等值”这到底是什么意思?

    有人可以用一些很好的例子清楚地解释它吗 在解释函数式编程时 我在 Scala 中遇到了这句话 一流 并不是一个正式定义的概念 但它通常意味着一个实体具有三个属性 有可能used 不受限制 只要 普通 值可以 即从函数传递和返回 放入容器等
  • Haskell 入门

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 几天来 我一直试图理解 Haskell 中的函数式编程范例 我通过阅读教程和观看截屏视频
  • 正确使用术语 Monoid

    从下面的例子来看 我认为这样的说法是正确的String在串联运算下定义了一个幺半群 因为它是关联二元运算 并且String碰巧有一个身份元素 它是一个空字符串 scala gt Jane Doe Jane Doe res0 Boolean
  • 在管道中重用变量的功能方式

    在 javascript 和 typescript 中与 Ramda 一起使用函数式编程 我经常发现自己编写如下代码 const myFun c gt const myId c id const value pipe getAnotherO

随机推荐

  • 在 Android 中检测传入电子邮件通知

    android 中有传入电子邮件时我们可以检测到通知吗 有什么解决方案 教程或示例代码我可以尝试吗 Thanks 尝试实现NotificationListenerService 这是官方文档https developer android c
  • 我应该在将模型导入 Unity 之前在 Blender 中烘焙模型吗?

    正如标题所示 何时为 Blender 模型烘焙纹理以在手机游戏中使用它很重要 烘焙对性能有何好处 如果我没有烘烤它并且直接在游戏中的模型上使用纹理 会有什么问题吗 有Unity中的烘焙和blender中的烘焙 您的问题似乎是关于在将模型导入
  • MS Chart控件缩放MinSize问题

    我正在使用 MS Chart Control NET 3 5 WinForms C 实现散点图 我的 x 轴数据是 DateTime 并注意到我无法放大小于 1 天的分辨率 尽管按如下方式设置 ScaleView chart1 ChartA
  • 熊猫连接失败

    我正在尝试连接以下两个 csv 文件中的数据帧 df a https www dropbox com s slcu7o7yyottujl df current csv dl 0 df b https www dropbox com s la
  • 如何从文件字节开始在内存中创建 zip 文件?

    我尝试使用 C 在内存中创建一个 zip 文件 但结果是一个 zip 文件 其中包含损坏的文件 所有要压缩的文件都在数据库中 我存储字节 文件为 PDF 格式 我的代码如下 extract bytes and file name for e
  • Notification.addAction 在 Android O 中不起作用

    下面提到的代码适用于 Android O 版本以下的所有设备 对于安卓O addAction 方法不起作用 即按钮单击在 android O 中不起作用 任何帮助 将不胜感激 NotificationManager notification
  • MVC 自定义 ViewModel 和自动绑定

    我有一个自定义 ViewModel 定义为 public class SampleFormViewModel public SampleFormViewModel SelectList companies Widget widget Com
  • 为 iOS7 编译 PJSIP

    我正在尝试在 Mac 10 9 Xcode 5 0 上编译适用于 iOS 的 PJSIP2 1 0 但是我运行时遇到一些错误 configure iphone 以下是错误 configure iphone DEVPATH is not sp
  • Java正则表达式和转义元字符

    我正在尝试编写正则表达式来匹配嵌入在两个大括号之间的标记 例如 如果缓冲区Hello World 我想从字符串中获取 World 令牌 当我使用正则表达式时 eclipse 显示错误消息为 无效的转义序列 有效的是 b t n f r 谁能
  • 是否可以远程托管 Android 应用程序中使用的资源,使其只能由我的应用程序使用?

    基本上我想要实现的是托管一个 CSV 文件 我的应用程序将检索该文件并将其用作数据源来填充一些表 CSV 将使用最新数据进行更新 我预计应用程序会经常获取最新版本 以确保其中的数据是最新的 我的问题是是否可以确保此远程 CSV 资源仅由我的
  • PHP:我应该如何转义将进入 Javascript 字符串的字符串?

    我应该如何转义将要进入 Javascript 字符串的字符串 URL 编码 X str replace X use json encode 所以你可以做 page params array user logged in gt suer gt
  • 如何在另一个 Perl 脚本中使用变量?

    我知道如何在 Perl 中使用一个包到另一个包的变量 我正在尝试使用声明的全局变量test1 pl在另一个 Perl 脚本中test2 pl 我在用require加载 perl 文件 usr bin perl test1 pl use st
  • 使用 jquery .html() 插入 html

    我想将一大块 html 插入到预先存在的 td 我正在使用这个方法 td content html LOTS OF HTML CODE HERE 但这不起作用 我是菜鸟 有很多引用和 HTML 块内似乎破坏了它 这样做的正确方法是什么 我建
  • 为什么局部变量或临时变量的返回地址只是警告而不是错误?

    刚刚收到编译器针对此函数的警告 template
  • hapi.js - 404 路由 VS 静态文件路由

    我正在尝试将 Express 应用程序迁移到 hapi js 但我的路线遇到了问题 我只想要 2 GET 我的索引 以及所有不是 的内容重定向到 使用 Express 我有这个 static files app use express st
  • 没有这样的模块 JSQMessagesViewController

    我正在尝试导入 JSQMessagesViewController import JSQMessagesViewController 它给了我错误 没有这样的模块 我在网上看到很多人遇到这个问题 但我找不到解决方案 这是我的 Podfile
  • 如何从颜色推断形状的状态

    我已经形成了乐高立方体4x4形状 我试图推断图像内区域的状态 空 满以及颜色是黄色还是蓝色 为了简化我的工作 我添加了红色标记定义border由于相机有时会晃动 因此形状会受到影响 这是我试图检测的形状的清晰图像 由手机摄像头拍摄 编辑 请
  • Phonegap - 在启用自动方向的同时防止旋转?

    我正在重新发布我在 Google 群组中找到的其他人的问题 我也遇到了类似的问题 我有一个应用程序 要求所有内容都处于纵向 除了播放视频时 在 iOS 上 当视频播放传递到 Quicktime 播放器时 我希望视频能够以横向模式播放 目前
  • 获取正确的月份格式日期java

    有什么帮助吗 如何从 2014 01 10T09 41 16 000 0000 这样的字符串中获取正确的日期 我的代码是 String strDate 2014 01 10T09 41 16 000 0000 String day Stri
  • 有人可以澄清一下 Joel On Software 引用的意思吗:(功能性程序没有副作用)

    我正在读书乔尔安软件 http www joelonsoftware com 今天又遇到了这个报价 http www joelonsoftware com articles ThePerilsofJavaSchools html 不了解功能