Clojure,这是什么鬼?一门基于JVM(现在也有基于.NET CLR的了:Clojure CLR) 的函数式编程语言。在JVM平台运行的时候,会被编译为JVM的字节码进行运算。。为什么要学它?其设计思想独特。有何先进独特之处?后面我会讲。

说实话,现在编程语言满天飞,哥也只是玩过C/C++/Basic/C#/javascript/Java/Python,,哥最喜欢的语言么?看平台了。Windows是C#,跨平台Java,脚本Python。其它的,比如: “最纯的函数式语言”Haskell、“天生擅长高并发的”Erlang,“当红辣子鸡的并发语言”Go,“上手最快的高并发语言”Node,“简约而不简单”的Scala.....,这些都是很棒的语言。哥今天来学一门独特的语言Clojure,首先因为它是LISP —— 一门富有传奇色彩的语言,其次,它小巧、简洁、稳定,是非常酷的语言,既继承了lisp的优美,也保留了java的实效,还具有高并发的特性。而且有个有名的应用实例,那就是Twitter Storm流式计算框架——开源实时Hadoop,是用Clojure语言写的。拿来玩玩,不选它选谁呢?

环境安装

哥今天是在一台win7的笔记本上来安装的(mac的兄弟此处可以鄙视我~),首先机器要安装好JDK7和maven并已配置好环境变量,然后Google搜索“clojure install”,下载与安装leiningen(这是什么鬼?Clojure的项目构建工具,可以自动给你搞定clojure项目打包依赖),设置环境变量,最后是安装IDE插件,例如:Emacs、Eclipse(至少Kepler)。OK,搞定!

使用 immutable 数据

这是Clojure在理念上与我们平常的Java或c#最大的区别,即使用不可改变的值,这儿的值可以是数字、字符串、向量、映射或集合。一旦创建,值不可改变。Clojure不是让“内存变量”的内容可变,而是让符号绑定到不同的不可变值上。

例如:( def hello ( fn [] "Hello, world!" ) )

这段Clojure代码把标识符hello绑定了一个值,这个值是一个函数(函数式编程意味着函数是一个值): (fn [] "Hello, world!"),不带参数,输出"Hello, workld!"。我们运行一下:(hello),输出Hello, workld!

现在我们让它重新绑定另外一个值:( defn hello ( fn [] "Get shit done!" ) )

这段Clojure代码把标识符hello绑定了另外一个值,这个值是一个函数: (fn [] "Get shit donw!"),不带参数,输出"Get shit done!"。

注意:与java等的变量赋值相比,区别是一个是变量内容变了,一个是值一旦创建,不可改变,符号重新绑定是指在不同时期指向不同的值。

使用 immutable 数据的好处是什么?区分identity和value,value不可变,给identity赋值新的value时都要经过语言内制定的function,由语言来保证一致性,让编写并发程序变得容易。这个并发的特性后面会讲到。

闭包(closure)

闭包是函数式编程中非常重要的特性,Clojure的闭包很类似javascript的闭包,举个栗子:

(defn double-op

  [f]

  (fn [& args]

    (* 2 ( apply f args ))) )

(def double-add (double-op +))

上面代码的详细解释:第一行定义一个名为“double-op”函数,这个函数用一个形参f。这个形参f应该是一个函数,因为我们的函数体是一个用fn(fn是一个宏,可以理解为宏也是一种能够动态生成函数的方式,且功能上强大很多)定义的匿名函数。这个匿名函数可以接受一或者多个参数(形参名字args前的“&”表明了这一点)。这个匿名函数会通过传入的实参(也就是f的值)而完整化,并作为函数“double-op”的返回值。函数apply会将第一个实参(一般为一个函数)作用于其余的实参之上,也就是说调用第一个实参代表的函数,并将其余的实参作为其参数传入。使用apply的好处在于不必立刻在代码中填入传入“其余的实参”,而可以用引用名代替。这时,这些“其余的实参”可以被叫做预参数。倒数第二行代码定义了一个名为“double-add”的引用,这个引用返回一个函数。这个返回的函数是通过向函数“double-op”传入函数“+”而完整化后得出的。换句话说,我们在这里定义了一个名为“double-add”的函数。调用方法是:(double-add 5 6),输出 22(把所有“其余的参数”相加并乘以2)。

