• 谈谈我对 Python 的看法 at 2018年04月29日

    我没说防御式编程有问题呀

    认真看我回你的原文:

    我知道有人会用防御式去减少内嵌,原文没说不代表我不知道,我只是陈述某中情况,它确确实实会发生你不说一定绝对能用防御式内嵌能解决的

    你不用列帖子给我,我手头的《代码简洁之道》比你这些帖子对 guard clause 陈述的更完整

  • 谈谈我对 Python 的看法 at 2018年04月29日

    你说的一切正中我下怀

    Python does not support access protection as C++/Java/C# does. Everything is public. The motto is, "We're all adults here." Document your classes, and insist that your collaborators read and follow the documentation.

    尤其 We're all adults here.

    这句话就是我非常要喷的,好,你 Python 这么 adult,干嘛要让人这么填鸭一样幼儿园在日字格去写数字 1,斜着,2 要笔顺从怎样多少度弯曲然后底部线要贴日字格底地去用?

    相反,Python is an ABC language! Guido design his Python as an ABC language!

    所以说,如果你认可容忍这样,而且你还觉得

    可以说你对 OO 编程缺乏理解,是不是应该去补补面向对象编程、重构、设计模式等方面的知识了?

    我觉得你应该得把所有编程语言都得重新学一遍,重新看看人家 Perl 怎么用 Moose OOP,哪怕不 OO,人家就算没有这样的环境都能自觉地 adult 形成这种思维。

    设计模式不是对所有语言都适用,不是所有语言都适用你所谓的那本《设计模式》里面的模式,Ruby 就有 mixin 式代理,为什么一定要定义一个空的方法去作为接口?直接调用一个不存在的方法不就完了,PHP 还可以 $obj->{'method_name'} 去 invoke 方法,按照设计模式去做,是不是得 Method m = class.getMethods ....再去 m.invoke(obj, params ...)

    我觉得你对任何语言都不熟悉,从计算机基础数据结构都得重新学!你连 OO 本质的抽象模型与数据复用想法估计都是错的!

    估计你没写过什么语言,没什么使用经验

    看了你的 Github,果然如此,你作为多年程序员,你也就是写写 Web 写写网站吧,难怪得出这样的结论

    你的 Stackoverflow 帖子提到的语言你得去补一下并且去任何一个公司做这些语言起码每个 2 年再回我帖子

  • 谈谈我对 Python 的看法 at 2018年04月29日

    我知道你会这么写,所以然后正好符合我喷的 Python 逻辑:

    while cond:
        if conditionA:
            # code
            break
        if conditionB:
            # code
            break
        if conditionC:
            # code
            break
        if conditionD:
            # code
            break
    

    if 是正向的,然后 Python 没有 until,所以你得 while 了再 if

    在代码简洁之道里面有讲,我知道有人会用防御式去减少内嵌,原文没说不代表我不知道,我只是陈述某中情况,它确确实实会发生你不说一定绝对能用防御式内嵌能解决的

  • 面试中的基础题小结 at 2018年04月28日

    真幸福

  • 谈谈我对 Python 的看法 at 2018年04月28日

    实在没办法,只好举例子:

    until condition
    end
    
    while condition do
      case n:
      when a:
        break
      else:
        # code
      end
    end
    

    我说了,不是所有场景都能一次性 and and and 的,如果 连续 几个 and 都是嵌套:

    data = {
      nest_data = {
        nest_nest_array = [
          { "nest_nest_info": "info" }
        ...]
      }
    }
    

    解析这种场景如何?当 key 不规则

    我知道可以有算法处理,但是有时候是赶时间完成任务的,不是去为了绕几个弯设计算法的。

    然后还有如果先筛选判断输入,后处理输入后写入存储后判断结果还有处理,3 - 4 个 缩进不算过份吧,不一定说【都是】这个词,我的意思就不都是 if 或者都是 while 什么的。

    对于数据 filter / reduce,Python lambda 只有一行,有很多场合处理起来真的不容易,你要么另外写一个函数,但是这样如果只针对某个数据结构场景,那是不是每个数据结构、业务场景都写个函数?

    但是 Ruby 可以:

    hash.select do |key, value|
       if key == 'name'
         # code
       end
       # code
    end
    

    而且 Ruby 有强大的 Enumerable 而且跟灵活的 Proc 结合在一起,非常灵巧。

    具体业务具体场景具体分析,反正 Python 就是写着很棘手,语法很干很硬,便秘一样的。

    有时候为了写出符合 pep8 风格又要达到算法优化级又要完成任务,那简直是多烧脑,不如去写 Haskell Ocaml,但是王垠在《我为什么不再做 PL 人》是这么评价的:

    第一段

    有一些 PL 人喜欢推广他们认为高大上的语言,比如 Haskell,OCaml,Scala 等。这些语言在 PL 学术界很受尊重,所以他们以为这些语言能够奇迹般的解决实际的问题,然而事实却不是这样的。事实是,这些学术界出来的语言,其实缺乏处理现实问题的机制。为了能够在学术上证明程序的所谓“正确性”,而且由于类型系统本身的局限性,这些语言往往被设计得过于简单,具有过度的约束性,以至于表达能力欠缺。最后,你发现用这些语言来写代码,总是这也不能做,那也不能做,因为你要是那么做了,编译器就无法发现“类型错误”。到最后你发现,这些语言的约束,其实是无需有的。如果放宽这些约束,其实可以更优雅,更简单的对问题进行建模。对正确性的过分关注,其实导致了 PL 人选择蹩脚的语言,写出绕着弯子,难以理解的代码。

    第二段

    这种天才病的危害在于,它蒙蔽了这些人的眼睛。他们不再能设计出让“普通人”可以容易使用的产品。如果你不会用,他们就会嘲笑你笨,而其实呢,是因为他们的设计不好。他们喜欢用含混晦涩的方式(所谓“函数式”)的写法来构造代码,让其它人阅读和修改都极其困难,……

    用 Ruby 虽然我也可以拿 block 很快解决问题,虽然匿名函数块没那么好维护,但是至少能先解决问题。

    Python 与 pep8 强制性过份地强调那种他自认为很神圣很学术总之接近于 法 lun 功 迷信信仰一样的语法风格信仰,固化了语法去用 4 space 就算了,还要让大家字里行间写得非得他认为的整齐整洁,我觉得那才是问题。

    另外,吾辈认为 Python 推崇的 简洁 不代表 简单 ,你想想看你去打扫一个房间,其实你只要把屋子收拾整齐,不留太多毛病就够了,最好就是能清洁一下然后让人看着舒服,但是那些都算优化。

    但是 Python 就像是打扫一个房间就搞得像是医院强制消毒一样的,投放各种消毒剂、清洁剂去把各种东西非得严格处理一样的。

    爱干净洗手很好,但是你在别人面前先拿肥皂洗手,再拿消毒液洗,再拿护理液洗,你旁边的人看你这样洗你觉得你自己很 tidy 但是我看着不以为然,反而觉得有病。

  • 谈谈我对 Python 的看法 at 2018年04月28日

    等你用来写了之后,你就会发现很多场景这么写不是故意的,因为除了这么做,没什么别的好用的语法了。

    就算你把逻辑用一个个函数分开来,你会发现,到处都是没必要定义函数。

  • 面试中的基础题小结 at 2018年04月28日

    LZ 在哪个城市呀

  • 谈谈我对 Python 的看法 at 2018年04月28日

    不是所有场景都能一次性 and and and 的,如果 result_1 在 第一个 and,result_2 在第二个 and……不一定说全都是 and,如果是:

    while condition
        if condition
            if condition
    

    等等组合呢,不一定非得是

    我说得有点激动,但是事实上我项目中实际这么一用,五味杂陈,啥感觉都出来了。

    例如有人单纯因为不喜欢 end,不喜欢 @ 就把 Ruby 整个否定的。这样就错过了 Ruby 的 DSL,元编程,Rails。

    Rei 的评论我是 OK 认可的,但是我只是觉得 Ruby 至少没那么强迫症,你可以不这么写嘛,Ruby 的文化就是多元的,不止一种方式做事。你不喜欢 Ruby 这种,你可以喜欢 Ruby 另一种。

    但是 Python 就不可以,你有且必须这么强迫症,像是把你捆起来 SM 一样的。

  • 谈谈我对 Python 的看法 at 2018年04月28日

    我说这是瞎扯淡的,所以归类到瞎扯淡,反正不喜欢这种强迫癌晚期的工具。

    尝试一下被强迫症施压的感觉是多么的扭曲和变态简直无法忍受

    不过这句话倒是有价值的:

    每个存在的语言都有可取之处,工作不得不用却不去发现它的优点那损失的是你自己

  • %{} 是什么意思? at 2018年03月30日

    因为 Perl 比 Ruby 早发展,198x 年的时候就已经 为人们所知所用,而且 Linux 早期团队其中就有 Larry Wall,Ruby 95 年出生 真正被人们所察觉的时候,都已经是 200x 年了。

  • %{} 是什么意思? at 2018年03月30日

    Ruby 的糖算甜度适中了,你去看看 Perl 的暴雨梨花甜,腻到吐,以至于有些语法写的人自己才知道。

  • 噢,昨晚快睡着了,困困哒不小心搞错了,是 singleton_methods,已修正

  • JIT for MRI 开始开发了 at 2018年03月29日

    嗯,这个在 HTTP 1.1+ 之后有了长连接,chucked 是可以做的,如果你不使用 Rails,垂直 Puma 直接编程应该可以

    Rails dispatch 到特定控制器、特定方法的时候,假设是在 A 线程里面的,但是你开一个线程 B 去处理数据库读出来,如果不 join,A 可能已经返回给客户端了。

    你说的 BigPipe 得改造 Rails 的响应方式。

    在博文中,已经明显这样的处理了:

    get '/chunked' do
      response['Transfer-Encoding'] = 'chunked'
      stream :keep_open do |out|
        out << erb(:bigpipe)
        sleep 2
        out << '<script>Bigpipe.puts("pagelat1","这是第一块")</script>'
        sleep 5
        out << '<script>Bigpipe.puts("pagelat2","这是第二块")</script>'
        out.close
      end
    end
    

    如果你非得讨论这个,你还可以上 HTTP/2 呢,HTTP/2 可以并行长连接,而且第一次握手之后的都是跟 WebSocket 类似的流,而且服务端和客户端还可以做互相的 RPC 反向推送,可以认为就没有谁是服务端谁是客户端的区别了。

    HTTP/2 比 你说的这 BigPipe 本质上就是 HTTP 1.1 chucked 流先进多了去了

    所以重新审题,我说的是 Rails 在 React 响应 Action 那里分配一个线程 task 处理 controller method 的业务

  • 该用 Bootstrap 4 还是 3? at 2018年03月29日

    b4 用上了 sass,b3 b2 是 less,样式定制如果你需要做前端写的话,是有差别的。

    b4 具有前端前瞻一些,看个人需求吧。

  • 吾辈认为,autoload 的废弃 实际上是 Ruby 有了成熟的包管理机制(融入了 gem)带来了模块管理就不需要了。现在的 Ruby 跟 Java 的包管理不相上下(当然还是有点差距)。

    就像 Java 有了 lib 目录,当然后来加入了 maven / ant,Java 是一开始,这方面机制就比较完备的。

    个人觉得 autoload 是解决 PHP 5 时代像:

    require '../../module_a.php'
    

    当时发明 autoload 还是以“集中目录”autoload 一些模块:

    function __autoload($classname) {
        $filename = "../../". $classname .".php";
        include_once($filename);
    }
    
    $obj = new ModuleA();
    

    后来 autoload 已经远去,标准文档都建议改用 spl_autoload_register。

    其实 composer 解决的就是跟 gem 同样目的的产物,但是,我觉得 PHP 的包管理没什么意义,作为标准有很多争议的语言(当时 CodeIgniter 有自己的 Code style,然后 Symphony 又有另外的还有锅铲各种更不用说了),如果不是 Laravel 带了个头,相信很多人是瞎写命名空间的。

    说到这里提一点话外语,我觉得 PHP 作为 View 语言(像 Angular / React.js 的 View 部分语法作为刚出生定位)也差不多了,现在有点变态(比双性恋还扭曲的一种形态,不伦不类)了(首先不好好作为 View 展示,又去加入复杂的语法、没有一个标准的书写面孔,还有 Scalar 与 面向对象混乱的搭配,Scalar 崇尚的是内聚、无类型、效率,class 的加入就是类型独立、分裂、离散,两种简直就是混搭,如果开发者稍微不注意就会写出相爱相杀的代码)。

    因此,用【编程语言界的畸形】来描述 PHP 最不为过。 人家 Perl 发明 $ 魔符是为了 跟 @(复数)还有 %(哈希)区分开来的,PHP 好歹参考人家 $,也得按人家规则来吧,你只搞一个 $ 然后数组还是 $var[] 然后 给数组追加语法又是 $var[] =,好,这是“[]=”的语法。

    因此,我觉得 $ 完全在 PHP 变量名 中是负责卖萌的,不起任何作用。 要是我去重写它的 词法 phrase tokenizer,我一定会坚决删掉它。

    呀,不小心黑了一把。。。表现出文不对题的尴尬

    回头说 autoload,其实它就是脚本语言早期没有包(或命名空间)对已存在的模块的管理的一种应对措施。

    对于猴子补丁啥的,我觉得应该说说 extend(允许类能够像 JS prototype 那样在 Ruby 的另一个叫做 singleton_methods 的继承支线)吧。

    感谢 LZ 分享 Ruby 基本模块加载用法。

  • 同在武汉

  • 不错!!!

  • 它是有 Out-of-Band,有些时候我故意读一些大文件(比如大软件安装包)测试过,其实是过一段时间会 GC,回到一个稳定的位置,但是有时候感觉起来不太起作用,真正跑 site 的场景,GC 不会在测试场景那么轻松,因为请求是那么的频繁和密集还有离散的。

    所以个人观点觉得要么就分流,不同的实例跑网站不同的部分。但是网站架构就改了,最简洁的办法,还是进程突破 max 触手工强 GC 或者 kill,或者限定 max,这样来得直接。

  • 其实 我早期就发现了 Ruby 这个问题,我想要是 Ruby 跟 JVM 一样有一个 -XX:max 的最大内存设置就好了。

    不仅仅是 puma、unicorn,我自己的 amber-kit 也会这样的。。。midori 也会

    跟 Server 没关系,Ruby 的 GC 分代回收,有些常驻的对象没那么容易直接收回去滴,项目大了,controller model 各种 obj 多了,如果在一段时间这么多的东西都会需要,就不轻易回收。

    思考一下 Ruby 的内存池要是碰到缓存攻击(别人故意去搜索命中率低的东西)那样的事情。。。

    幸好 unicorn 有杀进程的机制


    补充:

    刚看到一个帖子

    https://samsaffron.com/archive/2014/04/08/ruby-2-1-garbage-collection-ready-for-production

    We can tune our settings, from “Ruby 2.1 Out-of-Band GC”:

    RUBY_GC_MALLOC_LIMIT: (default: 16MB)
    RUBY_GC_MALLOC_LIMIT_MAX: (default: 32MB)
    RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR: (default: 1.4x)
    

    and

    RUBY_GC_OLDMALLOC_LIMIT: (default: 16MB)
    RUBY_GC_OLDMALLOC_LIMIT_MAX: (default: 128MB)
    RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR: (default: 1.2x)
    

    这应该很有帮助,设置试试看

  • 你确定?

    然而 puma 是 react 模型,轮询线程池是 loop,只有服务器挂了、退出了才会回收。。。

  • 既然能被 GC 则不是 static,然后又 final,那就是相当于“不可改变的动态创建对象”,作为默认值属性用途还是不错的

  • 我的理解就是 Mutable & Immutable Variable,LLVM Style,Rubinius 口味,语义解析中的常量折叠,Java 中的 final。

    To Think(遗留问题):如果 frozen 不被 GC,那么问题可大了,内存占用问题。

  • 其实,这个连接池只是 IO 用的,执行任务(到 rack 层交给 Rails 去 Route 去 Controller.method 是另一边),提升连接池超过 16 之后并不能显著提升并发,反而很多线程空余,虽然不阻塞。然而 Ruby 的线程并不 Parallel,开多了抢占 管道在 IO uds(好像以前是用 pipe)的另一头获取信号的时候卡 shi 你。

    补充: puma 的连接池是轮询的,发现 readable 的 连接 就会再次丢进去 任务队列,通知让其中一个线程抢占到之后执行。其实终归比起条件变量,性能还是差一些。

    然后再加上有 GIL,我也估计是因为 GIL puma 才选择 管道式通知的,因为走条件变量实现方式的路,不如 C 的高效,说了 Ruby 多线程不并行。

    然后很早以前很多人对 Fiber 有误解,以为 Fiber 能取代 Thread 啦,其实 Fiber 并不是解决并行问题的,而是解决异步同步的,跟并发关系大一些,跟 Goroutine Generator(生成器)是差不多的。

    Thread 本来应该并行的,但是不代表 Python Ruby 给它实现并行

  • Ruby 25 岁生日 #ruby25 at 2018年02月24日

    Loving Ruby

    t 站已送出祝福

  • Ruby 2.6.0-preview1 已发布 at 2018年02月24日

    JIT Yeppy~!

  • 好啦,逃 👣

  • 我写的 cocos - tars 游戏服务项目算是吧,不过日志比玩家信息数据要多,差不多吧,咿呀哈哈哈哈

    其中的一小小部分,其实还有分布式好几个 Server 的 log

    不过用 Cpp 写的,跟 Ruby 无关,在这里发言会不会让众多 Rubyist 有看法

  • PUMA 实现简要分析 at 2018年02月23日

    嗯嗯,不错,像我就会啥都哔哔,咿呀哈哈哈哈

  • 话题绕太远

    回到原来的话题,实际上我本来想表达的就是 Ruby 支持并发,但不并行。

    在 GIL 场景下,你除了写扩展,或者出门左拐 JRuby,在 MRI 传统 rb 编码是分时并发的,它解决的是均衡让多个线程能等分 CPU 时间,实现了一个虚假的“并行”,但实际上只要 GIL 的存在,它消耗的时间是不会少的。

    但是由于 IO 能绕开 GIL,IO 是不会被 GIL block 的,那是系统层面等待而不是语言平台级别去等待。所以我看大家都在极力证明服务器 IO 密集啦什么的。

    但是我个人观点是对于业务复杂的 site,基本都是 programming complex,造成 computing complex 和 CPU bound,A 类 -> B 类 的一大波业务,还有字符串处理等等,不是小损耗。而系统 IO 基本都是 C 甚至 Assembly Instruction(汇编指令)来完成,实际上提到的那些 Goroutine java.nio,都是为了把【等待】给异步开来,不阻塞原本 Main Thread 的 code 执行。

    研究 IO 的本质就是【模型】,玩来玩去就是设计模式,所以我才会说“玩玩具一样的,还不如直接调用系统 API”,虽然细看会有差异,还可能调度上的差别产生了性能差别。

    但是,我提及 asio,是我觉得研究这个还不如换 C / C++ / Java 去 implement,因为 Ruby 似乎并不擅长这个,就算写出来了,一个方法调用就已经内部损耗了很多重、一大波的指令。

    所以我才会描述很极端,但又很现实的情况:

    你 Ruby 代码连磁盘 IO 都跑不赢,很可能你刷新一个网页,IO 就那么点东西,但是逻辑就已经够你处理半天了。

    其实 Ruby 简单的异步 IO API 就已经完胜应对 IO 了,puma 能做到如此精简同时高性能。

    与其浪费时间去折磨这些,不如转 C++ / Go / Java,如果深爱 Ruby,不如好好思考一下 GIL 下一步该怎么解决。

  • PUMA 实现简要分析 at 2018年02月23日

    这篇文章不够完整,只写了 IO,实际上它还有协议 parsing,那部分在 ext 目录用 C 写了,这个 parsing 部分 amber-kit 和 midori 这个部分和 puma 都差不多,parse 正确的才算正确的包,错包、不完整的包,还是有相应处理的。

    其实这些协议部分在 mozilla 文档是有相关介绍了,而且还有 how to write a server 相关的 tutorial