我想完成的序列:
- 用户单击网页上的按钮
- model.py 中的一些函数开始运行。例如,通过爬网收集一些数据
- 函数完成后,将结果返回给用户。
我应该在 model.py 中打开一个新线程来执行我的函数吗?如果是这样,我该怎么做?
我想完成的序列:
我应该在 model.py 中打开一个新线程来执行我的函数吗?如果是这样,我该怎么做?
如this answer所示,您可以使用 threading 包来执行异步任务。似乎每个人都推荐 Celery,但对于执行简单但长时间运行的任务来说,它通常是矫枉过正的。我认为使用线程实际上更容易和更透明。
这是一个异步爬虫的简单示例:
#views.py
import threading
from .models import Crawl
def startCrawl(request):
task = Crawl()
task.save()
t = threading.Thread(target=doCrawl,args=[task.id])
t.setDaemon(True)
t.start()
return JsonResponse({'id':task.id})
def checkCrawl(request,id):
task = Crawl.objects.get(pk=id)
return JsonResponse({'is_done':task.is_done, result:task.result})
def doCrawl(id):
task = Crawl.objects.get(pk=id)
# Do crawling, etc.
task.result = result
task.is_done = True
task.save()
您的前端可以请求startCrawl
开始爬网,它可以发出 Ajax 请求来检查它,checkCrawl
当它完成时将返回 true 和结果。
Python3的更新:
该库的文档threading
建议将daemon
属性作为关键字参数传递,而不是使用 setter:
t = threading.Thread(target=doCrawl,args=[task.id],daemon=True)
t.start()
Python <3.7 的更新:
正如这里所讨论的,这个错误可能会导致缓慢的内存泄漏,从而导致长时间运行的服务器溢出。该错误已针对 Python 3.7 及更高版本进行了修复。
这是您所描述的示例。
User sends request
Django receives => spawns a thread to do something else.
main thread finishes && other thread finishes
... (later upon completion of both tasks)
response is sent to user as a package.
更好的方法:
User sends request
Django receives => lets Celery know "hey! do this!"
main thread finishes
response is sent to user
...(later)
user receives balance of transaction
如果您不想在项目中添加一些矫枉过正的框架,您可以简单地使用subprocess.Popen:
def my_command(request):
command = '/my/command/to/run' # Can even be 'python manage.py somecommand'
subprocess.Popen(command, shell=True)
command = '/other/command/to/run'
subprocess.Popen(command, shell=True)
return HttpResponse(status=204)
[编辑] 如评论中所述,这不会启动后台任务并立即返回 HttpResponse。它将并行执行这两个命令,然后在两者都完成后返回 HttpResponse。这是OP问的。