函数式编程语言天生就慢吗?

摘要:近期,函数式编程得到了越来越多的关注,Lisp不仅重获青春还涌现出了一批新函数式编程语言。因此开发者们对函数式编程语言的运行快慢各抒己见,展开激烈讨论。本文将和大家一起讨论,函数式编程语言真的就慢吗?

由于函数式语言需要基础架构支持,这样不可避免地增加了学习汇编理论知识的成本。一流的词法闭包只有在配合垃圾回收时才能良好地工作,因为它允许值越界。

函数式语言:过度分配

请注意自己的选择。C在基准套件中扮演最小公分母,限制是可以实现的。如果在比较C语言与函数式编程语言上有一个基准,那么它肯定是一个非常简单的程序。按理说这么简单,它是没有什么实际意义的。仅仅把C作为基准的话,那么在解决更复杂的问题上,它是没有什么实际可行的解决方案。

这方面最明显的例子就是并行性。如今,多核已成为一种主流,甚至连我的手机也是多核的。在C语言中,要想实现多核并行是相当困难的,但是在函数式编程语言中会却容易实现(我比较喜欢F#)。其它例子还包括持久化数据结构,例如撤消缓冲区与纯函数数据结构是微不足道的,但在命令式语言上,这却是个非常大的工作量。

函数式语言看起来比C语言要慢,因为你仅看到基准代码在C语言里很容易去编写并且你永远不会明白基准比任务更耐人寻味,从函数式语言到Excel。然而,目前你已经能正确的识别出函数式语言的最大瓶颈是什么:过度的分配率。为什么函数式语言分配会如此严重的原因就是它被拆分成历史和内在的。

从历史上看,Lisp实现已经做了50年的装箱工作。这个特点也渗透到许多其它编程语言中,类似Lisp的中间件表示。这些年来,语言实现不断地采取装箱这种方式快速实现并发。在面向对象语言中,默认堆分配每个对象,即使明显可以采用堆栈分配。提高效率的负担是推到垃圾收集器并且在建设垃圾收集器性能上做一些努力,使它能够达到或者最大可能接近堆栈分配,通常是使用bump-allocating托管实现。我认为,应该投入更多的精力来研究函数语言设计,减少装箱和垃圾收集器设计,从而优化不同的需求。

分代式垃圾收集器

分代式垃圾收集器对语言来说,是很棒的,因为堆可以分配很多并且他们的速度也和堆栈分配差不多一样快,但是会增加其他地方的开销。如今的程序越来越多地使用像队列似地的数据结构(例如并发编程)并且让分代式垃圾收集产生一些病态行为。如果队列中的某项活得比第一代长,那么它们都会被做标记,然后所有引用的旧位置将会得到更新并且被收藏。这个大概要比它们需要的慢3倍(例如比C语言)。标记区域的收集器有可能解决这个问题,像Belway(2002)和Lmmix(2008),因为托管已经被替换成一个区域,可以被收集,就好像是一个托管所,如果它包含大部分可及值,可以被另一个区域替换并且留下时间,直到它包含一些遥不可及的值。

尽管已经存在的C++,还有Java的发明人采用泛型来消除这些错误,但这些都导致了不必要的装箱。例如,我构建一个简单的哈希表,在.NET上面的速度比JVM要快17倍。原因就是.NET并没有犯这个错误(它采用具体化泛型)并且.NET还有值类型。实际上,我认为是Lisp让Java变慢。

装箱、拆箱

所有现代式的函数式语言都是过分依赖装箱。基于JVM语言,像Clojure和Scala别无选择,因为VM甚至不能表达值类型。Ocaml(Objective Caml)在早期就揭示了类型信息,在它的编译过程和经常使用整数类型进行装箱标记并且在运行时去处理多态性。因此,Ocaml常常作为私有浮点数字被装入箱中并且一直是盒元组。在Ocaml中一个三重的字节就是一个由指针(有一个隐藏的标签嵌入在里面并且在运行时会被反复检查)和一个64位的堆上分配块头与192位的主体包含三个标记的63字节整数(3个标签,在运行时会被反复检查)。这显然是疯了。

在函数式语言上,有关拆箱优化工作已经完成但它并未真正获得牵引力。例如Mlton编译器对于ML标准来说,是一个全程序优化编译器并且很擅长拆箱优化工作。不幸的是,在运行时间之前和“长”编译时间(在现代机器上低于1秒)阻止人们使用它。

唯一的主要平台已经打破了这个趋势,但令人惊讶的是.NET却是个例外。尽管有一个Dictionary类可以高度优化键和值。微软的员工,比如Eric Lippert就继续强调值类型是根据值进行传递的,这一点很重要并且性能特点不是来源于它们内部拆箱特征。Eric的理解似乎已经被证明是错误的:越来越多的.NET程序员青睐拆箱而不是值传递。事实上,大多数结构是不可变的,因此,引用透明在值传递和引用传递之间并没有什么语义差别。性能是可见的并且结构可以提供大量的性能改进。性能结构甚至可以保存堆栈溢出并且结构常常用来避免GC延迟在商业软件上面,比如Rapid Addition's。

函数式与命令式

重分配的函数式语言的另一个原因是与生俱来的。命令式数据结构像哈希表结构使用内在巨大的整体数组。如果这些巨大的内部数组一直持续使用,将需要不断复制和更新。所以纯函数式数据结构比如平衡二叉树分裂成许多小堆,分裂成块为了便于从一个版本集合到另一个版本。

Clojure采用了一个非常巧妙的花招来解决这个问题,当集合例如dictionaries在初始化时被写,然后进行读取。在这个例子中,初始化可以使用突变来建立“幕后”结构。然而,这并不会有助于增量更新并且由此产生的集合在读取数据方面仍然比较命令式等价物慢。当然纯函数式语言在数据持久化方面明显要比命令式强。然后,很少的实际应用程序受益于持久化实践,所以这并不算是什么优势。因此,把非纯函数式语言降到命令式风格,这样就可以毫不费力的从总受益。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/450776.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【老杜】MySQL—day02

文章目录day02课堂笔记1、把查询结果去除重复记录【distinct】10、连接查询10.1、什么是连接查询?10.2、连接查询的分类?10.3、当两张表进行连接查询时,没有任何条件的限制会发生什么现象?10.4、怎么避免笛卡尔积现象?…

vue根据数组对象中某个唯一标识去重

由于在vue中,会自动在数组和对象中加入_obser__观察者模式的一些属性,所以直接用数组的filter去重(下面这种),indexOf不能准确识别 var arr [1, 2, 2, 3, 4, 5, 5, 6, 7, 7]; var arr2 arr.filter(function(x, index…

Springsecurity之AuthenticationProvider

2019独角兽企业重金招聘Python工程师标准>>> 注意:AuthenticationProvider与Authentication紧密联系,关于Authentication,看我的这篇博客。 先上一张图,如下图1 图1 AuthenticationProvider的类图 AuthenticationProvi…

Postman使用入门

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 Postman测试管理的单位是测试集(Collections),测试集内可以创建文件夹(Folder)和具体的请求(Requests…

编程需要知道多少数学知识?

摘要:许多人认为在开始学习编程之前必须对数学很在行或者数学分数很高。但一个人为了编程的话,需要学习多少数学呢? 实际上不需要很多 。这篇文章中我会深入探讨编程中所需要的数学知识。 下面是我在reddit的子论坛 r/learnprogramming 看到的…

HDU 6071 Lazy Running

链接HDU 6071 Lazy Running 给出四个点1,2,3,4,1和2,2和3,3和4,4和1之间有路相连,现在从2点出发,最后回到2点,要求路径大于等于\(K\),问路径长度最…

vue弹窗插件实战

vue做移动端经常碰到弹窗的需求, 这里写一个功能简单的vue弹窗 popup.vue <template><div class"popup-wrapper" v-show"visible" click"hide"><div class"popup-text">{{text}}</div></div> </temp…

【狂神说】Redis笔记

文章目录1、Nosql概述1.1 为什么要用Nosql1.2 什么是NoSQL1.3 阿里巴巴演进分析2、NoSQL的四大分类3、Redis入门3.1 概述3.2 Windows安装3.3 Linux安装3.4 测试性能3.5 基础的知识4、五大数据类型4.1 Redis-Key4.2 String&#xff08;字符串&#xff09;4.3 List&#xff08;列…

Postman用法说明

见&#xff1a;http://blog.csdn.net/flowerspring/article/details/52774399 Postman用法简介-Http请求模拟工具 在我们平时开发中&#xff0c;特别是需要与接口打交道时&#xff0c;无论是写接口还是用接口&#xff0c;拿到接口后肯定都得提前测试一下&#xff0c;这样的话就…

位、字,字节与KB的关系?

位&#xff1a;我们常说的bit&#xff0c;位就是传说中提到的计算机中的最小数据单位&#xff1a;说白了就是0或者1&#xff1b;计算机内存中的存储都是01这两个东西。 字节&#xff1a;英文单词&#xff1a;&#xff08;byte&#xff09;&#xff0c;byte是存储空间的基本计量…

C++ string 介绍

之所以抛弃char *的字符串而选用C标准程序库中的string类&#xff0c;是因为他和前者比较起来&#xff0c;不必担心内存是否足够、字符串长度等等&#xff0c;而且作为一个类出现&#xff0c;他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。我们可以用 进行赋…

Linux核心总结

文章目录1.首先了解一下linux的目录结构2.linux的基本命令之使用命令开关机3.linux的基本命令之目录管理1.ls—列出目录命令2.cd—切换目录命令3.pwd—查看当前所在目录命令4.mkdir—创建文件夹命令5.rmdir—删除文件夹命令6.cp—复制文件命令7.rm—传说中的删库跑路命令8.mv—…

Java多线程系列---“JUC锁”01之 框架

本章&#xff0c;我们介绍锁的架构&#xff1b;后面的章节将会对它们逐个进行分析介绍。目录如下&#xff1a; 01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock06. Java多线程系列--“JUC锁”03之 Condition条件07. Java多线程系…

IDEA配置jdk (SDK)

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 提前安装jdk&#xff0c;配置环境变量 一、配置jdk 1、依次点开File -->Project Structure&#xff0c;点击左侧标签页&#xff0c…

C、C++函数集 说明

第1章 数学函数 1.1 _chgsign——求参数的相反数 1.2 _copysign——复制数据 1.3 _hypot——求直角三角形斜边长度 1.4 _max——求两个数中的大数 1.5 _min——求两个数中的小数 1.6 _scalb——求参数的(2^exp)倍数 1.7 abs——求整数的绝对值 1.8 acos——求…

读书印记 - 《创新者的解答》

虽然作者写书的意图是教会大家如何完成颠覆式创新&#xff0c;但看完全书之后我觉得这个目标远未达成&#xff0c;原因是作者的分析过于理论化&#xff0c;书中对于手机企业的发展建议即已被时间所否定。但如果标准放低&#xff0c;那这本书也确实总结出了不错的颠覆式创新管理…

MinGW下编译ffmpeg静态库给Visual C++使用

首先推荐 http://ffmpeg.zeranoe.com/builds/, 这里已经有编译好的动态连接库。可惜上面没静态链接库。我也试过 DLL2Lib, 但是无法连接LIBCMT库,只能使用MSVCRT 所以一定要静态库的话只能自己编译了。在Windows上用MinGW编译真是个痛苦的过程&#xff0c;没有yum install和ap…

元模型是什么

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 元模型 元模型&#xff0c;是特定领域的模型&#xff0c;用于创建该领域中的模型的构建元素。典型的元模型结构可以分为四种&#xff1a;…

使用 NodeJS+Express+MySQL 实现简单的增删改查

关于node.js暂时记录如下&#xff0c;以后有时间一定学习 文章来自简书&#xff0c;作者&#xff1a;sprint&#xff0c;2016-07 使用 Node.js ExpressMySQL 实现简单的增删改查 https://www.jianshu.com/p/0a161f341771 使用 Node.js Express 开发服务端 https://www.jiansh…

zabbix安装过程

安装了两天&#xff0c;zabbix监控服务器终于搭建好了。搭建过程中遇到过很多问题&#xff0c;都逐一解决了&#xff0c;好在有强大的网络搜索&#xff0c;和网络上牛人的优秀博客&#xff0c;让我能够不断的解决问题。之前在虚拟机上装过&#xff0c;觉得应该很简单&#xff0…