Django 启动时如何启动一个新线程

2019-04-18 11:15:41 +08:00
 kaiccc

需求:Django 在启动时初始化一个子线程,用于在后台轮训心跳任务

心跳任务,监控其他节点

目前测试情况:

1.定时器( apscheduler )的方案,并不是我想要的。比如 任务可能随着节点增多,本来 5 秒能处理完的 job,变成 10 秒。apscheduler 做不到顺延执行同 job (我是没找到办法)

2.尝试过 在 view 中创建线程,加载的代码没问题,但是创建线程无效果没 log。猜测 manage.py runserver 的时候是 fork 了子进程。

  1. manage.py 中创建线程,会阻塞主进程。

那位大佬 来指点一下。小弟感谢不尽(抱拳)

7083 次点击
所在节点    Python
18 条回复
wnh3yang
2019-04-18 11:50:03 +08:00
用芹菜队列应该可以
keepeye
2019-04-18 11:55:32 +08:00
创建线程怎么会阻塞主线程呢?能贴下代码么?

我用 tornado 也可以创建线程啊

```
# 创建队列处理线程
threading.Thread(target=handle_queue, name="handle_queue").start()
# 启动 tornado
port = os.environ.get('PORT', 8888)
api.listen(port)
print('listen on {}'.format(port))
tornado.ioloop.IOLoop.current().start()
```
phithon
2019-04-18 11:56:29 +08:00
创建线程的操作在哪都不会阻塞主线程吧,是不是你 join 了。。
wizardoz
2019-04-18 12:00:44 +08:00
好多业务通过 celery 就能做到,但是你问的是如何开线程,把创建线程的代码放在 app 的 __init__.py 中即可,并保证 app 会被 import
neoblackcap
2019-04-18 12:01:22 +08:00
开两个服务,Python 里面就不要用什么线程,当线程死了就好了。
还有就是正常一点都不会搞什么 view 中启动线程做心跳检测,你的检查周期跟请求的生命周期绑定?这个设计我只能投反对票。
还有就是生产环境不会用 manage.py runserver,那个只是给你开发用的。
如果你生产环境用 uwsgi,那么它已经自带心跳检查了,不知道你的心跳想怎么做,一般 http 的它还是能做的,你可以看看 uwsgi 的文档
wizardoz
2019-04-18 12:03:15 +08:00
manage.py 中创建线程不科学,manage.py 这个文件只是调试的时候用的,真正部署以后这个文件不会执行。
myyou
2019-04-18 12:07:22 +08:00
"apscheduler 做不到顺延执行同 job"是什么意思?” misfire_grace_time “参数是你要的吗?
JamesMackerel
2019-04-18 12:48:24 +08:00
Django crontab
guyujiezi
2019-04-18 12:53:39 +08:00
首先,你这个解决方案并不恰当,用 supervisor 启动独立守护进程更加合适,不过你的方案要实现也并非不可能。

django 程序一般会被托管给 WSGI 容器来运行,你在 django 程序中无法预料会是以多进程或是多线程运行,你需要一个全局互斥对象( Mutex )来保证这个线程只被运行一次,可以通过文件锁来实现
kaiccc
2019-04-18 13:54:45 +08:00
可能说的比较乱。
我只是想 创建 django 启动时加载一个子线程
kaiccc
2019-04-18 13:57:33 +08:00
@wizardoz 试过加载 init 中,通过 manage.py 启动项目 会阻塞 启动。(子线程创建没问题,但是子线程里是死循环,来处理业务)
est
2019-04-18 14:02:58 +08:00
wsgi 架构里 线程是 anti pattern。建议放弃治疗。
Qzier
2019-04-18 14:19:13 +08:00
首先你要使用 BackgroundScheduler,然后在你 app 下的 apps.py 中的 AppConfig 子类添加 ready 方法,该方法每次应用载入前被启动一次,然后在 INSTALLED_APPS 注册该类名,而不是 app 名。
kaiccc
2019-04-18 14:53:59 +08:00
@Qzier 我只是想 创建 django 启动时加载一个子线程 ,不需要 apscheduler
kaiccc
2019-04-18 14:55:11 +08:00
@myyou 触发器每 5 秒执行,但是任务 实际耗时 10 秒。顺延执行,上个耗时 10 秒任务完成后的 5 秒 触发
Aprilming
2019-04-18 15:27:40 +08:00
django.channles,可以试试,有延时其中任务这个功能,你可以创建一个 5 秒的延时任务,但时间之后,执行任务 ,执行完毕,在去掉创建延时任务的接口。
hakono
2019-04-20 20:53:09 +08:00
如果只是单纯想要启动时创建个进程的话,直接在对应的 app 的 apps.py 里创建不就好了

apps.py 的对应 AppConfig 类里的 ready()方法会自动被调用,在 ready()方法里创建进程就行了

不过有点要注意的是,python manage.py runserver 会启动两个 django 进程,另一个进程是用来监视代码变更动态重启服务的,这个进程也会调用 ready()方法。这里需要自己处理选择检测下,别多次创建进程
gollum9526
2019-06-12 16:51:36 +08:00
django 创建子线程确实会阻塞的,应该是 python 全局锁

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/556321

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX