• Ruby 的好朋友 -- jemalloc at 2018年10月31日

    已经在 facebook 上正常运行多年了,获得了广泛的认可。这儿有个讨论帖 https://ruby-china.org/topics/35515

  • @ThxFly @Rei 感谢,我的说法有点问题。

  • Rails 项目中 ruby 版本和 gemset 大多可以自动切换,是不是痛点得据情况而定,一般在项目切换不频繁时,ruby 版本不会是痛点。

    Docker 的本质是对运行环境进行隔离,主要价值在于可保证各个运行环境的一致性。对于环境不一致导致的问题,其实也可以考虑打造一个 和生产环境高度一致的测试环境,在测试环境中暴露问题。一般由于环境不一致导致的问题,其实不会太频繁。如果导致方案整体不可用的情况, 则可能方案的选择上欠考虑或者开发环境和生产环境差别过大。这其实也可以解决环境不一致带来的潜在问题,当然得根据情况而定。

    在开发环境中用 docker,除了环境一致性的优点外,其他的差不多可以视为缺点,带来反向价值。特别是对于像我等菜鸟,在开发时,经常拼错单词, 或者变量名取的不好要改,或者其他纰漏。这些小错在代码自动 reload 时,可以高效的解决。docker 嘛,毕竟多了一层,差不多活生生把动态语言开发搞成了静态语言开发,改一下还要构建一下。是否值得选择,也得看自身情况。

    至于用了 docker 是否区分 Rails 的三个模式,我实在想不出两者有什么关联。不用 docker 也不妨碍只用一种模式吧,只要你想。用了 docker,有多个模式也不会有问题。关联何在?

    以上是我的个人观点。

  • 2018 中国 Matz 访谈视频 at 2018年10月30日

    很棒,值得一看。 直接点这个链接可进 https://v.qq.com/x/page/p0772tw9fij.html

  • Ruby 的好朋友 -- jemalloc at 2018年10月30日

    @so_zengtao的风,来个完整的

    Ubuntu MAC centos 安装 jemalloc

    sudo apt-get install libjemalloc-dev
    brew install jemalloc
    sudo yum install -y jemalloc jemalloc-devel
    

    rbenv

    RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 2.5.0
    

    rvm

    rvm reinstall 2.5.0 --disable-binary --with-jemalloc
    

    源码安装

    ./configure --with-jemalloc
    make
    make install
    

    检查安装是否正确

    ruby -r rbconfig -e "puts RbConfig::CONFIG['LIBS']"
    # 应该输出:  -lpthread -ljemalloc -ldl -lobjc
    
  • 2.3.6 :021 > ENV['RUBY_VERSION']
     => "ruby-2.3.6"
    .3.6 :019 >  Benchmark.measure { maxa(1000)}
     => #<Benchmark::Tms:0x00007f8a60a4a780 @label="", @real=2.4335659999924246, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=2.42, @total=2.42>
    2.3.6 :020 > Benchmark.measure { maxf(1000)}
     => #<Benchmark::Tms:0x00007f8a60a3be88 @label="", @real=0.5101689999864902, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.5100000000000002, @total=0.5100000000000002>
    
     :001 > ENV['RUBY_VERSION']
     => "ruby-2.5.0"
     :022 > Benchmark.measure { maxa(1000)}
     => #<Benchmark::Tms:0x00007fe484845d30 @label="", @real=0.46752000000560656, @cstime=0.0, @cutime=0.0, @stime=0.00017400000000000054, @utime=0.46631599999999995, @total=0.46648999999999996>
     :023 > Benchmark.measure { maxf(1000)}
     => #<Benchmark::Tms:0x00007fe48282dc78 @label="", @real=0.6195719999959692, @cstime=0.0, @cutime=0.0, @stime=0.0003689999999999978, @utime=0.6181120000000001, @total=0.6184810000000001>
    

    2.3 和 2.5 的测试,确实也是反过来的,而且差别不小。

    我想说的是楼主的假设是不是不够科学? [].max 虽然会返回新对象,但是它的执行成本明显要低于max(a,b),执行过程本身就会创建一大波对象 (都放在 ObjectSpace 中的),调用越少消耗越少,虽然栈调用的消耗相对较小。

    不能简单地根据调用是否返回新对象来判断其性能吧? @quakewang

    这个测试用例中被测试的调用是在 each 中的,不知道虚拟机解释的时候,是否有区别优化?

  • 《Ruby 原理剖析》里面介绍过,each 方法每次迭代都准备一大波对象,执行很多逻辑。而 while 只需要调整 PC 指针的值,性能不在一个量级。具体的细节我得回去翻翻书了。

  • 用 Docker 构建开发环境 at 2018年10月16日

    把第五步how to use 整理成一个脚本,在 Dockerfile 中用 ENTRYPOINT/CMD 触发,再加上一个平滑替换容器的脚本,就完美了。

  • Z-Score ML 里面做数据特征归一化,数学真是无处不在

  • 关于一些基础的语法问题 at 2018年10月10日
    command :add do |c|
      c.action do |global_options,options,args|
        $todo_list.create(args)
      end
    end
    

    等价于:

    command(:add) do |c|
      c.action do |global_options,options,args|
        $todo_list.create(args)
      end
    end
    

    command(:add) 会返回一个方法,后面的代码块是这个方法的"参数"。

  • 你 nginx 代理静态资源写的是这个:

    location ~*^/app/assets/{
    
    }
    
    

    有这个路径吗?换下下面这个试试:

    location ^~ /assets/{
    
    }
    

    顺便建议在 config/environments/production.rb 加上:

    config.serve_static_files = false # 不让后端处理静态资源请求,可以检测你nginx是否真的代理的静态资源
    
  • 精靈旅社疯狂假期, 精灵旅社精靈旅社 在写入 ES 时,先全部转化为简体,只存一份。在查询时将所有的繁体转化为简体,再到 ES 查询,可行?

  • includes 的实现原理与困境 at 2018年08月18日

    实际情况复杂,关联对象取出来后,在渲染时还需要执行很多业务逻辑,而且对象关联可能不止一层。用 pluck,可能会有局限而且改造成本高。

  • 技师这个词用的好😂

  • 不是基于统计的???楼主能不能大概描述一下核心原理?thx

  •   class T
        A = {a: 1, b: 3}
        def s
          {c: 1, d: 1}
        end
      end
    
      T::A.object_id
    => 70307759309580
      T::A.object_id
    => 70307759309580
    
      t = T.new
    => #<T:0x00007fe39ba59ea8>
      t.s.object_id
    => 70307772676380
      t.s.object_id
    => 70307766481000
    

    最好用配置文件,实在不行,从内存的角度来看,还是放在常量里好些。

  • includes 的实现原理与困境 at 2018年07月30日

    很好的思路。将用户权限、用户自定义配置、核心数据配置、顶层数据 ((支持实时多条件查询)、关联数据本身组合打包,一起生成多层 cache_key,再增加层级间的 touch 机制,可以让这套机制跑起来。之前没有这么做,应该是因为缓存命中率和这一锅粥的复杂度,不过这个方案确实值得尝试。

  • includes 的实现原理与困境 at 2018年07月30日

    套娃更多的是提升渲染阶段的性能吧,在当前场景下需要做到很小的粒度才有意义,而且还是得先把数据查询出来,难以跳过 includes 带来的问题。

  • includes 的实现原理与困境 at 2018年07月30日

    确实,在准备融入项目时发现隐藏成本不小。特别是随着代码量增长,增加新的字段,新的方法时,特别容易埋下坑。这种功能需要写的尽量简洁,易配置,且只用在局部有性能痛点的地方。

  • 从 ActiveRecord 看乐观锁 at 2018年07月18日

    是的,一般读多写少怎么玩都行。乐观锁就是因为无锁,吞吐量大些,单次响应快(可能成功,可能失败)。

  • Ruby GC 自述 at 2018年07月11日

    有时确实容易造成 bug,我换一个例子:

    stringArray.each do |s|
      if s == 'someString'.freeze
          # do something
      end
    end
    
  • Ruby GC 自述 at 2018年07月09日

    环境永远不是完美的,或者说成本(时间/精力等)永远是有限的。我们需要做的事情,就是在这些限制下作出努力,让成本和收益达到某个平衡点。

    过分限制 Ruby 创建新对象会极大提升成本,得不偿失。大多数人建议少创建对象,本意是合理使用 Ruby 的特性,让它避免创建某些没有意义的临时对象。例如下面两段代码:

    stringArray = stringArray.map do |s|
      s.upcase  # 会创建新的对象
    end  # 创建一个新的数组
    
    stringArray.each do |s|
      s.upcase!  # 不会创建新的对象
    end
    

    这些小细节本身微不足道,但是当这些代码被执行千百次时,它带来的整体收益还是可观的。

  • Ruby GC 自述 at 2018年07月09日

    感谢@nowherekai的提醒和推荐,已经修改正确了。

    用 Ruby 很多时候是追求开发效率和开发体验。当应用对内存很敏感,或者说内存消耗造成了明显的问题,而这个问题又是 Ruby 造成的,那么换一种工具(语言)是可以考虑的选择。

  • Ruby GC 自述 at 2018年07月09日

    语言本身和使用语言的方式,这两个方面可能都得做出一些努力吧。据说 ActiveRecord 在重构了,会创建更少的对象。

  • Ruby GC 自述 at 2018年07月09日

    嗯,少创建对象是最重要的。文章本意主要是想介绍一下 GC。

  • Ruby GC 自述 at 2018年07月09日

    感谢提醒,已经修改了。

  • Ruby GC 自述 at 2018年07月08日

    关于文章内容,请各路大神们提点建议,帮助这篇文章成为 Ruby GC 的扫盲资料,通过文章能对 GC 有基础的了解。感谢!

  • 如果 http 请求本身会堵塞,那么重启后,此症状还不是会重现吗?

    进程/线程数开大,同时超时时间更短?

  • 从部署日志上看,你发送的是 TERM 信号,让进程先全部挂了,然后才重新启动。在进程挂掉到新的进程启动完成的过程中,你的服务肯定会有中断的。给进程发送 USR2 信号,puma 本身是支持平滑重启的,https://github.com/puma/puma/blob/master/docs/signals.md

  • 看了一下你的代码,创建 Websockt 连接去获取数据的操作,是在用户的 http 请求中被动触发的。这里面数据和数据是打包耦合在一起的。你看能不能换一种实现方式,单独开几个线程来实现数据,让这两个过程分开。比如在BvHelper::Daemon.run方法中先创建几个线程去获取数据,然后才EventMachine.start_server:

    require 'eventmachine'
    
    module EchoServer
    
      def receive_data data
        puts data
        puts $data
      end
    
    end
    
    class Server
      def self.run
        3.times do |i|
          Thread.new do
            loop do
              $data ||= {}
              $data[i] = Time.now.to_i
              sleep 1
            end
          end
        end
    
        EventMachine.run {
          EventMachine.start_server "127.0.0.1", 8081, EchoServer
        }
      end
    end
    
    Server.run