轨道
/
Lean
Lean
/
练习
/
并行字母频率
并行字母频率

并行字母频率

中等

说明

使用并行计算统计文本中字母的频率。

并行是指把那些同样可以顺序完成的事情并行地做。一个常见的例子就是统计字母的频率。利用并行计算来算出文本数组中每个字母的总频率。

异步任务

任务是在 Lean 中编写异步代码的主要抽象。 它们很轻量,可以在另一个线程上并行执行,也可以在同一线程上并发执行。

任务可以是纯的,也可以是非纯的。 纯任务用Task.spawn创建,它接受一个纯计算。 非纯任务则由IO计算创建,例如使用IO.asTask,它会在IO单子中把IO α提升为Task α。

在本练习中,函数calculateFrequencies是单子式的,返回一个IO (Std.TreeMap Char Nat)。 这样就可以通过IO.asTask使用非纯任务,也可以在返回最终值之前为中间计算生成纯任务。

防止数据竞争

作为一种函数式语言,Lean 中的大多数值都是持久化的,也就是不可变的。 看似修改某个值的操作,实际上会生成一个包含所需改动的新值。 这意味着内存通常可以在任务之间安全地共享,而不会引入数据竞争。

不过要注意,并非所有数据结构都同样适合持久化使用。 例如,更新Array中的单个元素通常需要复制整个数组。 Std.HashSet和Std.HashMap也是如此。

为了让这类数据结构保持高效,Lean 使用了引用计数。 只要某个值拥有唯一的引用,更新就可以破坏性地执行,避免不必要的复制。

其他数据结构,比如List、Std.TreeSet和Std.TreeMap,则在设计上支持内部结构共享。 执行更新时它们会复用未发生变化的节点,因此多个值可以共享对这些节点的引用。 这样一来,修改结构的某一部分通常不需要复制整个值。 这使得它们特别适合在任务之间共享。

测量执行速度

每个测试的执行时间都用IO.monoNanosNow以纳秒为单位测量,并显示在结果的旁边。 你可以尝试不同的做法,看看它们对运行时性能有什么影响。

通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Lean Exercism

准备好开始 并行字母频率 了吗?

注册 Exercism,借助 100 个练习 和真人导师指导,学习并掌握 Lean,全部免费。

深入探索 并行字母频率!

我们探讨并发与并行之间的区别,并看看 JavaScript、Go、Elixir 和 Rust 等语言采用的不同做法。