def _wait_core(self, timeout, catch=Timeout): # The core of the wait implementation, handling # switching and linking. If *catch* is set to (), # a timeout that elapses will be allowed to be raised. # Returns a true value if the wait succeeded without timing out. switch = getcurrent().switch # pylint:disable=undefined-variable self.rawlink(switch) try: with Timeout._start_new_or_dummy(timeout) as timer: try: if self.hub is None: self.hub = get_hub() result = self.hub.switch() if result is not self: # pragma: no cover raise InvalidSwitchError( 'Invalid switch into Event.wait(): %r' % (result, )) return True except catch as ex: if ex is not timer: raise # test_set_and_clear and test_timeout in test_threading # rely on the exact return values, not just truthish-ness return False finally: self.unlink(switch)
def __init__(self, maxsize=None, items=(), _warn_depth=2): if maxsize is not None and maxsize <= 0: if maxsize == 0: import warnings warnings.warn( 'Queue(0) now equivalent to Queue(None); if you want a channel, use Channel', DeprecationWarning, stacklevel=_warn_depth) maxsize = None self._maxsize = maxsize if maxsize is not None else -1 # Explicitly maintain order for getters and putters that block # so that callers can consistently rely on getting things out # in the apparent order they went in. This was once required by # imap_unordered. Previously these were set() objects, and the # items put in the set have default hash() and eq() methods; # under CPython, since new objects tend to have increasing # hash values, this tended to roughly maintain order anyway, # but that's not true under PyPy. An alternative to a deque # (to avoid the linear scan of remove()) might be an # OrderedDict, but it's 2.7 only; we don't expect to have so # many waiters that removing an arbitrary element is a # bottleneck, though. self.getters = collections.deque() self.putters = collections.deque() self.hub = get_hub() self._event_unlock = None self.queue = self._create_queue(items)
def _check_and_notify(self): # If this object is ready to be notified, begin the process. if self.ready() and self._links and not self._notifier: if self.hub is None: self.hub = get_hub() self._notifier = self.hub.loop.run_callback(self._notify_links)
def iwait_on_objects(objects, timeout=None, count=None): """ Iteratively yield *objects* as they are ready, until all (or *count*) are ready or *timeout* expired. :param objects: A sequence (supporting :func:`len`) containing objects implementing the wait protocol (rawlink() and unlink()). :keyword int count: If not `None`, then a number specifying the maximum number of objects to wait for. If ``None`` (the default), all objects are waited for. :keyword float timeout: If given, specifies a maximum number of seconds to wait. If the timeout expires before the desired waited-for objects are available, then this method returns immediately. .. seealso:: :func:`wait` .. versionchanged:: 1.1a1 Add the *count* parameter. .. versionchanged:: 1.1a2 No longer raise :exc:`LoopExit` if our caller switches greenlets in between items yielded by this function. """ # QQQ would be nice to support iterable here that can be generated slowly (why?) hub = get_hub() if objects is None: return [hub.join(timeout=timeout)] return _WaitIterator(objects, hub, timeout, count)
def __init__(self, maxsize=None, items=(), _warn_depth=2): if maxsize is not None and maxsize <= 0: if maxsize == 0: import warnings warnings.warn( 'Queue(0) now equivalent to Queue(None); if you want a channel, use Channel', DeprecationWarning, stacklevel=_warn_depth) maxsize = None self._maxsize = maxsize if maxsize is not None else -1 # Explicitly maintain order for getters and putters that block # so that callers can consistently rely on getting things out # in the apparent order they went in. This was once required by # imap_unordered. Previously these were set() objects, and the # items put in the set have default hash() and eq() methods; # under CPython, since new objects tend to have increasing # hash values, this tended to roughly maintain order anyway, # but that's not true under PyPy. An alternative to a deque # (to avoid the linear scan of remove()) might be an # OrderedDict, but it's 2.7 only; we don't expect to have so # many waiters that removing an arbitrary element is a # bottleneck, though. self.getters = collections.deque() self.putters = collections.deque() self.hub = get_hub() self._event_unlock = None self.queue = self._create_queue(items)
def __init__(self, seconds=None, exception=None, ref=True, priority=-1, _one_shot=False): BaseException.__init__(self) self.seconds = seconds self.exception = exception self._one_shot = _one_shot if seconds is None: # Avoid going through the timer codepath if no timeout is # desired; this avoids some CFFI interactions on PyPy that can lead to a # RuntimeError if this implementation is used during an `import` statement. See # https://bitbucket.org/pypy/pypy/issues/2089/crash-in-pypy-260-linux64-with-gevent-11b1 # and https://github.com/gevent/gevent/issues/618. # Plus, in general, it should be more efficient self.timer = _FakeTimer else: # XXX: A timer <= 0 could cause libuv to block the loop; we catch # that case in libuv/loop.py self.timer = get_hub().loop.timer(seconds or 0.0, ref=ref, priority=priority)
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() self._event_unlock = None
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() self._event_unlock = None
def getnameinfo(sockaddr, flags): """ getnameinfo(sockaddr, flags) -> (host, port) Get host and port for a sockaddr. .. seealso:: :doc:`/dns` """ return get_hub().resolver.getnameinfo(sockaddr, flags)
def gethostbyname(hostname): """ gethostbyname(host) -> address Return the IP address (a string of the form '255.255.255.255') for a host. .. seealso:: :doc:`/dns` """ return get_hub().resolver.gethostbyname(hostname)
def gethostbyname(hostname): """ gethostbyname(host) -> address Return the IP address (a string of the form '255.255.255.255') for a host. .. seealso:: :doc:`/dns` """ return get_hub().resolver.gethostbyname(hostname)
def getnameinfo(sockaddr, flags): """ getnameinfo(sockaddr, flags) -> (host, port) Get host and port for a sockaddr. .. seealso:: :doc:`/dns` """ return get_hub().resolver.getnameinfo(sockaddr, flags)
def gethostbyaddr(ip_address): """ gethostbyaddr(ip_address) -> (name, aliaslist, addresslist) Return the true host name, a list of aliases, and a list of IP addresses, for a host. The host argument is a string giving a host name or IP number. .. seealso:: :doc:`/dns` """ return get_hub().resolver.gethostbyaddr(ip_address)
def gethostbyaddr(ip_address): """ gethostbyaddr(ip_address) -> (name, aliaslist, addresslist) Return the true host name, a list of aliases, and a list of IP addresses, for a host. The host argument is a string giving a host name or IP number. .. seealso:: :doc:`/dns` """ return get_hub().resolver.gethostbyaddr(ip_address)
def gethostbyname_ex(hostname): """ gethostbyname_ex(host) -> (name, aliaslist, addresslist) Return the true host name, a list of aliases, and a list of IP addresses, for a host. The host argument is a string giving a host name or IP number. Resolve host and port into list of address info entries. .. seealso:: :doc:`/dns` """ return get_hub().resolver.gethostbyname_ex(hostname)
def gethostbyname_ex(hostname): """ gethostbyname_ex(host) -> (name, aliaslist, addresslist) Return the true host name, a list of aliases, and a list of IP addresses, for a host. The host argument is a string giving a host name or IP number. Resolve host and port into list of address info entries. .. seealso:: :doc:`/dns` """ return get_hub().resolver.gethostbyname_ex(hostname)
def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): # pylint:disable=function-redefined, undefined-variable # Also, on Python 3, we need to translate into the special enums. # Our lower-level resolvers, including the thread and blocking, which use _socket, # function simply with integers. addrlist = get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags) result = [(_intenum_converter(af, AddressFamily), _intenum_converter(socktype, SocketKind), proto, canonname, sa) for af, socktype, proto, canonname, sa in addrlist] return result
def _capture_hub(self, create): # Subclasses should call this as the first action from any # public method that could, in theory, block and switch # to the hub. This may release the GIL. if self.hub is None: # This next line might release the GIL. current_hub = get_hub() if create else get_hub_if_exists() if current_hub is None: return # We have the GIL again. Did anything change? If so, # we lost the race. if self.hub is None: self.hub = current_hub
def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): # pylint:disable=function-redefined, undefined-variable # Also, on Python 3, we need to translate into the special enums. # Our lower-level resolvers, including the thread and blocking, which use _socket, # function simply with integers. addrlist = get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags) result = [ (_intenum_converter(af, AddressFamily), _intenum_converter(socktype, SocketKind), proto, canonname, sa) for af, socktype, proto, canonname, sa in addrlist ] return result
def __init__(self): # Also previously, AsyncResult maintained the order of notifications, but Event # did not; this implementation does not. (Event also only call callbacks one # time (set), but AsyncResult permitted duplicates.) # HOWEVER, gevent.queue.Queue does guarantee the order of getters relative # to putters. Some existing documentation out on the net likes to refer to # gevent as "deterministic", such that running the same program twice will # produce results in the same order (so long as I/O isn't involved). This could # be an argument to maintain order. (One easy way to do that while guaranteeing # uniqueness would be with a 2.7+ OrderedDict.) self._links = set() self.hub = get_hub() self._notifier = None
def wait_read(fileno, timeout=None, timeout_exc=_NONE): """ wait_read(fileno, timeout=None, [timeout_exc=None]) -> None Block the current greenlet until *fileno* is ready to read. For the meaning of the other parameters and possible exceptions, see :func:`wait`. .. seealso:: :func:`cancel_wait` """ hub = get_hub() io = hub.loop.io(fileno, 1) try: return wait_on_watcher(io, timeout, timeout_exc, hub) finally: io.close()
def wait_read(fileno, timeout=None, timeout_exc=_NONE): """ wait_read(fileno, timeout=None, [timeout_exc=None]) -> None Block the current greenlet until *fileno* is ready to read. For the meaning of the other parameters and possible exceptions, see :func:`wait`. .. seealso:: :func:`cancel_wait` """ hub = get_hub() io = hub.loop.io(fileno, 1) try: return wait_on_watcher(io, timeout, timeout_exc, hub) finally: io.close()
def getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0): """ Resolve host and port into list of address info entries. Translate the host/port argument into a sequence of 5-tuples that contain all the necessary arguments for creating a socket connected to that service. host is a domain name, a string representation of an IPv4/v6 address or None. port is a string service name such as 'http', a numeric port number or None. By passing None as the value of host and port, you can pass NULL to the underlying C API. The family, type and proto arguments can be optionally specified in order to narrow the list of addresses returned. Passing zero as a value for each of these arguments selects the full range of results. .. seealso:: :doc:`/dns` """ return get_hub().resolver.getaddrinfo(host, port, family, socktype, proto, flags)
def getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0): """ Resolve host and port into list of address info entries. Translate the host/port argument into a sequence of 5-tuples that contain all the necessary arguments for creating a socket connected to that service. host is a domain name, a string representation of an IPv4/v6 address or None. port is a string service name such as 'http', a numeric port number or None. By passing None as the value of host and port, you can pass NULL to the underlying C API. The family, type and proto arguments can be optionally specified in order to narrow the list of addresses returned. Passing zero as a value for each of these arguments selects the full range of results. .. seealso:: :doc:`/dns` """ return get_hub().resolver.getaddrinfo(host, port, family, socktype, proto, flags)
def _primitive_wait(watcher, timeout, timeout_exc, hub): if watcher.callback is not None: raise ConcurrentObjectUseError( 'This socket is already used by another greenlet: %r' % (watcher.callback, )) if hub is None: hub = get_hub() if timeout is None: hub.wait(watcher) return timeout = Timeout._start_new_or_dummy( timeout, (timeout_exc if timeout_exc is not _NONE or timeout is None else _timeout_error('timed out'))) with timeout: hub.wait(watcher)
def _primitive_wait(watcher, timeout, timeout_exc, hub): if watcher.callback is not None: raise ConcurrentObjectUseError('This socket is already used by another greenlet: %r' % (watcher.callback, )) if hub is None: hub = get_hub() if timeout is None: hub.wait(watcher) return timeout = Timeout._start_new_or_dummy( timeout, (timeout_exc if timeout_exc is not _NONE or timeout is None else _timeout_error('timed out'))) with timeout: hub.wait(watcher)
def wait_write(fileno, timeout=None, timeout_exc=_NONE, event=_NONE): """ wait_write(fileno, timeout=None, [timeout_exc=None]) -> None Block the current greenlet until *fileno* is ready to write. For the meaning of the other parameters and possible exceptions, see :func:`wait`. .. deprecated:: 1.1 The keyword argument *event* is ignored. Applications should not pass this parameter. In the future, doing so will become an error. .. seealso:: :func:`cancel_wait` """ # pylint:disable=unused-argument hub = get_hub() io = hub.loop.io(fileno, 2) try: return wait_on_watcher(io, timeout, timeout_exc, hub) finally: io.close()
def wait_write(fileno, timeout=None, timeout_exc=_NONE, event=_NONE): """ wait_write(fileno, timeout=None, [timeout_exc=None]) -> None Block the current greenlet until *fileno* is ready to write. For the meaning of the other parameters and possible exceptions, see :func:`wait`. .. deprecated:: 1.1 The keyword argument *event* is ignored. Applications should not pass this parameter. In the future, doing so will become an error. .. seealso:: :func:`cancel_wait` """ # pylint:disable=unused-argument hub = get_hub() io = hub.loop.io(fileno, 2) try: return wait_on_watcher(io, timeout, timeout_exc, hub) finally: io.close()
def wait_on_objects(objects=None, timeout=None, count=None): """ Wait for ``objects`` to become ready or for event loop to finish. If ``objects`` is provided, it must be a list containing objects implementing the wait protocol (rawlink() and unlink() methods): - :class:`gevent.Greenlet` instance - :class:`gevent.event.Event` instance - :class:`gevent.lock.Semaphore` instance - :class:`gevent.subprocess.Popen` instance If ``objects`` is ``None`` (the default), ``wait()`` blocks until the current event loop has nothing to do (or until ``timeout`` passes): - all greenlets have finished - all servers were stopped - all event loop watchers were stopped. If ``count`` is ``None`` (the default), wait for all ``objects`` to become ready. If ``count`` is a number, wait for (up to) ``count`` objects to become ready. (For example, if count is ``1`` then the function exits when any object in the list is ready). If ``timeout`` is provided, it specifies the maximum number of seconds ``wait()`` will block. Returns the list of ready objects, in the order in which they were ready. .. seealso:: :func:`iwait` """ if objects is None: hub = get_hub() return hub.join(timeout=timeout) # pylint:disable= return list(iwait_on_objects(objects, timeout, count))
def wait_on_objects(objects=None, timeout=None, count=None): """ Wait for ``objects`` to become ready or for event loop to finish. If ``objects`` is provided, it must be a list containing objects implementing the wait protocol (rawlink() and unlink() methods): - :class:`gevent.Greenlet` instance - :class:`gevent.event.Event` instance - :class:`gevent.lock.Semaphore` instance - :class:`gevent.subprocess.Popen` instance If ``objects`` is ``None`` (the default), ``wait()`` blocks until the current event loop has nothing to do (or until ``timeout`` passes): - all greenlets have finished - all servers were stopped - all event loop watchers were stopped. If ``count`` is ``None`` (the default), wait for all ``objects`` to become ready. If ``count`` is a number, wait for (up to) ``count`` objects to become ready. (For example, if count is ``1`` then the function exits when any object in the list is ready). If ``timeout`` is provided, it specifies the maximum number of seconds ``wait()`` will block. Returns the list of ready objects, in the order in which they were ready. .. seealso:: :func:`iwait` """ if objects is None: hub = get_hub() return hub.join(timeout=timeout) # pylint:disable= return list(iwait_on_objects(objects, timeout, count))
def iwait_on_objects(objects, timeout=None, count=None): """ Iteratively yield *objects* as they are ready, until all (or *count*) are ready or *timeout* expired. If you will only be consuming a portion of the *objects*, you should do so inside a ``with`` block on this object to avoid leaking resources:: with gevent.iwait((a, b, c)) as it: for i in it: if i is a: break :param objects: A sequence (supporting :func:`len`) containing objects implementing the wait protocol (rawlink() and unlink()). :keyword int count: If not `None`, then a number specifying the maximum number of objects to wait for. If ``None`` (the default), all objects are waited for. :keyword float timeout: If given, specifies a maximum number of seconds to wait. If the timeout expires before the desired waited-for objects are available, then this method returns immediately. .. seealso:: :func:`wait` .. versionchanged:: 1.1a1 Add the *count* parameter. .. versionchanged:: 1.1a2 No longer raise :exc:`LoopExit` if our caller switches greenlets in between items yielded by this function. .. versionchanged:: 1.4 Add support to use the returned object as a context manager. """ # QQQ would be nice to support iterable here that can be generated slowly (why?) hub = get_hub() if objects is None: return [hub.join(timeout=timeout)] return _WaitIterator(objects, hub, timeout, count)
def _capture_hub(self, create): # Subclasses should call this as the first action from any # public method that could, in theory, block and switch # to the hub. This may release the GIL. It may # raise InvalidThreadUseError if the result would # First, detect a dead hub and drop it. while 1: my_hub = self.hub if my_hub is None: break if my_hub.dead: # dead is a property, could release GIL # back, holding GIL if self.hub is my_hub: self.hub = None my_hub = None break else: break if self.hub is None: # This next line might release the GIL. current_hub = get_hub() if create else get_hub_if_exists() # We have the GIL again. Did anything change? If so, # we lost the race. if self.hub is None: self.hub = current_hub if self.hub is not None and self.hub.thread_ident != _get_thread_ident( ): raise InvalidThreadUseError( self.hub, get_hub_if_exists(), getcurrent() # pylint:disable=undefined-variable ) return self.hub
def __init__(self, run=None, *args, **kwargs): """ :param args: The arguments passed to the ``run`` function. :param kwargs: The keyword arguments passed to the ``run`` function. :keyword callable run: The callable object to run. If not given, this object's `_run` method will be invoked (typically defined by subclasses). .. versionchanged:: 1.1b1 The ``run`` argument to the constructor is now verified to be a callable object. Previously, passing a non-callable object would fail after the greenlet was spawned. .. versionchanged:: 1.3b1 The ``GEVENT_TRACK_GREENLET_TREE`` configuration value may be set to a false value to disable ``spawn_tree_locals``, ``spawning_greenlet``, and ``spawning_stack``. The first two will be None in that case, and the latter will be empty. .. versionchanged:: 1.5 Greenlet objects are now more careful to verify that their ``parent`` is really a gevent hub, raising a ``TypeError`` earlier instead of an ``AttributeError`` later. """ # The attributes are documented in the .rst file # greenlet.greenlet(run=None, parent=None) # Calling it with both positional arguments instead of a keyword # argument (parent=get_hub()) speeds up creation of this object ~30%: # python -m timeit -s 'import gevent' 'gevent.Greenlet()' # Python 3.5: 2.70usec with keywords vs 1.94usec with positional # Python 3.4: 2.32usec with keywords vs 1.74usec with positional # Python 3.3: 2.55usec with keywords vs 1.92usec with positional # Python 2.7: 1.73usec with keywords vs 1.40usec with positional # Timings taken Feb 21 2018 prior to integration of #755 # python -m perf timeit -s 'import gevent' 'gevent.Greenlet()' # 3.6.4 : Mean +- std dev: 1.08 us +- 0.05 us # 2.7.14 : Mean +- std dev: 1.44 us +- 0.06 us # PyPy2 5.10.0: Mean +- std dev: 2.14 ns +- 0.08 ns # After the integration of spawning_stack, spawning_greenlet, # and spawn_tree_locals on that same date: # 3.6.4 : Mean +- std dev: 8.92 us +- 0.36 us -> 8.2x # 2.7.14 : Mean +- std dev: 14.8 us +- 0.5 us -> 10.2x # PyPy2 5.10.0: Mean +- std dev: 3.24 us +- 0.17 us -> 1.5x # Compiling with Cython gets us to these numbers: # 3.6.4 : Mean +- std dev: 3.63 us +- 0.14 us # 2.7.14 : Mean +- std dev: 3.37 us +- 0.20 us # PyPy2 5.10.0 : Mean +- std dev: 4.44 us +- 0.28 us # Switching to reified frames and some more tuning gets us here: # 3.7.2 : Mean +- std dev: 2.53 us +- 0.15 us # 2.7.16 : Mean +- std dev: 2.35 us +- 0.12 us # PyPy2 7.1 : Mean +- std dev: 11.6 us +- 0.4 us # Compared to the released 1.4 (tested at the same time): # 3.7.2 : Mean +- std dev: 3.21 us +- 0.32 us # 2.7.16 : Mean +- std dev: 3.11 us +- 0.19 us # PyPy2 7.1 : Mean +- std dev: 12.3 us +- 0.8 us _greenlet__init__(self, None, get_hub()) if run is not None: self._run = run # If they didn't pass a callable at all, then they must # already have one. Note that subclassing to override the run() method # itself has never been documented or supported. if not callable(self._run): raise TypeError("The run argument or self._run must be callable") self.args = args self.kwargs = kwargs self.value = None #: An event, such as a timer or a callback that fires. It is established in #: start() and start_later() as those two objects, respectively. #: Once this becomes non-None, the Greenlet cannot be started again. Conversely, #: kill() and throw() check for non-None to determine if this object has ever been #: scheduled for starting. A placeholder _cancelled_start_event is assigned by them to prevent #: the greenlet from being started in the future, if necessary. #: In the usual case, this transitions as follows: None -> event -> _start_completed_event. #: A value of None means we've never been started. self._start_event = None self._notifier = None self._formatted_info = None self._links = [] self._ident = None # Initial state: None. # Completed successfully: (None, None, None) # Failed with exception: (t, v, dump_traceback(tb))) self._exc_info = None if GEVENT_CONFIG.track_greenlet_tree: spawner = getcurrent() # pylint:disable=undefined-variable self.spawning_greenlet = wref(spawner) try: self.spawn_tree_locals = spawner.spawn_tree_locals except AttributeError: self.spawn_tree_locals = {} if get_generic_parent(spawner) is not None: # pylint:disable=undefined-variable # The main greenlet has no parent. # Its children get separate locals. spawner.spawn_tree_locals = self.spawn_tree_locals self.spawning_stack = _extract_stack(self.spawning_stack_limit) # Don't copy the spawning greenlet's # '_spawning_stack_frames' into ours. That's somewhat # confusing, and, if we're not careful, a deep spawn tree # can lead to excessive memory usage (an infinite spawning # tree could lead to unbounded memory usage without care # --- see https://github.com/gevent/gevent/issues/1371) # The _spawning_stack_frames may be cleared out later if we access spawning_stack else: # None is the default for all of these in Cython, but we # need to declare them for pure-Python mode. self.spawning_greenlet = None self.spawn_tree_locals = None self.spawning_stack = None
def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): # pylint:disable=function-redefined return get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags)
def __init__(self, run=None, *args, **kwargs): """ :param args: The arguments passed to the ``run`` function. :param kwargs: The keyword arguments passed to the ``run`` function. :keyword callable run: The callable object to run. If not given, this object's `_run` method will be invoked (typically defined by subclasses). .. versionchanged:: 1.1b1 The ``run`` argument to the constructor is now verified to be a callable object. Previously, passing a non-callable object would fail after the greenlet was spawned. .. rubric:: Attributes .. attribute:: value Holds the value returned by the function if the greenlet has finished successfully. Until then, or if it finished in error, `None`. .. tip:: Recall that a greenlet killed with the default :class:`GreenletExit` is considered to have finished successfully, and the `GreenletExit` exception will be its value. .. attribute:: spawn_tree_locals A dictionary that is shared between all the greenlets in a "spawn tree", that is, a spawning greenlet and all its descendent greenlets. All children of the main (root) greenlet start their own spawn trees. Assign a new dictionary to this attribute on an instance of this class to create a new spawn tree (as far as locals are concerned). .. versionadded:: 1.3a2 .. attribute:: spawning_greenlet A weak-reference to the greenlet that was current when this object was created. Note that the :attr:`parent` attribute is always the hub. .. versionadded:: 1.3a2 .. attribute:: spawning_stack A lightweight frame-like object capturing the stack when this greenlet was created as well as the stack when the spawning greenlet was created (if applicable). This can be passed to :func:`traceback.print_stack`. .. versionadded:: 1.3a2 .. attribute:: spawning_stack_limit A class attribute specifying how many levels of the spawning stack will be kept. Specify a smaller number for higher performance, spawning greenlets, specify a larger value for improved debugging. .. versionadded:: 1.3a2 .. versionchanged:: 1.3b1 The ``GEVENT_TRACK_GREENLET_TREE`` configuration value may be set to a false value to disable ``spawn_tree_locals``, ``spawning_greenlet``, and ``spawning_stack``. The first two will be None in that case, and the latter will be empty. """ # greenlet.greenlet(run=None, parent=None) # Calling it with both positional arguments instead of a keyword # argument (parent=get_hub()) speeds up creation of this object ~30%: # python -m timeit -s 'import gevent' 'gevent.Greenlet()' # Python 3.5: 2.70usec with keywords vs 1.94usec with positional # Python 3.4: 2.32usec with keywords vs 1.74usec with positional # Python 3.3: 2.55usec with keywords vs 1.92usec with positional # Python 2.7: 1.73usec with keywords vs 1.40usec with positional # Timings taken Feb 21 2018 prior to integration of #755 # python -m perf timeit -s 'import gevent' 'gevent.Greenlet()' # 3.6.4 : Mean +- std dev: 1.08 us +- 0.05 us # 2.7.14 : Mean +- std dev: 1.44 us +- 0.06 us # PyPy2 5.10.0: Mean +- std dev: 2.14 ns +- 0.08 ns # After the integration of spawning_stack, spawning_greenlet, # and spawn_tree_locals on that same date: # 3.6.4 : Mean +- std dev: 8.92 us +- 0.36 us -> 8.2x # 2.7.14 : Mean +- std dev: 14.8 us +- 0.5 us -> 10.2x # PyPy2 5.10.0: Mean +- std dev: 3.24 us +- 0.17 us -> 1.5x # Compiling with Cython gets us to these numbers: # 3.6.4 : Mean +- std dev: 3.63 us +- 0.14 us # 2.7.14 : Mean +- std dev: 3.37 us +- 0.20 us # PyPy2 5.10.0 : Mean +- std dev: 4.44 us +- 0.28 us _greenlet__init__(self, None, get_hub()) if run is not None: self._run = run # If they didn't pass a callable at all, then they must # already have one. Note that subclassing to override the run() method # itself has never been documented or supported. if not callable(self._run): raise TypeError("The run argument or self._run must be callable") self.args = args self.kwargs = kwargs self.value = None #: An event, such as a timer or a callback that fires. It is established in #: start() and start_later() as those two objects, respectively. #: Once this becomes non-None, the Greenlet cannot be started again. Conversely, #: kill() and throw() check for non-None to determine if this object has ever been #: scheduled for starting. A placeholder _dummy_event is assigned by them to prevent #: the greenlet from being started in the future, if necessary. self._start_event = None self._notifier = None self._formatted_info = None self._links = [] self._ident = None # Initial state: None. # Completed successfully: (None, None, None) # Failed with exception: (t, v, dump_traceback(tb))) self._exc_info = None if GEVENT_CONFIG.track_greenlet_tree: spawner = getcurrent() # pylint:disable=undefined-variable self.spawning_greenlet = wref(spawner) try: self.spawn_tree_locals = spawner.spawn_tree_locals except AttributeError: self.spawn_tree_locals = {} if spawner.parent is not None: # The main greenlet has no parent. # Its children get separate locals. spawner.spawn_tree_locals = self.spawn_tree_locals self._spawning_stack_frames = _extract_stack(self.spawning_stack_limit) self._spawning_stack_frames.extend(getattr(spawner, '_spawning_stack_frames', [])) else: # None is the default for all of these in Cython, but we # need to declare them for pure-Python mode. self.spawning_greenlet = None self.spawn_tree_locals = None self._spawning_stack_frames = None
def cancel_wait(watcher, error=cancel_wait_ex): """See :meth:`gevent.hub.Hub.cancel_wait`""" get_hub().cancel_wait(watcher, error)
def __call__(self, source): g = greenlet(self.callback, get_hub()) g.switch(source)
def __init__(self, run=None, *args, **kwargs): """ :param args: The arguments passed to the ``run`` function. :param kwargs: The keyword arguments passed to the ``run`` function. :keyword callable run: The callable object to run. If not given, this object's `_run` method will be invoked (typically defined by subclasses). .. versionchanged:: 1.1b1 The ``run`` argument to the constructor is now verified to be a callable object. Previously, passing a non-callable object would fail after the greenlet was spawned. .. versionchanged:: 1.3b1 The ``GEVENT_TRACK_GREENLET_TREE`` configuration value may be set to a false value to disable ``spawn_tree_locals``, ``spawning_greenlet``, and ``spawning_stack``. The first two will be None in that cases, and the latter will be empty. """ # The attributes are documented in the .rst file # greenlet.greenlet(run=None, parent=None) # Calling it with both positional arguments instead of a keyword # argument (parent=get_hub()) speeds up creation of this object ~30%: # python -m timeit -s 'import gevent' 'gevent.Greenlet()' # Python 3.5: 2.70usec with keywords vs 1.94usec with positional # Python 3.4: 2.32usec with keywords vs 1.74usec with positional # Python 3.3: 2.55usec with keywords vs 1.92usec with positional # Python 2.7: 1.73usec with keywords vs 1.40usec with positional # Timings taken Feb 21 2018 prior to integration of #755 # python -m perf timeit -s 'import gevent' 'gevent.Greenlet()' # 3.6.4 : Mean +- std dev: 1.08 us +- 0.05 us # 2.7.14 : Mean +- std dev: 1.44 us +- 0.06 us # PyPy2 5.10.0: Mean +- std dev: 2.14 ns +- 0.08 ns # After the integration of spawning_stack, spawning_greenlet, # and spawn_tree_locals on that same date: # 3.6.4 : Mean +- std dev: 8.92 us +- 0.36 us -> 8.2x # 2.7.14 : Mean +- std dev: 14.8 us +- 0.5 us -> 10.2x # PyPy2 5.10.0: Mean +- std dev: 3.24 us +- 0.17 us -> 1.5x # Compiling with Cython gets us to these numbers: # 3.6.4 : Mean +- std dev: 3.63 us +- 0.14 us # 2.7.14 : Mean +- std dev: 3.37 us +- 0.20 us # PyPy2 5.10.0 : Mean +- std dev: 4.44 us +- 0.28 us _greenlet__init__(self, None, get_hub()) if run is not None: self._run = run # If they didn't pass a callable at all, then they must # already have one. Note that subclassing to override the run() method # itself has never been documented or supported. if not callable(self._run): raise TypeError("The run argument or self._run must be callable") self.args = args self.kwargs = kwargs self.value = None #: An event, such as a timer or a callback that fires. It is established in #: start() and start_later() as those two objects, respectively. #: Once this becomes non-None, the Greenlet cannot be started again. Conversely, #: kill() and throw() check for non-None to determine if this object has ever been #: scheduled for starting. A placeholder _dummy_event is assigned by them to prevent #: the greenlet from being started in the future, if necessary. self._start_event = None self._notifier = None self._formatted_info = None self._links = [] self._ident = None # Initial state: None. # Completed successfully: (None, None, None) # Failed with exception: (t, v, dump_traceback(tb))) self._exc_info = None if GEVENT_CONFIG.track_greenlet_tree: spawner = getcurrent() # pylint:disable=undefined-variable self.spawning_greenlet = wref(spawner) try: self.spawn_tree_locals = spawner.spawn_tree_locals except AttributeError: self.spawn_tree_locals = {} if spawner.parent is not None: # The main greenlet has no parent. # Its children get separate locals. spawner.spawn_tree_locals = self.spawn_tree_locals self._spawning_stack_frames = _extract_stack( self.spawning_stack_limit) self._spawning_stack_frames.extend( getattr(spawner, '_spawning_stack_frames', [])) else: # None is the default for all of these in Cython, but we # need to declare them for pure-Python mode. self.spawning_greenlet = None self.spawn_tree_locals = None self._spawning_stack_frames = None
def __call__(self, source): g = greenlet(self.callback, get_hub()) g.switch(source)
def cancel_wait(watcher, error=cancel_wait_ex): """See :meth:`gevent.hub.Hub.cancel_wait`""" get_hub().cancel_wait(watcher, error)
def __wait_to_be_notified(self, rawlink): # pylint:disable=too-many-branches # We've got to watch where we could potentially release the GIL. # Decisions we make based an the state of this object must be in blocks # that cannot release the GIL. resume_this_greenlet = None watcher = None current_hub = get_hub() send = None while 1: my_hub = self.hub if my_hub is current_hub: break # We're owned by another hub. if my_hub.dead: # dead is a property, this could have released the GIL. # We have the GIL back. Did anything change? if my_hub is not self.hub: continue # start over. # The other hub is dead, so we can take ownership. self.hub = current_hub break # Some other hub owns this object. We must ask it to wake us # up. We can't use a Python-level ``Lock`` because # (1) it doesn't support a timeout on all platforms; and # (2) we don't want to block this hub from running. So we need to # do so in a way that cooperates with *two* hubs. That's what an # async watcher is built for. # # Allocating and starting the watcher *could* release the GIL. # with the libev corcext, allocating won't, but starting briefly will. # With other backends, allocating might, and starting might also. # So...XXX: Race condition here, tiny though it may be. watcher = current_hub.loop.async_() send = watcher.send_ignoring_arg if rawlink: # Make direct calls to self.rawlink, the most common case, # so cython can more easily optimize. self.rawlink(send) else: self._notifier.args[0].append(send) watcher.start(getcurrent().switch, self) # pylint:disable=undefined-variable break if self.hub is current_hub: resume_this_greenlet = getcurrent().switch # pylint:disable=undefined-variable if rawlink: self.rawlink(resume_this_greenlet) else: self._notifier.args[0].append(resume_this_greenlet) try: self._drop_lock_for_switch_out() result = current_hub.switch() # Probably releases # If we got here, we were automatically unlinked already. resume_this_greenlet = None if result is not self: # pragma: no cover raise InvalidSwitchError('Invalid switch into %s.wait(): %r' % ( self.__class__.__name__, result, )) finally: self._acquire_lock_for_switch_in() self.__unlink_all(resume_this_greenlet) self.__unlink_all(send) if watcher is not None: watcher.stop() watcher.close()
def acquire(self, blocking=True, timeout=None): """ acquire(blocking=True, timeout=None) -> bool Acquire the semaphore. .. note:: If this semaphore was initialized with a *value* of 0, this method will block forever (unless a timeout is given or blocking is set to false). :keyword bool blocking: If True (the default), this function will block until the semaphore is acquired. :keyword float timeout: If given, and *blocking* is true, specifies the maximum amount of seconds this method will block. :return: A `bool` indicating whether the semaphore was acquired. If ``blocking`` is True and ``timeout`` is None (the default), then (so long as this semaphore was initialized with a size greater than 0) this will always return True. If a timeout was given, and it expired before the semaphore was acquired, False will be returned. (Note that this can still raise a ``Timeout`` exception, if some other caller had already started a timer.) """ # pylint:disable=too-many-return-statements,too-many-branches # Sadly, the body of this method is rather complicated. if self._multithreaded is _UNSET: self._multithreaded = self._get_thread_ident() elif self._multithreaded != self._get_thread_ident(): self._multithreaded = _MULTI # We conceptually now belong to the hub of the thread that # called this, whether or not we have to block. Note that we # cannot force it to be created yet, because Semaphore is used # by importlib.ModuleLock which is used when importing the hub # itself! This also checks for cross-thread issues. invalid_thread_use = None try: self._capture_hub(False) except InvalidThreadUseError as e: # My hub belongs to some other thread. We didn't release the GIL/object lock # by raising the exception, so we know this is still true. invalid_thread_use = e.args e = None if not self.counter and blocking: # We would need to block. So coordinate with the main hub. return self.__acquire_from_other_thread( invalid_thread_use, blocking, timeout) if self.counter > 0: self.counter -= 1 return True if not blocking: return False if self._multithreaded is not _MULTI and self.hub is None: # pylint:disable=access-member-before-definition self.hub = get_hub() # pylint:disable=attribute-defined-outside-init if self.hub is None and not invalid_thread_use: # Someone else is holding us. There's not a hub here, # nor is there a hub in that thread. We'll need to use regular locks. # This will be unfair to yet a third thread that tries to use us with greenlets. return self.__acquire_from_other_thread( (None, None, self._getcurrent(), "NoHubs"), blocking, timeout) # self._wait may drop both the GIL and the _lock_lock. # By the time we regain control, both have been reacquired. try: success = self._wait(timeout) except LoopExit as ex: args = ex.args ex = None if self.counter: success = True else: # Avoid using ex.hub property to keep holding the GIL if len(args) == 3 and args[1].main_hub: # The main hub, meaning the main thread. We probably can do nothing with this. raise return self.__acquire_from_other_thread( (self.hub, get_hub_if_exists(), self._getcurrent(), "LoopExit"), blocking, timeout) if not success: assert timeout is not None # Our timer expired. return False # Neither our timer or another one expired, so we blocked until # awoke. Therefore, the counter is ours assert self.counter > 0, ( self.counter, blocking, timeout, success, ) self.counter -= 1 return True
def __init__(self, hub=None): self.hub = get_hub() if hub is None else hub self.greenlet = None self.value = None self._exception = _NONE
def __init__(self, run=None, *args, **kwargs): """ :param args: The arguments passed to the ``run`` function. :param kwargs: The keyword arguments passed to the ``run`` function. :keyword callable run: The callable object to run. If not given, this object's `_run` method will be invoked (typically defined by subclasses). .. versionchanged:: 1.1b1 The ``run`` argument to the constructor is now verified to be a callable object. Previously, passing a non-callable object would fail after the greenlet was spawned. .. versionchanged:: 1.3b1 The ``GEVENT_TRACK_GREENLET_TREE`` configuration value may be set to a false value to disable ``spawn_tree_locals``, ``spawning_greenlet``, and ``spawning_stack``. The first two will be None in that case, and the latter will be empty. """ # The attributes are documented in the .rst file # greenlet.greenlet(run=None, parent=None) # Calling it with both positional arguments instead of a keyword # argument (parent=get_hub()) speeds up creation of this object ~30%: # python -m timeit -s 'import gevent' 'gevent.Greenlet()' # Python 3.5: 2.70usec with keywords vs 1.94usec with positional # Python 3.4: 2.32usec with keywords vs 1.74usec with positional # Python 3.3: 2.55usec with keywords vs 1.92usec with positional # Python 2.7: 1.73usec with keywords vs 1.40usec with positional # Timings taken Feb 21 2018 prior to integration of #755 # python -m perf timeit -s 'import gevent' 'gevent.Greenlet()' # 3.6.4 : Mean +- std dev: 1.08 us +- 0.05 us # 2.7.14 : Mean +- std dev: 1.44 us +- 0.06 us # PyPy2 5.10.0: Mean +- std dev: 2.14 ns +- 0.08 ns # After the integration of spawning_stack, spawning_greenlet, # and spawn_tree_locals on that same date: # 3.6.4 : Mean +- std dev: 8.92 us +- 0.36 us -> 8.2x # 2.7.14 : Mean +- std dev: 14.8 us +- 0.5 us -> 10.2x # PyPy2 5.10.0: Mean +- std dev: 3.24 us +- 0.17 us -> 1.5x # Compiling with Cython gets us to these numbers: # 3.6.4 : Mean +- std dev: 3.63 us +- 0.14 us # 2.7.14 : Mean +- std dev: 3.37 us +- 0.20 us # PyPy2 5.10.0 : Mean +- std dev: 4.44 us +- 0.28 us _greenlet__init__(self, None, get_hub()) if run is not None: self._run = run # If they didn't pass a callable at all, then they must # already have one. Note that subclassing to override the run() method # itself has never been documented or supported. if not callable(self._run): raise TypeError("The run argument or self._run must be callable") self.args = args self.kwargs = kwargs self.value = None #: An event, such as a timer or a callback that fires. It is established in #: start() and start_later() as those two objects, respectively. #: Once this becomes non-None, the Greenlet cannot be started again. Conversely, #: kill() and throw() check for non-None to determine if this object has ever been #: scheduled for starting. A placeholder _dummy_event is assigned by them to prevent #: the greenlet from being started in the future, if necessary. self._start_event = None self._notifier = None self._formatted_info = None self._links = [] self._ident = None # Initial state: None. # Completed successfully: (None, None, None) # Failed with exception: (t, v, dump_traceback(tb))) self._exc_info = None if GEVENT_CONFIG.track_greenlet_tree: spawner = getcurrent() # pylint:disable=undefined-variable self.spawning_greenlet = wref(spawner) try: self.spawn_tree_locals = spawner.spawn_tree_locals except AttributeError: self.spawn_tree_locals = {} if spawner.parent is not None: # The main greenlet has no parent. # Its children get separate locals. spawner.spawn_tree_locals = self.spawn_tree_locals self._spawning_stack_frames = _extract_stack(self.spawning_stack_limit) self._spawning_stack_frames.extend(getattr(spawner, '_spawning_stack_frames', [])) else: # None is the default for all of these in Cython, but we # need to declare them for pure-Python mode. self.spawning_greenlet = None self.spawn_tree_locals = None self._spawning_stack_frames = None