繁体   English   中英

Ruby TCPServer性能问题

[英]Ruby TCPServer performance issue

我在Ruby TCPServer上遇到了一个有趣的问题,即客户端连接后,它将持续使用越来越多的CPU处理能力,直到达到100%,然后整个系统开始陷入瘫痪,无法处理传入的数据。

存在问题的处理类被设计为TCP客户端,该TCP客户端从嵌入式系统接收数据,对其进行处理,然后返回处理后的数据以供进一步使用(由其他类似的数据处理器或输出给用户)。

在这种特殊情况下,有一段外部代码想要处理的数据,但是无法从主父代码(原始流程类将其数据返回给它的东西)中访问它。 该外部部件在运行时可能随时连接,也可能未连接。

为了解决这个问题,我用TCPServer设置了一个线程,并且处理类不断添加到队列中,并且线程从队列中拉出并将其发送给客户端。

除性能问题外,它的效果都很好。 我很好奇我的代码中是否有一些时髦的东西,或者这仅仅是这种方法的本质,并且永远无法发挥足够的性能。

在此先感谢您对这个问题的任何见解/建议!

这是我的代码/设置,以及一些测试助手:

process_data.rb

require 'socket'

class ProcessData

  def initialize
    super

    @queue = Queue.new
    @client_active = false

    Thread.new do
      # Waiting for connection
      @server = TCPServer.open('localhost', 5000)

      loop do

        Thread.start(@server.accept) do |client|
          puts 'Client connected'

          # Connection established
          @client_active = true

          begin
            # Continually attempt to send data to client
            loop do

              unless @queue.empty?
                # If data exists, send it to client
                begin
                  until @queue.empty?
                    client.puts(@queue.pop)
                  end
                rescue Errno::EPIPE => error
                  # Client disconnected
                  client.close
                end
              end
              sleep(1)
            end

          rescue IOError => error
            # Client disconnected
            @client_active = false
          end
        end # Thread.start(@server.accept)
      end # loop do
    end # Thread.new do

  end



  def read(data)
    # Data comes in from embedded system on this method

    # Do some processing
    processed_data = data.to_i + 5678 

    # Ready to send data to external client
    if @client_active
      @queue << processed_data
    end

    return processed_data
  end

end

test_embedded_system.rb (原始数据源)

require 'socket'

@data = '1234'*100000 # Simulate lots of data coming ing

embedded_system = TCPServer.open('localhost', 5555)

client_connection = embedded_system.accept
loop do
  client_connection.puts(@data)
  sleep(0.1)
end

parent.rb (这将创建/调用ProcessData类)

require_relative 'process_data'

processor = ProcessData.new
loop do
  begin
    s = TCPSocket.new('localhost', 5555)
    while data = s.gets
      processor.read(data)
    end
  rescue => e
    sleep(1)
  end
end

random_client.rb (想要来自ProcessData的数据)

require 'socket'

loop do
  begin
    s = TCPSocket.new('localhost', 5000)
    while processed_data = s.gets
      puts processed_data
    end
  rescue => e
    sleep(1)
  end
end

要在linux中运行测试,请打开3个终端窗口:

窗口1:./ test_embedded_system.rb

窗口2:./ parent.rb

\\ CPU使用率稳定

窗口3:./ random_client.rb

\\ CPU使用率持续增长

我最终弄清了问题所在,不幸的是,我让人们误以为是我的榜样。

事实证明,我的示例并没有完全解决我遇到的问题,主要的区别是sleep(1)不在我的process_data.rb版本中。

睡眠实际上是非常重要的,因为它是在loop do ,没有睡眠,线程将不会产生GVL,并且会不断消耗CPU资源。

本质上,它与TCP无关,而更多与线程和循环相关。

如果您稍后在此问题上遇到问题,则可以在不需要的情况下将sleep(0)放入循环中,但希望它产生GVL。

还要查看以下答案以获取更多信息: Ruby无限循环导致100%cpu负载

sleep 0有特殊含义吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM