Commit 54df0039 authored by Jason Madden's avatar Jason Madden

Optimize GeventSelector for large numbers of FDs that aren't ready at the same time.

Similar to ideas in https://github.com/gevent/gevent/pull/1523
parent a51e0937
Add ``gevent.selectors`` containing ``GeventSelector``.
Add ``gevent.selectors`` containing ``GeventSelector``. This selector
implementation uses gevent details to attempt to reduce overhead when
polling many file descriptors, only some of which become ready at any
given time.
This is monkey-patched as ``selectors.DefaultSelector`` by default.
......
......@@ -475,8 +475,8 @@ elif hasattr(__socket__, 'socketpair'):
# cooperatively automatically if we're monkey-patched,
# else we must do it ourself.
_orig_socketpair = __socket__.socketpair
def socketpair(*args, **kwargs):
one, two = _orig_socketpair(*args, **kwargs)
def socketpair(family=_socket.AF_INET, type=_socket.SOCK_STREAM, proto=0):
one, two = _orig_socketpair(family, type, proto)
if not isinstance(one, socket):
one = socket(_sock=one)
two = socket(_sock=two)
......
This diff is collapsed.
......@@ -10,10 +10,10 @@ import gevent.testing as greentest
class SelectorTestMixin(object):
@staticmethod
def run_selector_once(sel):
def run_selector_once(sel, timeout=3):
# Run in a background greenlet, leaving the main
# greenlet free to send data.
events = sel.select(timeout=3)
events = sel.select(timeout=timeout)
for key, mask in events:
key.data(sel, key.fileobj, mask)
gevent.sleep()
......@@ -56,8 +56,12 @@ class GeventSelectorTest(SelectorTestMixin,
self._check_selector(sel)
def test_select_many_sockets(self):
try:
AF_UNIX = socket.AF_UNIX
except AttributeError:
AF_UNIX = None
pairs = [socket.socketpair() for _ in range(10)]
clients = [s[1] for s in pairs]
try:
server_sel = selectors.GeventSelector()
......@@ -67,13 +71,23 @@ class GeventSelectorTest(SelectorTestMixin,
server_sel.register(server, selectors.EVENT_READ,
self.read_from_ready_socket_and_reply)
client_sel.register(client, selectors.EVENT_READ, i)
# Prime them all to be ready at once.
for i, client in enumerate(clients):
# Prime them all to be ready at once.
data = str(i).encode('ascii')
client.send(data)
# Read and reply to all the clients
self.run_selector_once(server_sel)
# Read and reply to all the clients..
# Everyone should be ready, so we ask not to block.
# The call to gevent.idle() is there to make sure that
# all event loop implementations (looking at you, libuv)
# get a chance to poll for IO. Without it, libuv
# doesn't find any results here.
# Not blocking only works for AF_UNIX sockets, though.
# If we got AF_INET (Windows) the data may need some time to
# traverse through the layers.
gevent.idle()
self.run_selector_once(
server_sel,
timeout=-1 if pairs[0][0].family == AF_UNIX else 3)
found = 0
for key, _ in client_sel.select(timeout=3):
......
......@@ -308,6 +308,7 @@ class TestDefaultSpawn(TestCase):
with self.assertRaises(TypeError):
self.ServerClass(self.get_listener(), backlog=25)
@greentest.skipOnLibuvOnCIOnPyPy("Sometimes times out")
def test_backlog_is_accepted_for_address(self):
self.server = self.ServerSubClass((greentest.DEFAULT_BIND_ADDR, 0), backlog=25)
self.assertConnectionRefused()
......
......@@ -743,8 +743,9 @@ else:
future = self._threadpool.spawn(fn, *args, **kwargs)
return _FutureProxy(future)
def shutdown(self, wait=True):
super(ThreadPoolExecutor, self).shutdown(wait)
def shutdown(self, wait=True, **kwargs): # pylint:disable=arguments-differ
# In 3.9, this added ``cancel_futures=False``
super(ThreadPoolExecutor, self).shutdown(wait, **kwargs)
# XXX: We don't implement wait properly
kill = getattr(self._threadpool, 'kill', None)
if kill: # pylint:disable=using-constant-test
......
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