Commit b61f9e91 authored by Jason Madden's avatar Jason Madden

Add basic benchmarks for gevent.queue

Timing as of this commit (macOS 10.13.3, MacBook Pro retina 15-inch,
mid 2015, default loop impls):

| Benchmark                              | 27_queue_master | 27pypy_queue_master             | 36_queue_master              | 37_queue_master              |
|----------------------------------------|-----------------|---------------------------------|------------------------------|------------------------------|
| bench_unbounded_queue_noblock          | 2.09 us         | 10.8 ns: 193.75x faster (-99%)  | 1.34 us: 1.56x faster (-36%) | 1.24 us: 1.69x faster (-41%) |
| bench_bounded_queue_noblock            | 2.55 us         | 10.9 ns: 234.91x faster (-100%) | 1.67 us: 1.53x faster (-35%) | 1.55 us: 1.65x faster (-39%) |
| bench_bounded_queue_block              | 36.1 us         | 2.28 us: 15.81x faster (-94%)   | not significant              | 12.9 us: 2.80x faster (-64%) |
| bench_channel                          | 15.4 us         | 1.91 us: 8.03x faster (-88%)    | 9.96 us: 1.54x faster (-35%) | 8.17 us: 1.88x faster (-47%) |
| bench_bounded_queue_block_hub          | 13.6 us         | 1.07 us: 12.64x faster (-92%)   | 8.61 us: 1.57x faster (-36%) | 7.66 us: 1.77x faster (-44%) |
| bench_channel_hub                      | 7.55 us         | 760 ns: 9.94x faster (-90%)     | 5.11 us: 1.48x faster (-32%) | 4.33 us: 1.75x faster (-43%) |
| bench_unbounded_priority_queue_noblock | 5.02 us         | 186 ns: 26.97x faster (-96%)    | 1.63 us: 3.08x faster (-68%) | 1.60 us: 3.14x faster (-68%) |
| bench_bounded_priority_queue_noblock   | 5.48 us         | 183 ns: 29.91x faster (-97%)    | 1.98 us: 2.77x faster (-64%) | 1.79 us: 3.07x faster (-67%) |

[skip ci]
parent 8916cda1
# -*- coding: utf-8 -*-
"""
Benchmarks for gevent.queue
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import perf
import gevent
from gevent import queue
N = 1000
def _b_no_block(q):
for i in range(N):
q.put(i)
for i in range(N):
j = q.get()
assert i == j
def bench_unbounded_queue_noblock(kind=queue.Queue):
_b_no_block(kind())
def bench_bounded_queue_noblock(kind=queue.Queue):
_b_no_block(kind(N + 1))
def bench_bounded_queue_block(kind=queue.Queue, hub=False):
q = kind(1)
def get():
for i in range(N):
j = q.get()
assert i == j
return "Finished"
# Run putters in the main greenlet
g = gevent.spawn(get)
if not hub:
for i in range(N):
q.put(i)
else:
# putters in the hub
def put():
assert gevent.getcurrent() is gevent.get_hub()
for i in range(N):
q.put(i)
h = gevent.get_hub()
h.loop.run_callback(put)
h.join()
g.join()
assert g.value == 'Finished'
def main():
runner = perf.Runner()
runner.bench_func('bench_unbounded_queue_noblock',
bench_unbounded_queue_noblock,
inner_loops=N)
runner.bench_func('bench_bounded_queue_noblock',
bench_bounded_queue_noblock,
inner_loops=N)
runner.bench_func('bench_bounded_queue_block',
bench_bounded_queue_block,
inner_loops=N)
runner.bench_func('bench_channel',
bench_bounded_queue_block,
queue.Channel,
inner_loops=N)
runner.bench_func('bench_bounded_queue_block_hub',
bench_bounded_queue_block,
queue.Queue, True,
inner_loops=N)
runner.bench_func('bench_channel_hub',
bench_bounded_queue_block,
queue.Channel, True,
inner_loops=N)
runner.bench_func('bench_unbounded_priority_queue_noblock',
bench_unbounded_queue_noblock,
queue.PriorityQueue,
inner_loops=N)
runner.bench_func('bench_bounded_priority_queue_noblock',
bench_bounded_queue_noblock,
queue.PriorityQueue,
inner_loops=N)
if __name__ == '__main__':
main()
......@@ -62,6 +62,20 @@ def _safe_remove(deq, item):
pass
class ItemWaiter(Waiter):
__slots__ = ['item', 'queue']
def __init__(self, item, queue):
Waiter.__init__(self)
self.item = item
self.queue = queue
def put_and_switch(self):
self.queue._put(self.item)
self.queue = None
self.item = None
return self.switch(self)
class Queue(object):
"""
Create a queue object with a given maximum size.
......@@ -368,19 +382,6 @@ class Queue(object):
class ItemWaiter(Waiter):
__slots__ = ['item', 'queue']
def __init__(self, item, queue):
Waiter.__init__(self)
self.item = item
self.queue = queue
def put_and_switch(self):
self.queue._put(self.item)
self.queue = None
self.item = None
return self.switch(self)
class PriorityQueue(Queue):
......@@ -513,7 +514,10 @@ class JoinableQueue(Queue):
class Channel(object):
def __init__(self):
def __init__(self, maxsize=1):
# We take maxsize to simplify certain kinds of code
if maxsize != 1:
raise ValueError("Channels have a maxsize of 1")
self.getters = collections.deque()
self.putters = collections.deque()
self.hub = get_hub()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment