Share
Embed
Transcript
25 slides
-
A tiny thread pool class or The impact on performance
of a Service Oriented Architecture -
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 -
A typical web application • Is written using a framework
• Has some business logic • Talks to other systems • Databases • Caches • APIs -
parsing business logic rendering time Some of this time spent
waiting on other systems! (hopefully not too much) -
Our application • Connects to ~6 internal APIs • ...most
of which are slow • Hardly any state of its own • Relatively simple business logic -
parsing rendering time call API call API call API call
API business logic business logic business logic business logic -
parsing business logic rendering time call API call API call
API call API ~500ms (mean) -
parsing business logic rendering time call API call API call
API call API ~500ms (mean) (mostly just waiting! zzzzz.....) -
parsing business logic rendering time call API call API call
API call API ~ 125ms -
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)! -
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)! -
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)! -
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(...)! -
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 -
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 -
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