编程语言中的 timeout 原理是什么?
比如下面代码示例中的 timeout
import requestsrequests.get(url = 'http://www.google.com.hk', timeout=5)
代码中不存在一个计时线程来实现 timeout,我盲猜,实现的原理就是:用户程序向操作系统注册一个 timeout 的 timer,时间到了,操作系统就给应用程序一个中断信号。是这样吗?
如果我想自己实现一个任意 timeout 的程序,应该怎么做?
不限于 HTTP 的 timeout
OS 提供了什么 API 让我做这件事情?
有什么资料可供参考,使得我了解更多吗?
我需要的是一个任意解,调用任何即便没有任何系统调用的函数,都可以任意设置 timeout 的解决方案
回答:
不一定,有的是定时器,有的是用 select 模拟的,有的是操作系统 API 本身就提供了 timeout 相关设置。
但要是具体到某一个接口上的话,我们看源码就知道它是如何实现的了:
# REF: https://github.com/psf/requests/blob/main/requests/adapters.py#L499resp = conn.urlopen(
method=request.method,
url=url,
body=request.body,
headers=request.headers,
redirect=False,
assert_same_host=False,
preload_content=False,
decode_content=False,
retries=self.max_retries,
timeout=timeout,
)
timeout 参数最后传进了 conn.urlopen 方法里,而 conn 是 urllib3 库里提供的对象,那我们接着跟踪:
# REF: https://github.com/urllib3/urllib3/blob/main/src/urllib3/util/wait.pydef poll_wait_for_socket(
sock: socket.socket,
read: bool = False,
write: bool = False,
timeout: Optional[float] = None,
) -> bool:
if not read and not write:
raise RuntimeError("must specify at least one of read=True, write=True")
mask = 0
if read:
mask |= select.POLLIN
if write:
mask |= select.POLLOUT
poll_obj = select.poll()
poll_obj.register(sock, mask)
# For some reason, poll() takes timeout in milliseconds
def do_poll(t: Optional[float]) -> List[Tuple[int, int]]:
if t is not None:
t *= 1000
return poll_obj.poll(t)
return bool(do_poll(timeout))
def _have_working_poll() -> bool:
# Apparently some systems have a select.poll that fails as soon as you try
# to use it, either due to strange configuration or broken monkeypatching
# from libraries like eventlet/greenlet.
try:
poll_obj = select.poll()
poll_obj.poll(0)
except (AttributeError, OSError):
return False
else:
return True
def wait_for_socket(
sock: socket.socket,
read: bool = False,
write: bool = False,
timeout: Optional[float] = None,
) -> bool:
# We delay choosing which implementation to use until the first time we're
# called. We could do it at import time, but then we might make the wrong
# decision if someone goes wild with monkeypatching select.poll after
# we're imported.
global wait_for_socket
if _have_working_poll():
wait_for_socket = poll_wait_for_socket
elif hasattr(select, "select"):
wait_for_socket = select_wait_for_socket
return wait_for_socket(sock, read, write, timeout)
发现是用 select 模拟的。
最后 Python 中如果你想用的比较通用的超时机制的话,可以用 eventlet.Timeout
/gevent.Timeout
来实现。你也可以像你在题目里说的那样,用 signal 自己封装一下,不过由于 Windows 下不支持 signal,所以如果你有跨平台的需要的话就不能这么做了。
回答:
用signal可以在线程级别上timeout, 具体看看代码
import signalfrom contextlib import contextmanager
from functools import wraps
@contextmanager
def timeout_signal(second):
signal.signal(signal.SIGALRM, raise_timeout)
signal.alarm(second)
try:
yield
finally:
signal.signal(signal.SIGALRM, signal.SIG_IGN)
def raise_timeout(_signum, _frame):
raise TimeoutError
def timeout(second):
def _timeout(fun):
@wraps(fun)
def _fun(*args, **kwargs):
with timeout_signal(second):
return fun(*args, **kwargs)
return _fun
return _timeout
@timeout(1)
def f():
time.sleep(2)
f()
以上是 编程语言中的 timeout 原理是什么? 的全部内容, 来源链接: utcz.com/p/938528.html