Source

gipc / examples / wsgimultiprocessing.py

Full commit
# -*- coding: utf-8 -*-
# Copyright 2012-2013 Jan-Philip Gehrcke. See LICENSE file for details.


import gevent
from gevent.wsgi import WSGIServer
import gipc
import urllib2
import time

"""
Multiple clients (running in greenlets that concurrently run in a child
process) request a response from a WSGIServer running in the parent. Each
response is generated by a child process, i.e. each client connection makes
the server process spawn a child.

A greenlet in the parent, the `servelet`, runs the WSGIServer. Each client
connection is handled in its own greenlet running the `hello_world` function.
This delegates the response creation to a child process. The child process
transfers the response back to the greenlet in the parent process via a gipc
pipe. This yields the response to the client.

Each client greenlet validates the response and terminates.

Output on my test system: 100 clients were served within 0.43 s.
"""


MSG = "response"
N = 100


def main():
    http_server = WSGIServer(('localhost', 0), hello_world, log=False)
    servelet = gevent.spawn(serve, http_server)
    # Wait for server being bound to socket.
    while True:
        if http_server.address[1] != 0:
            break
        gevent.sleep(0.05)
    client = gipc.start_process(
        target=child_test_wsgi_scenario_client,
        args=(http_server.address, ))
    client.join()
    servelet.kill()
    servelet.join()


def serve(http_server):
    http_server.serve_forever()


def hello_world(environ, start_response):
    # Generate response in child process.
    with gipc.pipe() as (reader, writer):
        start_response('200 OK', [('Content-Type', 'text/html')])
        rg = gipc.start_process(
            target=child_test_wsgi_scenario_respgen,
            args=(writer, ))
        response = reader.get()
        rg.join()
    yield response


def child_test_wsgi_scenario_respgen(writer):
    writer.put(MSG)


def child_test_wsgi_scenario_client(server_address):
    def get():
        assert urllib2.urlopen("http://%s:%s/" % server_address).read() == MSG

    t1 = time.time()
    clientlets = [gevent.spawn(get) for _ in xrange(N)]
    gevent.joinall(clientlets)
    duration = time.time() - t1
    print "%s clients were served within %.2f s." % (N, duration)


if __name__ == "__main__":
    main()