我听到并接受了这样的说法,即突变和状态不利于并发。但是我很难理解什么是正确的替代品?
例如,当您查看所有最简单的任务时:计数,例如大量文档中的单词计数。访问和解析文档需要花费一些时间,因此我们希望使用k个线程或actor或任何抽象的并行性并行进行处理。
使用不可变数据结构执行此操作的正确但又实用的纯功能方法是什么?
答案 0 :(得分:2)
以功能性方式分析数据集的一般方法是以某种有意义的方式对数据集进行分区,对于文档,您可以根据大小将其划分为多个部分。即四个线程意味着该文档被分为四部分。
然后,线程或进程在数据集的每个部分上执行其算法,并生成输出。将所有输出汇总在一起,然后合并。例如,对于单词计数,按单词对单词计数的集合进行排序,然后使用查找相同的单词逐步遍历每个列表。如果该单词出现在多个列表中,那么将对计数进行求和。最后,输出包含所有单词的总和的新列表。
这种方法通常称为map / reduce。将文档转换为字数的步骤是“映射”,而输出的汇总则是“减少”。
除了消除开销以防止数据冲突的优点外,功能方法还使编译器可以优化为更快的方法。并非所有的语言和编译器都这样做,但是由于编译器知道外部变量不会修改其变量,因此可以对代码进行转换以提高其性能。
此外,函数式编程使Spark等系统可以动态创建线程,因为可以清楚地定义更改的边界。这就是为什么您可以在Spark中编写单个功能链,然后在不更改代码的情况下直接向其抛出服务器的原因。纯函数语言可以以一般的方式做到这一点,从而使每个应用程序本质上都是多线程的。
函数式编程之所以“热”是原因之一,就是它具有透明,安全地启用多处理的功能。
答案 1 :(得分:1)
仅当可变状态在多个线程之间共享以进行通信时,突变和状态才不利于并发,因为很难论证不纯净的函数和方法会无声地并行浪费一些共享内存。
一个可能的选择是使用消息传递在线程/参与者之间进行通信(如Akka所做的那样),并在其之上构建(“合理地纯”)功能数据分析框架,例如Apache Spark。众所周知,Apache Spark非常适合对大量文档中的单词进行计数。