Django线程和测试

9

我有一个多线程的django应用程序,它在不同的线程中创建一些对象以便更快地返回结果。这些创建的对象仅用于跟踪用户的操作,而且与时间无关。

视图函数原来是这样的:

def foo(request):
    #... do important computation...
    bar(x, y, z)
    return HttpResponse()

这里一切正常,但是当我将它改成下面这样并使用线程时:

def foo(request):
    #... do important computation...
    thread = Thread(target=bar, args=(x, y, z))
    thread.start()
    if testing_mode:
        thread.join()
    return HttpResponse()

第二个版本失败了。这一切都是使用TransactionTestCase和mySQL完成的。
有什么想法吗?

我已经更新了问题。更清楚了吗?基本思路是,如果bar()在测试数据库中创建一个对象,则该对象不会出现在第二个代码中,但会出现在第一个代码中。 - jmetz
你应该检查你的假设。如果按照Django数据库连接的工作方式,使用多线程创建多个项目并不比串行更快,那么我会非常惊讶。 - Daniel Roseman
1个回答

17

使用线程来卸载请求并不是一个好主意。有许多陷阱,但好处很少。主要问题(您的问题与此相关)包括:

  • Django中的每个线程都使用单独的数据库连接,因此:
    • 您将失去事务的好处
    • 您必须在线程中手动关闭连接
    • 如果您没有以正确的方式关闭线程中的连接(这很难做到正确),则会有数百个打开的数据库连接,这将给您带来问题
    • 由于测试框架对DB连接进行一些技巧,因此您将遇到测试问题,并且无法针对来自线程的连接执行测试
  • 翻译框架不适用于线程
  • 如果WSGI服务器决定重新加载但没有要处理的请求,则您的线程可能会被过早地终止
  • Django错误处理不适用于线程

正确的方法是:

  • 优化代码以更快地提供服务请求或
  • 使用任务系统,如Celery或RQ,将工作卸载到后台(这具有上述某些问题,但更为简单直接)。

附:不要尝试为测试设置Celery或RQ。您应该只模拟任务并单独测试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接