写点什么

加入 Transients 和 Chunked Sequences 的 Clojure 1.1 更加高效

  • 2009-12-27
  • 本文字数:2104 字

    阅读完需:约 7 分钟

Clojure 1.1 RC1 已经发布——现在是介绍它的时候了,我们希望能够在最终版发布之前给出一些反馈。这些工作是在 GitHub 的 Clojure 1.1 分支上完成的,现在在 Google Code 上已经可以下载到 Clojure 1.1 RC1 的 Binary Package 了。

1.1 的更新日志列出了和 1.0 的不同点,例如在 1.1 发布之前已经关闭的 issue 。同样也加入了一些新的特性来优化 Clojure 程序的性能。

Transients能够大幅改善构建持久数据结构的性能。持久数据结构是Clojure 非常重要的元素,例如隐藏在Clojure 的Vectors,Maps 和Sets(参考Clojure 创建者 Rich Hickey 关于持久数据结构的介绍)后面的细节和概念。简而言之,持久数据结构是非可变的;要删除或者修改数据的唯一办法就是复制一份此数据结构的副本。但是有一个小技巧:持久数据结构的内部结构以及它的性质(所有元素都是不可变的)允许共享所有的数据和大部分结构,因此创建一个拷贝只需要非常小的开销。

虽然复制副本的开销很小,但是也会有需要插入大量元素的情况出现。Transients也可以解决这种情况。简单来说,这种思想就是在大量修改之前将一个持久数据结构转换为一个 transient;调用 transient 即可完成这个功能。同一数据结构的 transient 版提供了和持久版相同的存取函数,但是对于修改操作来说,这就需要使用后缀为“!”的不同函数了,例如 conj!(而不是 conj)。

理解持久数据结构和他们的 transient 版本的关系的一个好办法是看看 java.lang.String 和 java.lang.StringBuilder 之间的关系;一个是不可变的,当需要修改的时候它会创建一个新的副本,而另一个则允许直接在其上进行修改。

不过它们的相似性也就这些。但是,创建一个 StringBuilder 也就意味着拷贝 String 的内容,一个 O(n)的操作。将持久数据结构转换为等价的 transient 版本的开销却非常小:只是一个 O(1)的操作;它只是创建了一个 transient 的对象,这个对象包括了一个数据结构的根对象,然后还有一个表示其为 transient 的标记;不会有数据复制的行为。一旦数据结构的 transient 版本需要转换为持久版,同样也只需要 O(1)的操作。

但是为什么有时候需要将持久版转回为 transient 版呢?难道不能无限制地使用 transient 吗?当然不能 - transient 版本有一个非常重要的限制:它只能被一个线程使用。原因很简单:因为 transient 是可变的,在不同的线程中使用它将会非常危险的,所以需要同步。而持久数据结构使得在线程间共享数据结构变得非常简单;transient 允许一个线程修改数据结构,然后通过将其转换为持久数据结构置为其他线程可访问。

Chunked Sequences是 Clojure 1.1 中的另外一个优化。快速预览可以看 Rich Hickey 关于 chunked sequence 演讲的幻灯片(PDF 格式)。

chunked sequences 背后的思想即是减少由于(lazy)sequences 引入的开销。

Lazy sequences 在 Clojure 中随处可见,它能够延迟某个任务直到必须要去做的时候。但是在某些情况下,有些任务根本不需要做,例如下列代码:

复制代码
(take 10 (range 1 1000000000000) )

range 创建了一个 lazy sequence,这个 lazy sequence 会预生成好指定范围内的 10 个数。然后,take 会请求 10 次 sequence 来获取生成的数。由于使用 lazy 方法,这只是请求了 10 个数而已,因为预处理,所以总共只需计算 10 个数。

实现使用了 lazy-seq 宏(在 core.clj 中),这样使得代码非常简洁。但是有一个问题:在 lazy sequence 中访问下一个元素可能会有一些数据管理上的开销。Chunked sequences 即是为了减少这样的开销而生的,它将元素划分成多个块并且缓存值;块的大小是 32,也就是说每一步的开销只是限定在 32 个元素之内。

另外一种优化 chunked sequences 的方法是对数据结构内部组织结构分析。例如,一个持久 vector 是以树的形式组织的,在这里面数据保存在 32 个元素数组中。为了访问一个元素,需要遍历这棵树来寻找到元素保存的数组。一个原生的 sequence 使用索引访问下一个元素,这样可能导致每次访问的时候都需要遍历树。chunked sequence 的持久 vector 实现避免了这种情况:它找到 sequence 开始的存储有 32 个元素的数组,然后为每个元素快速建立一个简单索引;只有在 32 个元素都访问之后,才需要取下一个树节点并且开始遍历。

现在就只是看看 chunked sequences 的接受度如何了;它们显然有着很大的优点,但是 Clojure 1.1 更新日志指出:

chunked-seq 的开销和其他 sequence 一样都是完全透明的。但是,注意有些 sequence 一次会处理超过 32 个元素。如果你依赖于完全惰性(full laziness),不希望学习如何生成任何零成本的结果,那么当然可能对你有影响。一个将开销限制在单个元素的 chunked-seq 的接口仍然在设计中,请将 chunked sequence 在实际应用中出现的问题或者行为差异反馈给我们。

当然 Clojure 1.1 还有更多特性仍待介绍,更多信息请参考 Clojure 1.1 更新日志

如果需要更多关于 Clojure 的信息,请点击 InfoQ 的 Clojure 标签。强烈推荐 Rich Hickey 的演讲,例如持久性数据结构和已托管的引用。InfoQ 同样也有在 QCon London 2009 上采访 Rich Hickey 的视频

查看英文原文: Clojure 1.1 Adds Transients, Chunked Sequences for Efficiency

2009-12-27 05:171662
用户头像

发布了 90 篇内容, 共 35.9 次阅读, 收获喜欢 5 次。

关注

评论

发布
暂无评论
发现更多内容

搭建 VuePress 站点必做的 10 个优化

冴羽

JavaScript Vue 前端 vuepress 博客搭建

TDesign Vue Next For Mobile 发布

TDesign

企业知识管理包括哪些内容?

小炮

知识管理 企业

链上智能合约dapp系统开发,TRX波场链系统开发

Geek_232be3

DAPP系统开发 区块链资讯

弹窗如何设计才能提高用户体验

源字节1号

网站开发

WebAssembly技术_在Web端运行C与C++程序(ubuntu18.04)

DS小龙哥

webassembly 3月月更

OpenHarmony 3.1 Beta版本关键特性解析——HAP包安装实现剖析

OpenHarmony开发者

OpenHarmony

第11期直播:解读集群镜像“开箱即用”神器——sealer!

OpenAnolis小助手

技术分享 龙蜥社区 sig 龙蜥大讲堂 集成镜像

web前端培训比较常见的排序算法有哪些

@零度

算法 前端开发

架构实战营-模块一作业

凯博无线

iuap 助力长久汽车打造“业财一体数字智能化平台”

用友BIP

用友 用友iuap

Flutter事件响应源码分析

得物技术

flutter 源码 源码分析 UI 框架

NFT跨链挖矿软件定制,defi质押挖矿dapp平台搭建

Geek_232be3

系统开发、 TFS挖矿 系统开发 区块链资讯

与容器服务 ACK 发行版的深度对话最终弹:如何通过 open-local 玩转容器本地存储

阿里巴巴云原生

java编程开发多线程锁的8个问题分析

编程江湖

重磅发布 丨 阿里云首部 “数智化转型系列丛书”重磅面世!

博文视点Broadview

Digital Twins与物联网的挑战:如何可视化并加速开发

龙智—DevSecOps解决方案

物联网 digital twin 物联网发展

大数据培训hive和mapreduce的区别

@零度

mapreduce hive 大数据开发

grpc双向流究竟是什么情况?2段代码告诉你

华为云开发者联盟

gRPC RPC 消息 grpc双向流 消息序列

面试突击33:线程池有哪些状态?状态是如何转换的?

王磊

java面试

Spark启动及提交流程内部核心原理剖析

编程江湖

Perforce Helix Core与SVN的较量,谁会赢?

龙智—DevSecOps解决方案

svn Subversion helixcore

如何通过 Jira Service Management 打造员工自助服务工具实现高效分布式工作

龙智—DevSecOps解决方案

Atlassian 薪酬估算器 jsm

Node.js-COMMONJS 规范

编程江湖

突破地心引力!与KubeEdge一起迈向太空的云原生

华为云原生团队

开源 边缘计算 卫星定位 边缘技术 边缘云

java培训Spring之AOP的案例分析

@零度

spring JAVA开发 aop

如何写出好的产品帮助文档?

小炮

产品文档

深度解密|基于 eBPF 的 Kubernetes 问题排查全景图发布

阿里巴巴云原生

您有多点会员吗?——数据库渐进式创新助力多点推进经营大脑实践

PingCAP

OpenHarmony 3.1 Beta版本关键特性解析——HiStreamer轻量级可定制的媒体管线框架大揭秘

OpenHarmony开发者

OpenHarmony HiStreamer 媒体管线框架

web技术分享| 快速实现一个呼叫邀请 SDK

anyRTC开发者

前端 Web 语音通话 视频通话 呼叫邀请

加入Transients和Chunked Sequences的Clojure 1.1更加高效_Java_Werner Schuster_InfoQ精选文章