Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PDX Python lightning talk

PDX Python lightning talk

Kevin McConnell

March 27, 2014
Tweet

Other Decks in Programming

Transcript

  1. A tiny thread pool class or The impact on performance

    of a Service Oriented Architecture
  2. A tiny thread pool class or The impact on performance

    of a Service Oriented Architecture or That time we had that really slow website and we made it much faster with only about 10 lines of code
  3. A typical web application • Is written using a framework

    • Has some business logic • Talks to other systems • Databases • Caches • APIs
  4. parsing business logic rendering time Some of this time spent

    waiting on other systems! (hopefully not too much)
  5. Our application • Connects to ~6 internal APIs • ...most

    of which are slow • Hardly any state of its own • Relatively simple business logic
  6. parsing rendering time call API call API call API call

    API business logic business logic business logic business logic
  7. parsing business logic rendering time call API call API call

    API call API ~500ms (mean) (mostly just waiting! zzzzz.....)
  8. from threading import Thread! ! ! class ThreadQueue:! def __init__(self):!

    self._tasks = {}! self._results = {}! ! def run(self, name, fn, *args, **kwargs):! thread = Thread(target=self._perform,! args=[name, fn, args, kwargs])! self._tasks[name] = thread! thread.start()! ! def get(self, name):! self._tasks[name].join()! return self._results[name]! ! def _perform(self, name, fn, args, kwargs):! self._results[name] = fn(*args, **kwargs)!
  9. from threading import Thread! ! ! class ThreadQueue:! def __init__(self):!

    self._tasks = {}! self._results = {}! ! def run(self, name, fn, *args, **kwargs):! thread = Thread(target=self._perform,! args=[name, fn, args, kwargs])! self._tasks[name] = thread! thread.start()! ! def get(self, name):! self._tasks[name].join()! return self._results[name]! ! def _perform(self, name, fn, args, kwargs):! self._results[name] = fn(*args, **kwargs)!
  10. from threading import Thread! ! ! class ThreadQueue:! def __init__(self):!

    self._tasks = {}! self._results = {}! ! def run(self, name, fn, *args, **kwargs):! thread = Thread(target=self._perform,! args=[name, fn, args, kwargs])! self._tasks[name] = thread! thread.start()! ! def get(self, name):! self._tasks[name].join()! return self._results[name]! ! def _perform(self, name, fn, args, kwargs):! self._results[name] = fn(*args, **kwargs)!
  11. from threadqueue import ThreadQueue! ! tq = ThreadQueue()! ! tq.run('notifications',

    get_user_notifications)! tq.run('billing', get_billing_status)! tq.run('privileges', get_user_privileges)! ! # ...things happen...! # ...! ! if tq.get('privileges')['can_create_projects']:! create_project(...)!
  12. from threadqueue import ThreadQueue! ! tq = ThreadQueue()! ! tq.run('notifications',

    get_user_notifications)! tq.run('billing', get_billing_status)! tq.run('privileges', get_user_privileges)! ! # ...things happen...! # ...! ! if tq.get('privileges')['can_create_projects']:! create_project(...)! returns! immediately
  13. from threadqueue import ThreadQueue! ! tq = ThreadQueue()! ! tq.run('notifications',

    get_user_notifications)! tq.run('billing', get_billing_status)! tq.run('privileges', get_user_privileges)! ! # ...things happen...! # ...! ! if tq.get('privileges')['can_create_projects']:! create_project(...)! returns! immediately blocks if! results! pending
  14. What we learned • Apps that use many external services

    can spend a lot of time blocked on I/O • One way to minimize the waiting time is to do all your waiting at once • There's great support for all sorts of nice concurrency models nowadays, but often a Thread is all you need