celluloid / celluloid-io

UNMAINTAINED: See celluloid/celluloid#779 - Evented sockets for Celluloid actors
https://celluloid.io
MIT License
879 stars 93 forks source link

Establishing a connection in TCPSocket is not happening asynchronously #175

Closed dblock closed 8 years ago

dblock commented 8 years ago

I've added a Celluloid.sleep into handle_connection in echo_server and modified echo_client.rb like so:

#!/usr/bin/env ruby

require "rubygems"
require "bundler/setup"
require "celluloid/io"

Celluloid.boot

class EchoClient
  include Celluloid::IO

  def initialize(id, host, port)
    puts "#{id}: *** Connecting to echo server on #{host}:#{port}"

    # This is actually creating a Celluloid::IO::TCPSocket
    @socket = TCPSocket.new(host, port)
    puts "#{id}: *** Connected to echo server on #{host}:#{port}"
  end

  def echo(s)
    @socket.write(s)
    @socket.readpartial(4096)
  end
end

3.times do |i|
  Celluloid.defer do
    client = EchoClient.new(i, "127.0.0.1", 1234)
    puts client.echo("TEST FOR ECHO")
  end
end

(note the addition of Celluloid.defer)

The connections are being created sequentially, TCPSocket.new is blocking. I am probably missing something. How can I parallelize establishing of the connections?

This is related to https://github.com/dblock/slack-ruby-client/issues/84

tarcieri commented 8 years ago

#initialize runs synchronously. Move the connect out of #initialize, e.g.

def initialize
  async.connect
end

def connect
  @socket = TCPSocket.new
end

Also, please use the Google Group for help:

https://groups.google.com/forum/#!forum/celluloid-ruby

The issue tracker is for bugs.

dblock commented 8 years ago

Thanks @tarcieri, I did ask a few days ago, sorry for being impatient.

I ended up with this, establishing the connection and echoing asynchronously:

#!/usr/bin/env ruby

require "rubygems"
require "bundler/setup"
require "celluloid/io"

Celluloid.boot

class EchoClient
  include Celluloid::IO

  attr_reader :id, :host, :port

  def initialize(id, host, port)
    @id = id
    @host = host
    @port = port
    @connection = future.connect
  end

  def connect
    @socket = TCPSocket.new(@host, @port)
    @socket
  end

  def echo(s)
    wait_for_connection
    @socket.write(s)
    @socket.readpartial(4096)
  end

  def wait_for_connection
    @connection.value
  end

  def ping
    puts echo("#{id}: hello world")
  end
end

clients = 3.times.map do |i|
  EchoClient.new(i, "127.0.0.1", 1234)
end

futures = clients.map do |client|
  client.future.ping
end

futures.each(&:value)