并发(Concurrency)

 

Java的状态模型从根本上来说是基于状态可变思想的,这直接导致并发代码的安全问题,所以OOP的java的并发编程非常复杂,只能靠悲观锁(locking),或CAS来解决。当然,OOP的真正优势在于对现实世界的建模,而不是数据处理。我们应该辩证的看待不同范式的编程语言,死磕一个必然会使思想禁锢,甚至编程灵感尽失。回到正题,Clojure的指导思想是把线程彼此隔开来实现线程安全,开发人员不用care线程调度,让Clojure来管理线程池。假设“没有共享资源”的基线和采用不可变值使Clojure避开了很多Java面临的问题。举例来说,Clojure的Ref并发模型使用STM机制,该模型在符号和值之间引入了一个额外的中间层,符号绑定到值的引用上,而不是直接绑定到值上,这个系统是事务化的,由Clojure运行时来进行协调,开发人员无需担忧任何锁问题。

STM机制比较抽象,举个栗子吧:银行转账的时候,客户的银行余额显然应该是可变的,而且肯定会有多个线程会对这个余额进行读写,Clojure对于这种情况提供了软件事务内存(Software Transactional Memory -- STM),STM的作用简单点说就是我们无法直接对状态进行读写, STM代理了我们对于状态的所有读写,当我们说要一个状态进行修改的时候,STM充当了余额状态与值的中间层 -- 也就是说多线程之间的协调由STM帮我们搞定了,自然不会有问题了。

以上是对STM的粗略解释,要深入研究建议去阅读R. Mark Volkmann的论文《Software Transactional Memory》。

下面是使用ref的一段代码,不解释了,自己去玩吧:

