Я сталкиваюсь с интересной проблемой с Ruby TCPServer, когда после подключения клиент постоянно использует все больше и больше вычислительной мощности ЦП, пока не достигнет 100%, а затем вся система начинает отключаться и не может обрабатывать входящие данные.
Класс обработки, имеющий проблему, предназначен для 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
\ Загрузка процессора стабильна
Окно 3: ./random_client.rb
\ Загрузка ЦП постоянно растет