I think there may be a race condition here.  While you are calling `self.redis.rpush(self.key, *self.queue)` from the flush task thread, the main thread may be appending to self.queue.  The items you append while it is flushing may simply be lost, since after flushing you do self.queue = [].

I don't think you can get away from using a Lock.  IMHO, the overhead of a Lock is justified because you are sending stuff to the network, which is much slower than mutex locking anyway[1].

So, I would acquire a Lock in emit(), and also in _flush_task (but only while calling _flush_buffer).

[1] http://www.eecs.berkeley.edu/~rcs/research/interactive_latency.html