(import ' (java.util.concurrent Executors) )

;;(test-stm 10 10 10000)

;;-> (550000 550000 550000 550000 550000 550000 550000 550000 550000 550000)

(defn test-stm [nitems nthreads niters]

  (let [refs (map ref ( repeat nitems 0 ))

    pool (Executors/newFixedThreadPool nthreads )

      tasks (map (fn [t]

      (fn []

        (dotimes [n niters]

          (dosync

            (doseq [r refs]

              (alter r + 1 t ))) )))

      (range nthreads ))]

  (doseq [future (.invokeAll pool tasks)]

    (.get future) )  

  (.shutdown pool)

(map deref refs)) )

可以看到比起冗长的Java,Clojure的语法非常简练,封装的很好,既继承了lisp的优美,也保留了java的实效,还具有高并发的特性。

CPU/网络I/O高并发

 

现在所谓的“高并发”很多是指网络I/O高并发,具体来说指的是单进程接受多少多少个连接,例如:Node.JS实现了这个,可以用很少的资源吃满I/O,这里的资源的重点自然是指内存和CPU。而Clojure的高并发完全不是指的这个,Clojure的STM高并发指的是CPU密集型的高并发,不是网络I/O, 这点不要搞错了。其网络I/O高并发完全依赖JVM,或是其他的NIO框架比如Netty或Mina什么的,所以Clojure 提供了相对更为正交的功能集合(STM,并发支持,独立的异步 I/O 库)

原文:Clojure上手

原文发布与微信公众号 rayisthinking

Clojure上手的更多相关文章

  1. 我的Emacs折腾经验谈(二) Emacs上手难的原因

    既然之前说过要写我怎么继续折腾Emacs的,过了一个星期这里就是第二篇了,突然觉得我把blog这样分节不是很好,每次可能要凑一些东西才有该有的篇幅,而且说的东西可能东一点西一点,这样一篇看下来不利于检 ...

  2. Clojure基础课程2-Clojure中的数据长啥样?

    本文来自网易云社区 作者:李诺 " Clojure is elegant and pragmatic; it helps me focus more on solving business ...

  3. JavaScript之父Brendan Eich,Clojure 创建者Rich Hickey,Python创建者Van Rossum等编程大牛对程序员的职业建议

    软件开发是现时很火的职业.据美国劳动局发布的一项统计数据显示,从2014年至2024年,美国就业市场对开发人员的需求量将增长17%,而这个增长率比起所有职业的平均需求量高出了7%.很多人年轻人会选择编 ...

  4. 【Python五篇慢慢弹】快速上手学python

    快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...

  5. Impress.js上手 - 抛开PPT、制作Web 3D幻灯片放映

    前言: 如果你已经厌倦了使用PPT设置路径.设置时间.设置动画方式来制作动画特效.那么Impress.js将是你一个非常好的选择. 用它制作的PPT将更加直观.效果也是嗷嗷美观的. 当然,如果用它来装 ...

  6. ECharts数据图表系统? 5分钟上手!

    目录: 前言 简介 方法一:模块化单文件引入(推荐) 方法二:标签式单文件引入 [前言] 最近在捣鼓各种插件各种框架,发现这个ECharts还是比较不错的,文档也挺全的,还是中文的,给大家推荐一下. ...

  7. 快速上手Unity原生Json库

    现在新版的Unity(印象中是从5.3开始)已经提供了原生的Json库,以前一直使用LitJson,研究了一下Unity用的JsonUtility工具类的使用,发现使用还挺方便的,所以打算把项目中的J ...

  8. Masonry介绍与使用实践:快速上手Autolayout

    1 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-iphone3gs时代 w ...

  9. [译]:Xamarin.Android开发入门——Hello,Android Multiscreen快速上手

    原文链接:Hello, Android Multiscreen Quickstart. 译文链接:Hello,Android Multiscreen快速上手 本部分介绍利用Xamarin.Androi ...

随机推荐

  1. 用PHP将Unicode 转化为UTF-8

    function unescape($str) { $str = rawurldecode($str); preg_match_all("/(?:%u.{4})|&#x.{4};|& ...

  2. Slave failed to initialize relay log info structure from the repository

    现象 查看slave 服务状态 show slave status\G; 错误 Last_Errno: 1872 Last_Error: Slave failed to initialize rela ...

  3. 用sql从一张表更新数据到另外一张表(多表数据迁移)

    update TBL_1 A, TBL_2 B, TBL_3 Cset a.email=c.email_addrwhere a.user_id=b.user_id and b.un_id=c.un_i ...

  4. POJ1222_EXTENDED LIGHTS OUT

    给出5*6的位置,每个位置有一个灯,一开始每个灯有各自的状态,你可以选定一些位置使得所有与这个位置相邻以及位置本身的灯都取反. 输出合法方案. 本来是找高斯消元找到这个题目的,可是....我发现可以直 ...

  5. Jade之Code

    Code jade支持内嵌js的代码到jade代码之中. Unbuffered Code 无缓冲代码以-符号开始,无任何额外输出(文本是什么即是什么). jade: - for (var x = 0; ...

  6. js 根据年月获取当月有多少天_js获取农历日期_及Js其它常用有用函数

    //根据年月获取当月有多少天 function getDaysInMonth(year, month) { debugger; //parseInt(number,type)这个函数后面如果不跟第2个 ...

  7. Python模拟C++输出流

    看到一Python例子,挺有意思的,用Python模拟C++的输出流OStream.单纯只是玩. 原理: 利用Python __lshift__左移内建函数<<,调用时将输出内容,如果内容 ...

  8. Linux内核分析之计算机是如何工作的

    一.计算机工作原理 本周实验主要是反汇编C代码,生成汇编程序.冯·诺依曼理论的要点是:数字计算机的数制采用二进制,计算机应该按照程序顺序执行.人们把冯·诺依曼的这个理论称为冯·诺依曼体系结构.CPU通 ...

  9. Virtualbox修改bios信息安装Windows XP OEM

    转载 http://hi.baidu.com/guoyao11/item/631ad6eb4fb3d93887d9de11 具体方法有两个: 1.把下面的代码复制改后缀为BAT文件直接运行即可,以Le ...

  10. 制作SMD Package及SMD焊盘制作

    1.设置公英制. 2.设置栅格点.在Etch里设置0.1MM. 3.封装包括以下内容:REF标识, Place bound层包括高度, silkscreen 层, 1pin标识及pin序, 中心坐标, ...