[email protected]:~$

  • javascript学习笔记(一)

    以前没怎么用过javascript(仅停留在简单的dom处理与ajax上),身为后端程序员对其印象仅有杂乱 完成简书新richtext编辑器的基本功能后,感到js也没这么不堪,反而基于原型的模型能很轻易的应对反射,动态定义Function/Object等‘元编程任务’ 并且和ruby中的’元编程’不同,在js中这些就是通常编程 “原型”的表达力不弱于OO,并且复杂程度远小于OO。当然在javascript中的实现还是略微杂乱..虽然这门语言很多细节部分的设计让人匪夷所思,但是其核心的原型功能还是兼具了精简与好用这两处优点 遂打算好好学习下js, 并在阅读《JavaScript语言精粹》时把一些知识要点记录下来 本文会以tips的方式罗列从书中获取的知识要点,以及一些我自己的理解和对这门语言的想法 所有内容基于ECMAScript-262 (javascript 1.5) false,js的条件判断中 0, -0, null, false, "", undefined, NaN 均为 false(coffeeScript中的?操作符编译为typeof a !== "undefined" && a !== null;使其行为接近一般语言) Number,js中数字储存为(相当于java中的)double, 所以1/2会等于0.5 基本类型,js中有 Number, Boolean, String, Array, Object, undefined几种类型,Boolean, String, Array, Object都属于Object(因为可以用原型系统, null比较特殊) 对比,js中==仅对比值,===更为严格,要求类型也一致(coffeScript把这两个颠倒了过来,更加接近一般语言的行为) 注释,js中单行注释用//,导致你无法用//来表示一个空的正则,/**/也是 原型继承,js中通过键来获取对象中的值时,如果该对象无此键,则会到对象的原型链中去查找,直到Object的prototype,任何对象都隐含链接到Object.prototype,该值默认是{} 更改对象的键时不会影响到原型 delete操作符,用来删除对象的键(不会影响到原型),这时对象原型的相应键会暴露(如果有的话),再次delete会被忽略并返回true(这代表如果原型上有key,则没办法在对象上删除该键,但是可以赋值为undefined) for..in 语句可以用来遍历对象的所有key hasOwnProperty方法用来判断对象是否有该key(从原型中继承的不算)

  • fiber, goroutine/erlang process, thread的区别

    经常看到有人会认为fiber和thread是一类东西,或者认为fiber就是轻量级的thread,和goroutine / erlang process是同一种东西 JRuby的fiber目前也是用thread来实现的,可能因此引起很多fiber和thread的误解 当然它们当然不是同一种概念..(两个当然!!哦不..三个!!) thread是一种“执行单位”,操作系统会分配CPU去运行thread。goroutine和erlang process与此相近,相比thread更加的轻量化(貌似听说过goroutine就是简单的通过线程池来实现),所以它们也是“执行单位”。概念上thread 和goroutine / erlang process更加接近,都会由VM或OS(OS也可看做是VM!)分配CPU时间去执行。 fiber与此不同,打个简单的比方,如果你用了两个线程,并且你用的双核电脑,这时你的代码很有可能会跑在两个CPU上。 如果你用了两个fiber会怎么样?当你调用run的时候并不会新开始一个“执行单位”,fiber的调用是在你当前的thread执行的,fiber的call需要占用“执行单位”(通常是thread),因为其本身不是一个“执行单位”。 fiber是在“执行单位”之上的,与thread不是同一个概念,fiber用来保存“执行流程”,仅仅是保存,这样可以把“执行流程”从“执行单位”上抽离,更加有效的利用“执行单位”。 Celluloid(ruby的一个实现actor model的库)中Actor就是这样的用法,可以让本应被block的“执行流程”暂时保存在fiber中,这时“执行单位”(其实就是thread)可以执行下一个“流程”,让thread的利用率更高。 em-synchrony则更巧妙的通过fiber切换“执行流程”来达到写同步代码,异步执行(有兴趣可以看em-synchrony在github主页上的链接,里面讲了如何实现) 这样看的话就很清晰了,thread和goroutine / erlang process 这些都是“执行单位”,可以获得CPU时间。fiber的用处则是保存“执行流程”,与前者完全不是同一个概念。

  • 2014年凌晨的胡思乱想

    没有实感 对于电脑右下角年份的切换没有特别的感觉 好像和昨天一样,昨天又和前天一样 最近偶尔会发呆,在不知道做什么事时突然楞在那里,就好像大脑回路里某个字节出现了错误,或者像是输入设备出了bug,迟迟不能接收外界 思考了很多,感觉最近在技术上找不到方向,不知道做什么,可能是眼高手低,很简单的不屑于去做,很难的水平又不够,翻下github就知道我没有自己做过web项目(blog可以忽略了吧)。为什么?没什么意义,不想做千篇一律的东西,不想做一个又一个的BBS,Blog,没有什么有趣的想法,做出来的也都是废物 可能这也是一种回避思考,知道做出来后没什么用,于是就不做,很聪明的选择,知道即使学了llvm能做出玩具语言,但没什么用,于是看着看着乏味了就放弃了。因为明知是失败,无意义,乏味的东西,所以主动放弃,这种回避做法是聪明吗? 感觉不仅是职业上,在生活上也找不到方向,昨天等于今天等于明天,害怕被拒绝于是回避和别人的对话,感觉说出来会被无视于是不做声,感觉语言是无意义的于是尽量寡言。其实语言明明是很重要的东西,无论其承载,语言本身就是很重要的。很羡慕Cai*那种性格,某次RubyTuesday明明最晚到,却能强制的插入话题,并且引导话题到自己的产品,这种气势似乎是先天得来,有些猎命师里‘命格’的感觉。所以该说是性格使然吗?性格是命运吗?如果一个人出生带有的性格决定其做法或对其做出的选择至少会有影响,那么这算是命运吗? 性格决定命运,命运决定环境,环境决定性格。应该由哪一环来打破? 环境?环境是最薄弱的一环,想做的话甚至辞职换个城市生活就可以了。 这不是逃避,绝对不是,浑浑噩噩的生活才是逃避,打破负面的循环是一种面对,是一种尝试 但是这种选择往往伴随着新的枷锁,选择打破环境可能会带来新鲜感,于是本质的问题暂时被掩盖,但总还会有浮上来的一天,那时又该怎么办? 自视甚高是凡人的可悲,明明对自己要求很高,目光中充满不屑,却达不到这种要求,想象中与现实中的自我产生极大差异。我能想到的结果其一自欺欺人,其二不满现实郁郁而终 是不是真的有贤人?无欲无求的人和庸人区别在何处?所以那些人又为什么被成为圣贤? 感到自己缺少‘匠’心,无论做什么都很烦躁,从技术上或是爱好上都能看出,不想学基础却一直想着做出什么有用的东西,平时的小说也基本都是一晚上完成的,回过头看很是粗糙,有些明明有趣的故事,因为着急展开,压缩字数,导致铺垫不足,完全渣掉了 其实想当的是演奏家,对此没有执着,只是感觉当个流浪的演奏家是很惬意的事情。独自来到小村子,用演奏来换取住处食物和村人的友情,生活一段时间后在夕阳中悄然离去,只留下背影。如果遇到同样的流浪艺人还能组个队什么的。当然只是一种幻想中的理想生活,精神寄托,所以只能想,更何况自己演奏水平低,流浪这种事情更做不来。 写完后感觉有点像是反省录?不过缺点这种东西不是意识到了就可以改的,写下来也不行! 不过既然人无完人,那么是否有必要改正所谓缺点?还是说缺点也只是人的构成部分而已,每个齿轮都有凹凸 2014年意义不明的一篇文章,新的一年要想有长进最简单的先从早睡开始吧? 起床时就是2014年的第一次醒来了

  • Yet Another Markdown Parser, 没想到还原度还挺高的

    最近写了个markdown parser练手, 发现这种有规范的东西非常适合TDD, 照着markdown语法来写spec, 然后一个一个将其通过, 之前从未试过这么彻底的TDD 是写代码写的很爽时顾不上测试 是spec一定要事先定下,如果是创造性的编程, spec没法确定, 在代码和spec间来回改动就失去了TDD的意义 托TDD的福,写好各个语法的parse后跑了下GFM的source页,没想到还原度还挺高的 之后fix了几个小地方,parse的效果已经比较完善了,而且因为TDD 保证了测试的覆盖率(2k行左右的代码估计1k多都是spec),可以放心的修改代码,只要可以pass spec基本就是没问题的 之前一直感觉TDD有点名副其实, 经过这次实践感觉这种编程方式真的能帮助你写出可靠的代码 当然关键还是要事先确定spec, 如果不能确定spec我是绝不会用TDD的方式去开发的, 实际上我把minidown改成支持GFM时就改动了一些spec, 当然相应之前的所有代码也需要修改,相当于白写了一遍测试 benchmark了下各种markdown parser解析14000篇文章的效率 跑在the ruby racer 上的marked大概3.8s可以完成 minidown 大概16s可以完成 maruku报错.. kramdown 大概200+s可以完成…(这货README里写着fast..) 后3种都是pure ruby的markdown parser marked考虑到主要是前端使用,可能没有太多考虑效率,看得出ruby和v8差距还是挺大… 对于后边两个结果到是很惊讶, 没想到minidown在pure ruby的parser里还挺快的..

  • ruby vs python benchmark

    写这篇的目的是下次在看见有人认为ruby效率比python低时我可以直接贴给他链接.. 鉴于很多人用ruby1.8来benchmark说明ruby效率是多么低下,我使用了ruby和python标准实现的最新稳定版本 ruby -v ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-linux] python3 --version Python 3.3.2 使用传统的fibonacci来benchmark #ruby require 'benchmark' def fib n if n < 2 1 else fib(n - 1) + fib(n - 2) end end Benchmark.bm{|bm| bm.report{puts fib(35)}} #python import timeit def fib(n): if n < 2: return 1...

  • ruby中的lambda为什么是Proc类

    当然写之前我试着在网上搜了下, 果然没有搜到类似的问题。 lambda为什么不是Function, Method 而是Proc ? 这个问题当然没有标准答案,于是我做了一番推(猜)测 lambda和proc都是Proc类,这样已经可以看出一些端倪,proc既然叫proc当然是Proc类的主角,所以lambda只是Proc的一个附属,因为已经实现了proc,所以就顺手实现了lambda。 proc是用来代表block的(双飞燕中的话是proc更接近block), 如果我们在参数中用&block,我们会得到一个代表block的proc对象, 并且proc和block在各种行为上几乎都是一致的。 再来看下lambda,双飞燕中说lambda更接近method 当然…其实他们的区别是很大的,ruby中method必须bind到一个object上才可以调用,method(消息)必有接收者 而lambda就很异端了,仅仅是一段可执行代码,没有什么可与之对应的(python中的method可以对应为第一个参数为self的lambda) 而与proc的区别仅仅是传参和上下文跳转上更像method,并且在block的压力之下几乎没有任何用处.. “虽然很鸡肋, 但是实现上很简单(把proc稍微改下?) 干脆一起实现了,说不定谁可以用得上” -————————-(我猜测的实现lambda时matz的想法) 于是就同归于Proc类了

  • 突发奇想, 试下celluloid + eventmachine

    前几天benchmark了下ruby中比较有前途的websocket-server(reel和em-websocket),结果是eventmachine完胜.. 而且发现reel有个很严重的问题,打开的文件描述符有一部分不能释放,于是造成打开的文件越来越多 https://groups.google.com/forum/?fromgroups=#!topic/celluloid-ruby/4btMSHIcjj4 mail list中问了下, tony说是我用法不对,但是我按照他说的用了detach还是会有此问题 但是如果使用em-websocket来写server的话难度的确是很大, 多线程环境很容易出问题, 于是我想如果有个能运行在eventmachine thread pool里的轻量级actor库就好了。 于是花时间研究了下如何实现,结果发现同步是个大问题 调用异步的actor没有什么问题,让他在pool里执行便可,但是如果同步的调用,那么当前的线程必须要阻塞住等待结果返回,可能阻塞住pool中很多的thread, 如果引入fiber进行异步的回调,则必须保证当前actor在fiber结束前不能被再次执行 class Player ... def ... @mp = ... @hp = ...#假设是异步计算的代码, 如果在fiber.yield之间有其他任务执行 #可能会造成数据不一致 ... ... end 于是需要引入exclusive之类机制 这样实现的话就偏离了轻量二字,而且更关键的。。这简直就是celluloid啊。。身为ruby程序员当然不能重新发明轮子 于是干脆使用eventmachine + celluloid这种形式,由em-websocket进行异步的io,然后celluloid并行的去执行代码, 而且还有个好处就是因为每个链接分一个线程,所以完全不要担心阻塞em-websocket的线程,在actor中可以尽情使用阻塞io 至于效率就交给传说中JVM上很屌的抢占式线程调度吧 于是这里是‘成品’

  • Celluloid中的任务中断和Condition

    ######Celluloid有个很神奇的机制(<–示例代码) Celluloid每次任务(方法调用)会用Fiber去包装 当一个FiberTask因为某些代码被中断时,此时Celluloid可以回到线程执行任务的方法 相当于中断的任务已经结束 之后Actor线程继续的从mailbox取任务 ######某些代码! FiberTask会因某些方法被中断,上面的示例代码中中断当前Fiber的是sleep方法,这个方法由Celluloid做了覆盖 sleeper = Sleeper.new(@timers, interval) Celluloid.suspend(:sleeping, sleeper) Celluloid.suspend这行代码就起到中断作用,(知道它会中断当前Fiber即可,实际会根据后边的参数调用一些callback) ######中断了。。如何恢复? def before_suspend(task) @timers.after(@interval) { task.resume } end 这就是参数sleeper的callback,可以看到利用定时器来执行恢复的task 如果Fiber.resume的时候当前正在执行别的FiberTask会怎么办?岂不是会乱掉? after定时器也是通过FiberTask来执行的,所以到时间后我们的block会被传到mailbox中,就像一个新任务被调用一样,完全没有问题! ######某些方法能中断? actor当然不是再任何情况下都可以自己中断..上文sleep方法是之一,另外Celluloid还提供了Condition类来进行中断 Condition类和ConditionVariable行为类似 ######Condition ConditionVariable主要是用来在线程间统一资源的,README很详细 在Celluloid中应该用Celluloid::Condition来完成这件事,他们的行为是差不多的 Celluloid::Condition的好处是会中断当前的FiberTask, 这样Actor可以去执行之后的Task,而不是一直block住,基本原理和之前sleep是差不多的 Condition可以很好用的去做些同步操作,而且不会浪费线程

  • ruby-stdlib-delegate

    一直对delegate效率抱有疑问(虽然从未做过牛X到需要改进这里效率的项目..) SimpleDelegate使用的果然是method_missing方法 method_missing据说是很慢的。。因为ruby要查询很多层方法 ActiveRecord采用的改进方案是method_missing中去创建方法,这样第二次调用就会命中创建的方法了 不过不到框架的级别应该是不需要在意这些的.. DelegateClass方法会返回一个匿名类,并且作为参数的类的实例方法都会在其中定义一遍 所以没有method_missing,当然用起来不是那么Simple.. delegate库解决了像是equal?, methods, instance_methods等等很多类似的小问题

  • Celluloid中的Atom Mode与锁

    Celluloid默认是Atom Mode执行的, 这种模式下可以中断当前执行的任务 先执行下一个 Celluloid提供了一个sleep方法,在Actor内部调用sleep时会中断当前Fiber并且用timer异步来恢复 def before_suspend(task) @timers.after(@interval) { task.resume } end 当中断当前的TaskFiber时,Actor即可处理下一个message,被中断的message等待timer去恢复自身 def task(task_type, method_name = nil, &block) if... .... else @task_class.new(task_type, &block).resume#中断fiber时从此处返回 end end 我们在Actor上的每次调用都是一个独立Fiber Actor 线程是一个worker,来运行多个Fiber,个人感觉这里有点矛盾,Celluloid把多线程程序,变成了多Fiber程序,不同的Fiber很有可能并发访问同一个变量 而exclusive就是Celluloid中的Fiber的锁。actor本身就是消除锁的,而现在却又引入了一个新的锁。 不过实际写过Celluloid程序后,感觉还是不要对这个锁太担心的,实际中只有中断时(调用sleep)才会插入新的fiber,而我们在写需要同步执行的代码时 一般的正常人类是不会在其中插入个sleep的,如果必须确定代码的同步 则要把代码写在exclusive块中(一般不需要,exclusive作用是阻止在本块中Fiber的中断) 这种机制虽然带来了少许的复杂性但是 绝大多数情况下我们无需知道这种机制也可正常的运作程序 即使用到exclusive, 也只是很简单的应用 可以更加有效率的利用线程 Celluloid把任务和worker之间隔离开,之后可能会把thread和actor也进行抽象分离,这样增加了灵活性和效率, 不过随之也带来了复杂性, 其中得失还是很难说清的