返回介绍

附一:主要编程范式 及其语言特性关系

发布于 2024-12-15 23:02:01 字数 2254 浏览 0 评论 0 收藏 0

节选自博客文章“‘主要的编程范式’及其语言特性关系”(2009 年 10 月)。文章对 Peter Van Roy 的“主要编程范式”一图进行了解读,Peter Van Roy 的原文参见: www.info.ucl.ac.be/~pvr/paradigms.html

【一】

Peter 将一个最重要的概念“state”引入进来。而这个 state 也是 Peter 对语言进行分类并考察其变化的主要依据。但 Peter 所使用的 state 概念以及专用名词“cells”都相当地令人困惑。所以在这个图的补充说明中,Peter 对此专门做了解释:“状态是记忆信息的一种能力,更精确地说,是及时存贮值序列的能力。”

你觉得这个概念像什么?对了,的确,非常像是“变量”。事实上,状态在编程核心概念的“数据逻辑”抽象中,表明的正是“数据的可变性”。也就是说,数据的可变性表现为状态。更进一步地,当数据被命名时,它称为变量或常量;当数据未被命名时,它成为游离的、无名称的、时序含义的存储单元,即“cells”。这也是 Peter 使用“cells”这个专用名词的原因:在本图的讨论中,需要从“变量/常量”这样的概念中,剥离掉“未命名或命名的、确定的或非确定的,以及串行的或并发的”这三个方面的性质。

当不考虑一个存储位置上的命名特性时,它就既非变量或常量,也非某个确定的运算对象(例如“对象”等高级的抽象概念),而只是一种更加泛义的“状态”;同时存储这个状态本身的事物,由于没有位置、时序等概念,所以被称为“cells”。

【二】

《程序设计语言:实践之路》这本书解释过命令式语言的本质特性,即用算法改变数据。如果用两个以上的逻辑(例如两行代码)去影响同一个存储位置(cells),使它的状态改变,并最终在该 cell 产生运算结果,那么它就是一种命令式语言。

再简单一点(但没有上面这样严谨)地说:在程序中不断地重写变量,变量值即是程序的最终结果。所以在本图中,Peter 把这个衍生关系表达为:命令式 = 纯数据 + 算法 + 状态维护。

无论是在串行还是在并发的编程中,命令式编程范式对“状态”的理解都是:共享状态。在串行(例如单线程)的编程中,状态是时序相关的。因为不断地重写“状态(数据/cells/变量)”,所以前一行和后一行所面对都是同一个共享状态的不同的值/副本。在这个过程中,正因为状态与时序相关,所以前一分钟与后一分钟的状态是不确定的。但是在同一时刻,这个状态是确定的。

与上面相类似地,在多线程中,同一时刻,不同线程也将面临这个值/副本。但正是因为多线程(并发)中,线程 A 与线程 B 对于同一个 cell,在同一时刻所得到的状态也是不确定的——我们可以假想为多核 CPU 在对同一个内存地址读写(于是就出现了我们所谓的“同步”问题,进而也就出现了“锁”的问题)。所以在这个分支中,当加入“线程”概念之后,新的编程范式全都变成了“可观测的非确定性”为“yes”的情况。

【三】

我们显然可以发现,问题出在由于多个线程都在“写 cell”。在命令式的解决方案中,采用的方法是“加锁”;持锁存取的最经济的方法之一是“多读单写”,即保证同时只有一个线程能“写 cell”。

但是这给应用带来了负担。如果一个应用程序有多个线程(分布或不分布在多个 CPU 核上),在它们都要读取同一个 cell 而又有某个线程要写该 cell 时,那么大家就都要被挂起来,直到这个写操作完成。整个应用程序在 CPU 使用(或者说效率)上就大大打了折扣。

如果这只是一个桌面程序(例如记事本),大概没人会说什么。但如果这是个服务器程序(例如 WWW Service),那么整个网络、所有的会话就都处于等待状态了,但同时,服务器的 CPU 占用可能会远远小于 1%!

解决问题的终极方法,就是不解决这个问题。既然写 cell 带来了问题,那么我们就“不写 cell”。我们由前面所有讲述的内容开始倒推,问题根本是由“命令式语言”这个编程范式本身决定的:用算法改变数据。

所以我们回到了原始的问题:如果算法不改变 cells(数据/状态/变量)呢?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文