Fix memory leak
This naive implementation of the observer pattern both leaks memory and
causes a very slow performance degradation over time as the
`_subscribers` dictionary gets larger and larger, mostly full of `None`
values.
This replaces the implementation with one that ensures that repeated
subscribe/unsubscribe calls don't affect performance or memory
consumption.