• 自己写了个,不知道有没有什么好办法

    使用的话,像下面这样:

    
    require_relative 'select_chan'
    
    include Channel
    
    ch1 = Chan.new(1)
    ch2 = Chan.new(2)
    ch3 = Chan.new(3)
    
    
    select_chan(
      on_write(chan: ch1, obj: '1st'),
      on_write(chan: ch3, obj: '3rd'),
      on_read(chan: ch3),
      on_read(chan: ch2)
    ) { puts 'call default block' }
    
    

    代码: select_chan.rb

    require 'thread'
    require 'set'
    require 'monitor'
    
    module Channel
      class Chan < SizedQueue
        include Enumerable
    
        def each
          if block_given?
            loop do
              begin
                yield pop(true)
              rescue ThreadError
                return
              end
            end
          else
            enum_for(:each)
          end
        end
    
        def initialize(max)
          super(max)
          @readable_observers = Set.new
          @readable_observers.extend(MonitorMixin)
          @writable_observers = Set.new
          @writable_observers.extend(MonitorMixin)
        end
    
        def register(observer:, mode: :rw)
          unless observer.is_a? ConditionVariable
            return false
          end
          mode = mode.to_sym.downcase
          if mode == :rw
            @readable_observers.synchronize do
              @readable_observers.add(observer)
            end
            @writable_observers.synchronize do
              @writable_observers.add(observer)
            end
          elsif mode == :r
            @readable_observers.synchronize do
              @readable_observers.add(observer)
            end
          elsif mode == :w
            @writable_observers.synchronize do
              @writable_observers.add(observer)
            end
          else
            return false
          end
          true
        end
    
        def unregister(observer:, mode: :rw)
          mode = mode.to_sym.downcase
          if mode == :rw
            @readable_observers.synchronize do
              @readable_observers.delete(observer)
            end
            @writable_observers.synchronize do
              @writable_observers.delete(observer)
            end
          elsif mode == :r
            @readable_observers.synchronize do
              @readable_observers.delete(observer)
            end
          elsif mode == :w
            @writable_observers.synchronize do
              @writable_observers.delete(observer)
            end
          else
            return false
          end
          true
        end
    
        def push(obj, nonblock = false)
          super(obj, nonblock)
          notify_readable_observers
          self
        rescue ThreadError
          raise ClosedQueueError.new if closed?
          raise
        end
    
        def pop(nonblock = false)
          res = super(nonblock)
          notify_writable_observers
          res
        rescue ThreadError
          raise unless closed?
        end
    
        def clear
          super
          notify_writable_observers
          self
        end
    
        def close
          super
          notify_readable_observers
          notify_writable_observers
          self
        end
    
        alias_method :<<, :push
        alias_method :enq, :push
        alias_method :deq, :pop
        alias_method :shift, :pop
    
        private
    
        def notify_readable_observers
          @readable_observers.each(&:broadcast)
        end
    
        def notify_writable_observers
          @writable_observers.each(&:broadcast)
        end
      end
    
      def select_chan(*ops)
    
        ops.shuffle!
    
        mutex = Mutex.new
        cond  = ConditionVariable.new
    
        loop do
    
          ops.each do |op|
            begin
              return op.call
            rescue ThreadError
            end
          end
    
          return yield if block_given?
    
          ops.each do |op|
            op.register(cond)
          end
    
          mutex.synchronize do
            until ops.any?(&:ready?)
              cond.wait mutex
            end
          end
    
          ops.each do |op|
            op.unregister(cond)
          end
    
        end
    
      end
    
      def on_read(chan:)
        raise ArgumentError.new('chan must be a Chan') unless chan.is_a? Chan
        op = Proc.new do
          chan.deq(true)
        end
        op.define_singleton_method(:ready?) do
          !chan.empty? || chan.closed?
        end
        op.define_singleton_method(:register) do |cond|
          chan.register(observer: cond, mode: :r)
        end
        op.define_singleton_method(:unregister) do |cond|
          chan.unregister(observer: cond, mode: :r)
        end
        op
      end
    
      def on_write(chan:, obj:)
        raise ArgumentError.new('chan must be a Chan') unless chan.is_a? Chan
        op = Proc.new do
          chan.enq(obj, true)
        end
        op.define_singleton_method(:ready?) do
          chan.size < chan.max || chan.closed?
        end
        op.define_singleton_method(:register) do |cond|
          chan.register(observer: cond, mode: :w)
        end
        op.define_singleton_method(:unregister) do |cond|
          chan.unregister(observer: cond, mode: :w)
        end
        op
      end
    
      module_function :select_chan, :on_read, :on_write
    end
    
  • 不想深究深度学习的数学基础,能不能以黑盒的方式应用呢?

  • ruby太好用了 好喜欢

  • 请问 ruby 的 $, 怎么用的? at 2018年12月06日

    调用join方法 separator默认就是$,

  • Matz看起来年轻 头发多 健康状况良好 不会burn out

  • 可文档上也没说object_id一定是内存地址啊

  • 哦 好的😀

  • 是这样的,我学习ruby知道ruby不需要函数重载,但是在ruby里一个函数有多种参数列表比比皆是。我用Arrary的new函数只是举个例子,它不是可以有几种参数调用形式吗,Array.new(size=0,default=nil) Array.new(array) Array.new(size) {|index| block }, 我的foo函数就是照着这个写的,不是针对这个函数。我想既然标准库里都这样,应该是一种风格吧,难道ruby里不鼓励这样,一个函数最好就一种参数列表。😀

  • 以Array的Initialize为例,难道这样?

    def param_pattern_match(pattern, params)
      return false if pattern.size != params.size
      match = true
      pattern.zip(params) do|type, param|
        unless type === param
          match = false
          break
        end
      end
      match
    end
    class Array
      def initialize(*variants)
        case
        when param_pattern_match([], variants)
          '[size=0, default=nil]'
        when param_pattern_match([Integer],variants)
          '[size, default=nil]'
        when param_pattern_match([Integer,Integer], variants)
          '[size, default]'
        when param_pattern_match([Array],variants)
          '[array]'
        else
          'no match'
        end
      end
    end