Queue based implementation is obviously the cheapest but author does not mention that queue.erl time complexity is O(1) amortized. It does introduce latency spike when "in" list needs to get reversed because "out" list is empty.
My throughput benchmark does take this into account though. It attempts to add 100,000 events to a window that only keeps events for 10 seconds. Adding 100,000 events takes much longer than 10 seconds, so the out list will be repopulated a couple times before the test is complete. The throughput benchmark is only an average though... And a longer running throughput test would yield a more accurate average.
I will update the post with this information.