几行代码解决淘宝面试题之Clojure版

  我估计我不写这样的标题,吸引不了人气。问题的起因是Javaeye的一个帖子《淘宝面试题:如何充分利用多核CPU,计算很大的 List中所有整数的和》,看见为了这么个问题写长长的Java代码,让我十分蛋疼。为了表示蛋定,我想介绍下用Clojure解决这个问题的方法。

    题目很明确了,要你充分多核,这年头不“多核”不好意思出去跟人打招呼,为了多核,你要将list拆分下,每个子list并发去计算和,然后综合这些结果求出最终的和,您没搞错,这不是传说中人见人爱的MapReduce吗?你没听过?不好意思,你out了。

    咱们先别着急并发,先搞个不并发的版本试试看,第一步,切分list,实在不好意思,clojure有现成的clojure.core/partition函数:

user=> (partition 3 3 [0] '(1 2 3 4 5 6 7 8 9 10))
((1 2 3) (4 5 6) (7 8 9) (10 0))

   牛刀小试,将(1 2 3 4 5 6 7 8 9 10)切分成了3个子串,还有个可怜的犀利哥——10号同学没办法归入任意一个组,只好让他跟虚无的0为伴了。partition的第三个参数指定一个凑伙的集合,当无法完全切分的时候,拿这个集合里的元素凑合。但是我们不能随便凑合啊,随便凑合加起来结果就不对了,用0就没问题了。

   切分完了,计算子集的和,那不要太简单,该reduce同学上场,请大家欢呼、扔鸡蛋,千万别客气:

user=> (reduce + 0 '(1 2 3))
6

  
    自然要reduce,总要指定规则怎么reduce,我们这里很简单,就是个加法运算,再给初始值0就好咯,reduce万岁。

    慢着,有个问题,partition返回的是集合的集合((1 2 3) (4 5 6) (7 8 9) (10 0)),而上面的reduce却要作用在子集里,怎么办?无敌的map大神出场了,map的作用是将某个函数作用于集合上,并且返回作用后的集合结果,这里要干的事情就是将上面的reduce作用在partition返回的集合的集合上面:

user=> (map #(reduce + 0 % )(partition 3 3 [0] '(1 2 3 4 5 6 7 8 9 10)))            
(6 15 24 10)

    返回的是4个子集各自的和,答案肯定没错,最后一个结果不正是唯一的元素10吗?这里可能比较费解的是#(reduce + 0 %),这其实定义了一个匿名函数,它接收一个参数,这个参数用百分号%默认指代,因为是将map作用于集合的集合,因此这里的%其实就是各个子集。

   map返回的是个集合,又要求集合的总和,是不是又该reduce上场了?不好意思,map同学,这次演出你就一跑龙套的:

user=> (reduce + 0 (map #(reduce + 0 % )(partition 3 3 [0] '(1 2 3 4 5 6 7 8 9 10))))
55

    伟大的55出来了,它不是一个人在战斗,这一刻LISP、Scheme、Erlang、Scala、Clojure、JavaScript灵魂附体,它继承了FP的光荣传统,干净漂亮地解决了这个问题。

    综合上面所述,我们给出一个非多核版本的解答:

(defn mysum [coll n]
     (let [sub-colls   (partition n n [0] coll)
           result-coll (map #(reduce + 0 %) sub-colls) ]
         (reduce + 0 result-coll)))

   
    我们是使用了let语句绑定变量,纯粹是为了更好看懂一些。sub-colls绑定到partition返回的集合的集合,result-coll就是各个子集的结果组成的集合,#(reduce + 0 %)是个匿名函数,其中%指向匿名函数的第一个参数,也就是每个子集。最终,利用reduce将result-coll的结果综合在一起。

    “我们要多核,我们要多核,我们不要西太平洋大学的野鸡MapReduce"。

     台下别激动,神奇的“多核”马上出场,我要改动的代码只是那么一点点,用pmap替代map

(defn psum [coll n]
     (let [sub-colls   (partition n n [0] coll)
           result-coll (pmap #(reduce + 0 %) sub-colls) ]
         (reduce + 0 result-coll)))

   完了吗?真完了,你要改动的只有这么一点点,就可以让切分出来的子集并发地计算了。(感谢网友@clojans的提醒)。

以下是原文:
    首先是匿名函数改造一点点:
    我干嘛了,我就加了个future,给你个未来。严肃点地说,future将启动一个单独的线程去reduce子集。现在result-coll里不再是直接的结果,而是各个子集的Future对象,为了得到真正的和,你需要等待线程结束并取得结果,因此最后的reduce也要小小地改动下:

(reduce #(+ %1 @%2) 0 result-coll))

    reduce不再是简单地用加号了,替代的则是一个两个参数的匿名函数,第二个参数%2是Future对象,我们通过@操作符等待Future返回结果,并跟第一个参数%1(初始为0)作加法运算。

    最终的多核版本:

(defn mysum2 [coll  n]
    (let [sub-colls   (partition n n [0] coll)
          result-coll (map #(future (reduce + 0 %)) sub-colls)] 
         (reduce #(+ %1 @%2) 0 result-coll)))

   这个多核版本跟非多核版本区别大吗?不大吗?大吗?不大吗?……
   可以看到,Clojure可以多么容易地在并发与非并发之间徘徊,习惯脚踏N只船了。

文章转自庄周梦蝶  ,原文发布时间 2010-07-15

时间: 2024-08-30 08:27:47

几行代码解决淘宝面试题之Clojure版的相关文章

挑战淘宝:且看如何用1500行搞定淘宝20000行Java SDK(2)

        挑战淘宝:且看如何用1500行搞定淘宝20000行SDK(2)  既然想要比淘宝SDK更优秀,就必须解决淘宝SDK存在的问题,那么来看我是如何设计的:1)"API请求"(如ItemGetRequest)."API响应"(如ItemGetResponse)."API结果"(如Item)本质上都是"数据结构",不需要完成什么具体的操作,因此可以通过XML来进行定义,而不需要在代码中进行定义,这一指导思想是整个设计的

挑战淘宝:且看如何用1500行搞定淘宝20000行Java SDK(1)

         挑战淘宝:且看如何用1500行搞定淘宝20000行Java SDK 继亚马逊.雅虎.Google等一众知名大公司掀起了开放API的潮流后,淘宝也不甘寂寞,于2009推出了TOP平台,搭上了这趟开放API的顺风车(详细请看http://open.taobao.com/). 为了更好的开发TOP程序,淘宝提供了各种语言的SDK,其中自然少不了编程语言老大Java的SDK.但不幸的是,当我兴致勃勃的将SDK下载下来,准备大干一场的时候,却发现淘宝的Java SDK只是"看上去很美&q

剑指Offer之淘宝面试题之小白鼠与毒药解题过程分析

网上流传着一题淘宝面试题,原题如下: 我们有很多瓶无色的液体,其中有一瓶是毒药,其它都是蒸馏水,实验的小白鼠喝了以后会在5分钟后死亡,而喝到蒸馏水的小白鼠则一切正常.现在有5只小白鼠,请问一下,我们用这五只小白鼠,5分钟的时间,能够检测多少瓶液体的成分().A:5, B:6, C:31, D:32. +1只小白鼠首先可以想象只有1只小白鼠的情况,毫无疑问,1只小白鼠五分钟只能判断1瓶液体的成分,喝两瓶或以上如果是碰不到毒药,则喝多少瓶也能确定多少瓶:但如果遇到有毒药的瓶子,则不能判断那1瓶是毒药

国内最早对移动电商的报道,那一年淘宝高调上线手机网页版

国内最早对移动电商的报道始于2008年,那一年淘宝高调上线手机网页版.2010年,淘宝和麦考林相继发布手机客户端.紧接着是2012年,凡客不断释放出移动端交易额猛涨的信号--从2010-2012年,淘宝.凡客.麦考林基本上是国内移动购物领域的最为高调几个的弄潮儿,京东.腾讯电商.唯品会.聚美优品则鲜有露面. 进入2014年,移动购物市场风云突变,凡客.麦考林几乎都已淡出行业视线,曾经默不作声的京东.唯品会.聚美开始疯狂在移动端做文章,最出人意料的是,本来以为已经格局初定的电商行业内杀出一个"万能

由一道淘宝面试题到False sharing问题

今天在看淘宝之前的一道面试题目,内容是 在高性能服务器的代码中经常会看到类似这样的代码: typedef union { erts_smp_rwmtx_t rwmtx; byte cache_line_align_[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_smp_rwmtx_t))]; }erts_meta_main_tab_lock_t; erts_meta_main_tab_lock_t main_tab_lock[16]; 请问其中用来填充的c

淘宝联盟丢单怎么处理,怎么解决淘宝联盟丢单问题?

最近常有人在淘宝联盟群中里面看到有朋友喊淘宝客丢单,那么今天开淘小编和大家分享一下,常见的淘宝联盟丢单的原因以及对应的解决方案. 一.部分虚拟产品 根据淘宝联盟的相关规定,对于某些类目的虚拟产品,是没有淘宝客佣金的,其实,我们应该反过来说,哪些类目是有佣金的? 淘宝网.天猫及天猫国际平台7个虚拟类目将开始全部计佣推广.具体为: 1.7个虚拟类目清单:"网游装备/游戏币/帐号/代练"."网络游戏点卡"."腾讯QQ专区"."移动/联通/电信

电脑打开淘宝网却进入手机版的解决办法

近日在微博上看到有用户表示,自己在电脑上用IE浏览器打开淘宝网,但是进入的却是手机版淘宝.只有点击网页最下面的"电脑版"才恢复正常,但是再次打开依然还是手机版的淘宝.使用其他浏览器打开则是正常.然后在微博上一搜发现遇到这个问题的用户还不少,遇到这个问题应该是网站对浏览器识别错误导致的. 一般情况下是不会出现这种错乱的情况,不过在IE临时文件夹满后就会出现各种异常问题,例如IE无法打开某些页面,无法显示页面中的Flash动画,看在线视频时出现卡或是无法播放的情况.并且也会导致其他IE内核

黄鸣:马云没解决淘宝假冒问题 退休极不负责任

"http://www.aliyun.com/zixun/aggregation/11613.html">中国企业家中,爷们少,只要太阳能热水器行业存在的问题还没有解决,只要骗人坑人的事情依旧盛行,我就不会退出.不管这个行业如何发展,我都会站到最后."5月14日,素有"太阳能教父"之称的皇明董事长黄鸣,第七次自曝了太阳能行业内的潜规则. 在太阳能热水器行业健康发展之前,黄鸣不准备"退休".在他看来,马云的高调退休是不应该的.&qu

RGB转换实现代码,淘宝前端开发工程师笔试题_javascript技巧

例如: #1234ff 输出 #1234ff #123 输出 #123 #12345g 输出 #12345g 复制代码 代码如下: function RGB(rgb) { reg=/^#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/; if ( reg.test(rgb) ) rgb='rgb('+parseInt(RegExp.$1,16)+","+parseInt(RegExp.$2,16)+","+pars