Clojure与并行计算

我们在写Java代码时对于处理并行计算总是需要特加小心,加锁与否是个相当伤脑筋的事。Clojure对并行计算支持的很好,这也成为很多业内人员选择使用Clojure的一个重要原因。

 

维基百科中有一段文字很好的阐述了并行计算的概念:“系统中能够同时执行多个计算,并且存在潜在的彼此交互,这种特性被称为并行。并行计算可能在同一芯片的多个核上执行,那些时分线程优先运行在同一处理器上,或执行在物体空间彼此独立的处理器上。”并发的主要挑战是如何管理好对共享而又易变状态的访问。

 

管理并封锁比较有困难。因为需要决定哪些对象需要锁定,以及何时锁定。当代码发生更新或者新的代码加入时,这些决定需要重新评估。如果一个开发人员忘记了给需要锁定的对象上锁或者上锁的时间点错误,会导致糟糕的事情发生。这些包括死锁和条件竞争。如果对象不需要上锁且给锁定了会带来性能上的损耗。

 

Clojure中所有的数据都是非易变的,除非用相应的VarRefAtomAgent类型明确表示某数据是易变的。这提供了管理共享状态的安全机制。

在一个新的新线程中运行任何Clojure函数都是小菜一碟,包括用户自定义的显示或者匿名函数。更多和Java交互的细节内容可以参考Java Interoperability

 

因为Clojure能够使用所有的Java类和接口,所以它能够充分利用Java的并发能力。"Java Concurrency In Practice"是一本非常不错的专门讨论Java并发性的书籍。该书就如何使用Java管理并发性提出了相当不错的建议,但是想要按照建议去做并非易事。大多数场合下,使用Clojure的引用类型要比基于Java的并发容易得多。

 

除了引用类型外,Clojure提供了多个函数用于辅助在不同的线程中运行代码。

 

future宏主体中的表达式执行在线程池(CachedThreadPoolAgents也享用这些线程)的某个线程上。这非常有利于执行那些需要长时间运行但又不必立即返回值的表达式。其结果通过对future宏的返回值对象进行解析得到。假如值被请求时,宏体还没有执行完毕,当前的线程将阻塞直到完毕为止。由于某个Agent线程池中的某线程处于被用状态,应该在某处调用shutdown-agents以终止这些线程,使得应用程序能够顺利退出。

 

为了阐述future的使用,下面的示例特意加了打印函数println,帮助理解函数如何运行,如下(注意输出内容的顺序):

(println "creating future")
(def my-future (future (f-prime 2))) ; f-prime is called in another thread
(println "created future")
(println "result is" @my-future)
(shutdown-agents)
 

输出如下:

creating future
created future
derivative entered
result is 9.0

 

pmap函数将一个函数并行地应用在集合的所有项上。当函数应用在各个项上的函数的消耗时间比管理线程所消耗的时间要多时,它提供了比map函数更好的性能。

 

Clojure.parallel名字空间提供了更多用于处理并行代码的辅助函数。包括 parpdistinctpfilter-dupespfilter-nilspmaxpminpreducepsortpsummary pvec.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值