函數式編程語言天生就慢嗎?

摘要:近期,函數式編程得到了越來越多的關注,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.pswp.cn/news/450776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/450776.shtml
英文地址,請注明出處:http://en.pswp.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…