pygrunn2014
2020-02-27 160浏览
- 1.gevent, threads & async frameworks Denis Bilenko
- 2.What is gevent? • green threads for Python – Coopera>ve, only switch at I/O • greenlet for context switching – No syscalls • libev for event loop – PreEy fast
- 3.status • currentstable:1.0.1 – Runs on Python 2.5 – 2.7 • masterbranch:1.1 – Support forPyPy:85% tests pass – Support forPython3:53% tests pass • Basics and sockets work • Subprocesses and fileobjects todo
- 4.import thread, socket def send(host): sock = socket.create_connec>on((host, 80)) sock.sendall("GET / HTTP/1.0\r\n\r\n”) # do two requests in parallel create_new_thread(send, ('python.org', )) create_new_thread(send, ('gevent.org', ))
- 5.#import thread, socket from gevent import thread, socket def send(host): sock = socket.create_connec>on((host, 80)) sock.sendall("GET / HTTP/1.0\r\n\r\n”) # do two requests in parallel create_new_thread(send, ('python.org', )) create_new_thread(send, ('gevent.org', ))
- 6.drop-‐in modules from gevent import socket, ssl, subprocess, thread, local, queue
- 7.stdlib compa>bility • • • • less to learn API is more stable across gevent versions we can use stdlib's tests to verify seman>cs trivial to port libraries and apps to gevent
- 8.from gevent import monkey; monkey.patch_all() import requests from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return requests.get('hEp://python.org').content app.run()
- 9.A TCP server def echo(socket, address): for line in socket.makefile(): socket.sendall(line) gevent.server.StreamServer(':5000’, handle).start()
- 10.gevent.wait([… objects …]) • wait for any gevent object • extendable through rawlink(callback)
- 11.gevent.wait([… objects …], >meout=5) • limit wai>ng to certain >me
- 12.gevent.wait([… objects …], count=N) • only wait for N objects • return value is a list of ready objects
- 13.gevent.wait() • wait for everything • “background” watchers ref=False • gracefulshutdown:– stop accep>ng new requests – gevent.wait()
- 14.geventserver • • • • • pre-‐fork, <999LOC supports any gevent server, not just HTTP graceful shutdown can beembedded:import geventserver reports long loop itera>ons github.com/surfly/geventserver
- 15.Why? • Avoid complexi>es of event loops • Avoid costs of real threads
- 16.Complexi>es of event loops A simple sock = socket.create_connec>on((host, 80)) sock.sendall("GET / HTTP/1.0\r\n\r\n”) data = sock.recv(1024) becomes
- 17.Complexi>es of event loops def connec>onMade(self): … def dataReceived(self, data): … def connec>onError(self, error): …
- 18.async vs. sync excep>ons for I/O errorstry:connect() exceptIOError:… def connec>onMade(self): … def connec>onError(self, error): …
- 19.async vs. sync context managers with open(‘log’, ‘w’) aslog:io_opera>on() log(“connected”) io_opera>on() log(“sent”) # log object is closed by “with” explicit state machine
- 20.async vs. sync synchronous programming model handle_result(func(params)) d = Deferred() func(d) d.add_callback(handle_result) d.add_errback(handle_error)
- 21.Giving up • excep>on handling • context managers • synchronous programming style • 3rdparty libraries A subset of Python without baEeries.
- 22.Generators / PEP-‐3156? • Help somewhat • But notenough:with conn.cursor() ascurs:curs.execute(SQL) # cursor() needs to do I/O in __exit__ • No compa>bility with threading / 3rdparty libraries
- 23.Corou>nes •generators:non-‐stackful corou>ne – Only yield to parent – Need special syntax – Only saves the top frame •greenlet:stackful corou>ne – Switching is just a func>on call – Switching to any target – Saves the whole stack, like a thread
- 24.Why? • Avoid complexi>es of event loops • Avoid costs of real threads
- 25.Threads vs green threads • crea>on – thread.start_new_thread:28usec –gevent.spawn:5usec – gevent.spawn_raw:1usec • does not maEer if used via pool
- 26.Threads vs green threads memory •threads:8MB of stack by default •greenlet:only allocate what’s actually used – 350 bytes per Python frame – 10-‐15KB • does not maEer since the memory is virtual – limits number of threads on 32bit arch
- 27.Gevent server def handle(socket, addr): # read out the request for line in socket.makefile(): if not line.strip(): break # send the response socket.sendall(HTTP_RESPONSE) socket.close() from gevent.server import StreamServer StreamServer(':5000', handle).serve_forever()
- 28.Threaded server queue = Queue() def worker(): whileTrue:'>True: