Django线程和测试

jme*_*etz 4 database django multithreading unit-testing

我有一个多线程的django应用程序,它在单独的线程中创建一些对象,以便更快地返回.创建的对象仅用于跟踪用户已完成的操作,并且不以任何方式对时间敏感.

视图函数看起来像这样:

def foo(request):
    #... do important computation...
    bar(x, y, z)
    return HttpResponse()
Run Code Online (Sandbox Code Playgroud)

一切都运行正常,但当我改变它看起来像这样并使用线程:

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

第二个版本失败了.这都是使用TransactionTestCase和mySQL 完成的.

有任何想法吗?

Tom*_*cki 6

使用线程来卸载请求并不是一个好主意.有许多陷阱,并没有什么好处.主要问题(以及您的问题与这些问题有关)是:

  • Django中的每个线程都使用单独的数据库连接,因此:
    • 你放松了交易的好处
    • 你必须在线程中手动关闭连接
    • 如果你没有以正确的方式关闭线程中的连接(并且很难做到正确),你将有数百个与数据库的开放连接,这将给你带来问题
    • 你有测试的问题,因为测试框架在数据库连接上做了一些技巧,而且它不能在线程连接上做
  • 翻译框架在线程中不起作用
  • 如果wsgi服务器决定重新加载,你的线程可能会被过早杀死,但没有请求处理
  • Django错误处理不适用于线程

正确的方法是:

  • 优化代码以更快地提供请求或
  • 使用像Celery或RQ这样的任务系统将你的工作卸载到后台(这有一些上面的问题,但更直接).

PS.不要尝试为测试设置Celery或RQ.您应该只是模拟任务并单独测试它.