twisted.py 文件源码

python
阅读 25 收藏 0 点赞 0 评论 0

项目:maas 作者: maas 项目源码 文件源码
def synchronous(func):
    """Decorator to ensure that `func` never runs in the reactor thread.

    If the wrapped function is called from the reactor thread, this will
    raise a :class:`AssertionError`, implying that this is a programming
    error. Calls from outside the reactor will proceed unaffected.

    There is an asymmetry with the `asynchronous` decorator. The reason
    is that it is essential to be aware when `deferToThread()` is being
    used, so that in-reactor code knows to synchronise with it, to add a
    callback to the :class:`Deferred` that it returns, for example. The
    expectation with `asynchronous` is that the return value is always
    important, and will be appropriate to the environment in which it is
    utilised.

    It is possible to programmatically determine if a function has been thusly
    decorated by checking if `ISynchronous` is provided::

      if ISynchronous.providedBy(a_function):
          ...  # a_function has been decorated with @synchronous

    This also serves a secondary documentation purpose; functions decorated
    with this are readily identifiable as synchronous, or blocking.

    :raises AssertionError: When called inside the reactor thread.
    """
    try:
        # A function or method; see PEP 3155.
        func_name = func.__qualname__
    except AttributeError:
        # An instance with a __call__ method.
        func_name = type(func).__qualname__

    @wraps(func)
    def wrapper(*args, **kwargs):
        # isInIOThread() can return True if the reactor has previously been
        # started but has now stopped, so don't test isInIOThread() until
        # we've also checked if the reactor is running.
        if reactor.running and isInIOThread():
            raise AssertionError(
                "Function %s(...) must not be called in the "
                "reactor thread." % func.__name__)
        else:
            result = func(*args, **kwargs)
            if isinstance(result, Deferred):
                args_reprs = chain(
                    map(repr, args), starmap(
                        "{}={!r}".format, kwargs.items()))
                raise TypeError(
                    "Synchronous call returned a Deferred: %s(%s)"
                    % (func_name, ", ".join(args_reprs)))
            else:
                return result

    # This makes it possible to reliably determine programmatically if a
    # function has been decorated with @synchronous.
    interface.directlyProvides(wrapper, ISynchronous)

    return wrapper
评论列表
文章目录


问题


面经


文章

微信
公众号

扫码关注公众号