阻塞当前程序运行, 直到超时

    .. note: 会阻塞当前程序运行

    - 如果 ``timeout大于0``, 则当作 ``计时阻塞器`` 来使用

    .. code:: python

            @run_until(0.1)
            def s2():
                m = 5
                while m:
                    print('s2: ', m, now())
                    time.sleep(1)
                    m -= 1
                return 'good'

    :param timeout: int
    :type timeout:
    :return:
    :rtype:

def block_until_expired(timeout):
    """ 阻塞当前程序运行, 直到超时

    .. note: 会阻塞当前程序运行

    - 如果 ``timeout大于0``, 则当作 ``计时阻塞器`` 来使用

    .. code:: python

            @run_until(0.1)
            def s2():
                m = 5
                while m:
                    print('s2: ', m, now())
                    time.sleep(1)
                    m -= 1
                return 'good'

    :param timeout: int
    :type timeout:
    :return:
    :rtype:
    """
    if not callable(timeout):
        def dec(fn):
            @wraps(fn)
            def wrapper_(*args, **kwargs):
                class TimeLimited(threading.Thread):
                    def __init__(self, _error=None, ):
                        threading.Thread.__init__(self)
                        self.error_ = _error
                        self.result = None
                        self.stopped = False

                    def run(self):
                        self.result = fn(*args, **kwargs)

                try:
                    float(timeout)
                except ValueError as err:
                    print('err: ', err)
                    return None, None

                t = TimeLimited()
                t.start()

                if timeout > 0:
                    t.join(timeout)

                    if t.isAlive():
                        print('[timeout running out for {}]'.format(fn.__name__))
                        _async_raise(t.ident, SystemExit)
                        return None, None

                    return t.error_, t.result

            return wrapper_

        return dec