Maxima computer algebra system (CAS) backend that is event driven using EventMachine for high concurrency per thread. Uses [Goliath] (http://github.com/postrank-labs.github.com/goliath/)
Future Plans:
- Each thread will use fibers to manage an asynchronous ConnectionPool of N maxima processes through ruby's Pty::expect in order to let other concurrent requests process through maxima backends while other maxima requests are waiting on I/O or on calculations
- M event loop processes of the above can be run behind a reverse proxy for even higher concurrency
- A rails (javascript-heavy) UI will communicate with these backends and use MathJAX to render beautiful math output on the client side rather than making the server produce and serve images
- The project could also expose a HTTP API to maxima for other frontends
require "em-synchrony"
# use eventmachine watch to get notification when pipe has data to read, then use the select-based expect.rb to get data
# if this ends up blocking too long unnecessarily, we can use a different mechanism. And if it would work, we could even use receive_data instead and simplify our lives
# This is still a work in progress...
# use an EventMachine-friendly expect rather than the select polling one
#require "expect-synchrony"
# use expect to drive maxima processes and get the results.
#require "maxima-expect"
# N = number of maxima processes in a connection pool for each EventMachine reactor process
# maxima processes need to be on same machine as this process (popen might deadlock because of the stdout buffering of maxima whereas a pty-connection can get the output right away)
# maybe maxima could be run across ssh on another machine, but that is currently not supported
N = 2
# M of these programs should get started, each in its own process, and they can all be joined via a reverse proxy such as HAProxy
EventMachine.synchrony do
mes = EventMachine::Synchrony::ConnectionPool.new(size: N) do
MaximaExpectServer.new
end
multi = EventMachine::Synchrony::Multi.new
multi.add :a, mes.aexecute("tex(1+1);")
multi.add :b, mes.aexecute("tex(1+1);")
res = multi.perform
p "Look ma, no callbacks, and parallel requests!"
p res
EventMachine.stop
end
The MIT License - Copyright (c) 2011 Ammon Christiansen