[
  {
    "path": "README.md",
    "content": "Concurrency Live - PyCon 2015\n=============================\n\nDavid Beazley (@dabeaz)\n\nThis is the live-demo code written during my talk \"Python Concurrency\nFrom The Ground Up: Live\", presented at PyCon 2015, April 10, 2015.\n\n"
  },
  {
    "path": "aserver.py",
    "content": "# server.py\n# Fib microservice\n\nfrom socket import *\nfrom fib import fib\nfrom collections import deque\nfrom select import select\nfrom concurrent.futures import ThreadPoolExecutor as Pool\nfrom concurrent.futures import ProcessPoolExecutor as Pool\n\npool = Pool(4)\n\ntasks = deque()\nrecv_wait = { }   # Mapping sockets -> tasks (generators)\nsend_wait = { }\nfuture_wait = { }\n\nfuture_notify, future_event = socketpair()\n\ndef future_done(future):\n    tasks.append(future_wait.pop(future))\n    future_notify.send(b'x')\n\ndef future_monitor():\n    while True:\n        yield 'recv', future_event\n        future_event.recv(100)\n\ntasks.append(future_monitor())\n\ndef run():\n    while any([tasks, recv_wait, send_wait]):\n        while not tasks:\n            # No active tasks to run\n            # wait for I/O\n            can_recv, can_send, _ = select(recv_wait, send_wait, [])\n            for s in can_recv:\n                tasks.append(recv_wait.pop(s))\n            for s in can_send:\n                tasks.append(send_wait.pop(s))\n\n\n        task = tasks.popleft()\n        try:\n            why, what = next(task)   # Run to the yield\n            if why == 'recv':\n                # Must go wait somewhere\n                recv_wait[what] = task\n            elif why == 'send':\n                send_wait[what] = task\n            elif why == 'future':\n                future_wait[what] = task\n                what.add_done_callback(future_done)\n\n            else:\n                raise RuntimeError(\"ARG!\")\n        except StopIteration:\n            print(\"task done\")\n\nclass AsyncSocket(object):\n    def __init__(self, sock):\n        self.sock = sock\n    def recv(self, maxsize):\n        yield 'recv', self.sock\n        return self.sock.recv(maxsize)\n    def send(self, data):\n        yield 'send', self.sock\n        return self.sock.send(data)\n    def accept(self):\n        yield 'recv', self.sock\n        client, addr = self.sock.accept()\n        return AsyncSocket(client), addr\n    def __getattr__(self, name):\n        return getattr(self.sock, name)\n\ndef fib_server(address):\n    sock = AsyncSocket(socket(AF_INET, SOCK_STREAM))\n    sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)\n    sock.bind(address)\n    sock.listen(5)\n    while True:\n        client, addr = yield from sock.accept()  # blocking\n        print(\"Connection\", addr)\n        tasks.append(fib_handler(client))\n\ndef fib_handler(client):\n    while True:\n        req = yield from client.recv(100)   # blocking\n        if not req:\n            break\n        n = int(req)\n        future = pool.submit(fib, n)\n        yield 'future', future\n        result = future.result()    #  Blocks\n        resp = str(result).encode('ascii') + b'\\n'\n        yield from client.send(resp)    # blocking\n    print(\"Closed\")\n\ntasks.append(fib_server(('',25000)))\nrun()\n"
  },
  {
    "path": "fib.py",
    "content": "def fib(n):\n    if n <= 2:\n        return 1\n    else:\n        return fib(n-1) + fib(n-2)\n\n"
  },
  {
    "path": "perf1.py",
    "content": "# perf1.py\n# Time of a long running request\n\nfrom socket import *\nimport time\n\nsock = socket(AF_INET, SOCK_STREAM)\nsock.connect(('localhost', 25000))\n\nwhile True:\n    start = time.time()\n    sock.send(b'30')\n    resp =sock.recv(100)\n    end = time.time()\n    print(end-start)\n\n    \n"
  },
  {
    "path": "perf2.py",
    "content": "# perf2.py\n# requests/sec of fast requests\n\nfrom socket import *\nimport time\n\nsock = socket(AF_INET, SOCK_STREAM)\nsock.connect(('localhost', 25000))\n\nn = 0\n\nfrom threading import Thread\ndef monitor():\n    global n\n    while True:\n        time.sleep(1)\n        print(n, 'reqs/sec')\n        n = 0\nThread(target=monitor).start()\n\nwhile True:\n    sock.send(b'1')\n    resp =sock.recv(100)\n    n += 1\n\n\n    \n"
  },
  {
    "path": "server.py",
    "content": "# server.py\n# Fib microservice\n\nfrom socket import *\nfrom fib import fib\nfrom threading import Thread\nfrom concurrent.futures import ProcessPoolExecutor as Pool\n\npool = Pool(4)\n\ndef fib_server(address):\n    sock = socket(AF_INET, SOCK_STREAM)\n    sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)\n    sock.bind(address)\n    sock.listen(5)\n    while True:\n        client, addr = sock.accept()\n        print(\"Connection\", addr)\n        Thread(target=fib_handler, args=(client,), daemon=True).start()\n\ndef fib_handler(client):\n    while True:\n        req = client.recv(100)\n        if not req:\n            break\n        n = int(req)\n        future = pool.submit(fib, n)\n        result = future.result()\n        resp = str(result).encode('ascii') + b'\\n'\n        client.send(resp)\n    print(\"Closed\")\n\nfib_server(('',25000))\n"
  }
]