56

我想完成的序列:

  1. 用户单击网页上的按钮
  2. model.py 中的一些函数开始运行。例如,通过爬网收集一些数据
  3. 函数完成后,将结果返回给用户。

我应该在 model.py 中打开一个新线程来执行我的函数吗?如果是这样,我该怎么做?

4

3 回答 3

55

如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 及更高版本进行了修复。

于 2018-11-15T20:09:54.210 回答
28
  1. 是的,它可以是多线程的,但通常使用 Celery 来做同样的事情。您可以在 celery-django 教程中了解如何操作。
  2. 很少有人真的想强迫用户等待网站。虽然这比冒超时风险要好。

这是您所描述的示例。

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 
于 2013-07-11T19:25:55.467 回答
-5

如果您不想在项目中添加一些矫枉过正的框架,您可以简单地使用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问的。

于 2018-02-19T10:39:53.937 回答