【问题标题】:Why does time.sleep() stop immediately when using signal handler?为什么使用信号处理程序时 time.sleep() 会立即停止?
【发布时间】:2018-02-06 08:17:01
【问题描述】:

在制作 WSGI 服务器时,我注意到在循环中对 time.sleep() 的一些测试调用仅在第一次迭代中起作用。这是复制品:

import os
import signal 
import time


def run_loop():
    i = 0
    while True:
        print('PID: {}, i = {}'.format(os.getpid(), i))
        time.sleep(5) # Only works the first time
        i += 1

        pid = os.fork() . # May or may not be related?
        if pid == 0:
            print('PID: {}, CHILD'.format(os.getpid(), i))
            os._exit(0)


if __name__ == '__main__':
    # If I uncomment this line it works fine.
    # If I leave it as is, the time.sleep in run_loop() only waits once. 
    signal.signal(signal.SIGCHLD, lambda a, b: os.wait())

    run_loop()

我知道 time.sleep() 文档中的以下部分。

实际的挂起时间可能少于请求的时间,因为任何捕获的信号都会在执行该信号的捕获例程后终止 sleep()。

这是因为SIGCHLD 信号在time.sleep() 运行时不断触发吗?什么会导致信号一致地取消对 time.sleep() 的每次调用?

【问题讨论】:

    标签: python asynchronous signals fork


    【解决方案1】:

    来自 linux sleep 文档

    sleep() 导致调用线程休眠,直到 以秒为单位指定的实时秒数已经过去或直到一个信号 没有被忽略的到达。

    有一个 linux c 函数可以让你在被一个叫做“nanosleep”的信号打断后继续睡眠。它要么休眠给定数量的纳秒,要么休眠直到信号到达并返回剩余休眠的纳秒数,但 python 不会在任何模块中公开它

    您可以自己模拟 nanosleep 的相同行为,例如:

    import datetime
    import time
    def busy_sleep(seconds):
        start_time = datetime.datetime.now()
        seconds_slept = 0
        while seconds_slept < seconds:
            time.sleep(seconds - seconds_slept)
            seconds_slept = (datetime.datetime.now() - start_time).total_seconds()
    

    【讨论】:

    • 我知道发生了什么。但是,这是否意味着信号在同一时间到达 sleep() 每次都在等待?这会仅靠“运气”发生吗,还是我可以期望sleep() 在这种情况下会一直被打断?
    • 由于子进程基本上没有要运行的代码,它总是会在 5 秒过去之前终止,但根据您的操作系统和 cpu,信号可能会在 之前到达 你开始睡觉,但我不会指望那个
    猜你喜欢
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 2022-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多