Python: Django: 信号处理器与主线程

11 投票
4 回答
12718 浏览
提问于 2025-04-17 08:41

我正在开发一个Django应用,这个应用依赖于一个Python模块,而这个模块里实现了一个SIGINT信号处理器。

假设我不能修改我依赖的这个模块,我该如何解决在Django中集成时出现的“信号只能在主线程中工作”的错误呢?

我可以在Django的主线程中运行它吗?有没有办法禁用这个处理器,让模块可以在非主线程中运行呢?

谢谢!

4 个回答

2

有一种更简单的方法,这样做不会影响你使用线程和进程的能力。

把你的注册调用放在 manage.py 文件里:

def handleKill(signum, frame):
    print "Killing Thread."
    # Or whatever code you want here
    ForceTerminate.FORCE_TERMINATE = True 
    print threading.active_count()
    exit(0)


if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

from django.core.management import execute_from_command_line

signal.signal(signal.SIGINT, handleKill)
signal.signal(signal.SIGTERM, handleKill)

execute_from_command_line(sys.argv)
3

我在项目中使用的是Python 3.5和Django 1.8.5,最近遇到了一个类似的问题。我可以直接用SIGNAL轻松运行我的xxx.py代码,但在Django中作为一个包运行时却出现了“signal only works in main thread”的错误,导致无法执行。

首先,使用--noreload --nothreading启动服务器是可行的,但这样运行我的多线程代码速度太慢了。

其次,我发现我包中的__init__.py代码是在主线程中运行的。当然,只有主线程才能捕获这个signal,所以我包里的代码根本无法捕获到。虽然这对我来说不能解决问题,但可能对你有帮助。

最后,我发现Python里有一个内置模块叫subprocess。这个模块的意思是你可以用它来运行一个完整的子进程,也就是说,这个进程有自己的主线程,所以你可以在这里轻松运行带有SIGNAL的代码。虽然我不太清楚使用它的性能如何,但对我来说效果很好。顺便说一下,你可以在Python文档中找到关于subprocess的所有详细信息。

谢谢~

6

Django自带的开发服务器默认开启了自动重载功能,这个功能会启动一个新的线程来重新加载代码。如果你想绕过这个功能,可以简单地做以下操作,不过这样的话你就失去了自动重载的便利:

python manage.py runserver --noreload

在选择你的生产环境设置时,你也需要注意这一点。至少有一些部署选项(比如线程型的fastcgi)会确保你的代码在主线程之外执行。

撰写回答