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. vim编辑格式与环境设置

    set wildmenu set backspace= set pastetoggle=<f3> filetype on filetype plugin on filetype inden ...

  2. 搭建DHCP服务器以及DHCP中继服务器

    一.DHCP服务器   1.首先配置DHCP服务器的IP地址(DHCP服务器网卡桥接在VMnet1)   .配置好IP后重启DHCP服务 3.安装DHCP服务器,在这里我用的是YUM安装的(关于YUM ...

  3. php 解析 视频 信息 封面 标题 图片 支持 优酷, 土豆 酷6 56 新浪 qq播客 乐视 乐视

    原文地址:http://www.lianyue.org/2013/2497/ <?php /** * 解析 视频信息 类 * * 支持 优酷, 土豆 酷6 56 新浪 qq播客 乐视 乐视 ** ...

  4. Oracle 截取、查找字符函数(持续更新)

    整理一些常用的截取.查找字符函数: 1.查找某一个字符串中某一个字符(串)出现的次数 SELECT LENGTH(REGEXP_REPLACE(REPLACE('anne<br>lily& ...

  5. iptables文件

    # Firewall configuration written by system-config-firewall# Manual customization of this file is not ...

  6. 1029. Median (25)

    分析: 考察归并排序,用简单的快排会超时. #include <iostream> #include <stdio.h> #include <algorithm> ...

  7. linux 下vim的使用

    vi与vim vi编辑器是所有Unix及Linux系统下标准的编辑器,他就相当于windows系统中的记事本一样,它的强大不逊色于任何最新的文本编辑器.他是我们使用Linux系统不能缺少的工具.由于对 ...

  8. java 图示

    java类继承关系 java流类图结构

  9. android --- Afianl框架里面的FinalBitmap加载网络图片

    Afinal里面FinalBitmap:用于显示bitmap图片,而无需考虑线程并发和oom等问题. 1.测试请求 使用网页打开http://avatar.csdn.net/C/6/8/1_bz419 ...

  10. php数据库常用函数

    //打开mysqlmysql_connect( $host, $user, $pwd ) or die('error');$host => localhost //数据库地址$user => ...