EM vs Twisted

Omer Katz edited this page Jun 5, 2016 · 3 revisions

I was interested in the performance differences between Twisted and EventMachine for an application I’ve developing which is going to have to handle a lot of load as clients will be regularly polling it.

Disclaimer: I’m fairly new to Python and Twisted – so there may be a way of speeding them up which I’m not aware of – perhaps by compiling to byte code or using a stackless interpreter.

Rather than test performance at a TCP level, I thought I’d do more of a real world example – and test HTTP servers. Thin (combined with Rack) is a HTTP layer to EventMachine. Twisted has its own HTTP parser built in.

Results (recorded with ab)

Concurrency: 20 Requests: 2000

  • EventMachine: Requests per second: 3327.79 #/sec (mean)
  • Twisted: Requests per second: 3194.76 #/sec (mean)

Concurrency: 200 Requests: 20000

  • EventMachine: Requests per second: 4401.80 #/sec (mean)
  • Twisted: Requests per second: 4761.90 #/sec (mean)

Conclusion

Take these tests with a pinch of salt, as the old saying goes something along the lines of ‘There are lies, damned lies, and then there are statistics’.

The results are remarkably similar – with EM beating Twisted at some concurrency levels, and vica versa. There doesn’t seem to be an obvious difference in requests per second – even with an extremely large volume of requests.

To be honest, I’m a bit surprised. Ruby isn’t known for it’s speed, and we’re already using 2 more gems, Thin and Rack which, although they are as light as possible, still add overhead.

When it comes down to virtual memory Ruby uses a hefty 47 mb, but Python isn’t much better at 39 mb. I don’t suppose that would be a deal breaker for most people though.

I call it a draw ;)

Versions

EventMachine 0.10.0
Ruby 1.8.6
Thin 0.7.0
Python 2.5
Twisted 2.5.0

em_test.ru

app = proc do |env|
  [200, {"Content-Type" => "text/plain"}, ["Hello. The time is #{Time.now.to_i}"]]
end

run app

Run with: thin start —rackup em_test.ru

twisted_test.py

import time
from twisted.internet import protocol, reactor

class TimeProtocol(protocol.Protocol):
    def connectionMade(self):
        self.transport.write(
            'Hello. The time is %s' % time.time())
        self.transport.loseConnection()

class TimeFactory(protocol.ServerFactory):
    protocol = TimeProtocol

reactor.listenTCP(3001, TimeFactory())
reactor.run()

Run with: python twisted_test.py