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. Java获取服务器网址

    StringBuffer url1 = request.getRequestURL(); String tempContextUrl1 = url1.delete(url1.length() - re ...

  2. python多进程

    一.多进程池 from multiprocessing import Pool import time pool = Pool(processes=3) result=[];lr=range(t);a ...

  3. 9x25 串口映射

    duart       /dev/ttyS0            /dev/ttyS0 usart1    /dev/ttyS2 /dev/ttyS1 usart2    /dev/ttyS3    ...

  4. session的使用方法

    概念:session把客户资料存在服务器中,给浏览器一个加密凭证,每次登录生成的凭证都不相同,浏览器用cookie保存凭证.下次访问时服务器收到凭证后,打开文件读取session信息.session_ ...

  5. 斯坦福第六课:逻辑回归(Logistic Regression)

    6.1  分类问题 6.2  假说表示 6.3  判定边界 6.4  代价函数 6.5  简化的成本函数和梯度下降 6.6  高级优化 6.7  多类分类:一个对所有 6.1  分类问题 在分类问题中 ...

  6. SQL Server存储过程中防止线程重入处理方式

    对于线程重入,在C#中有lock关键字锁住一个SyncObject,而SQL Server也可用一个表来模拟实现. 先创建一个同步表,相当于C#中的SyncObject,并插入一条记录(初始值为1) ...

  7. How to do logging in C# with log4net

    If you are writing server code in C# or to a lesser extent desktop/client then it's a good idea to i ...

  8. 待实验:Android 增量升级

    参考资料: 增量升级(省流量更新)的Android客户端实现  http://blog.csdn.net/sgwhp/article/details/9009427 http://my.oschina ...

  9. (译)如何优化cocos2d程序的内存使用和程序大小:第二部分(完)

    前言:从上周发布教程的微博反应情况来看,cocos2der们对于游戏的内存问题还是非常关心的.本文是上一篇博文的续,旨在教大家如何减少cocos2d程序的大小. 全文如下: 减少你的程序的大小 把纹理 ...

  10. redhat 6上nis配置

    redhat 6上nis有点改动.在这里记一下 新装系统以后,首先要 yum install ypserv 安装ypserv的包 然后是设置 # 设置nis服务器名字 ypdomainname cen ...