Multithreading for Python Django
一些函数应该在Web服务器上异步运行。发送电子邮件或数据后处理是典型的用例。
编写decorator函数异步运行函数的最佳(或大多数pythonic)方法是什么?
我的设置很常见:python、django、gunicorn或waitress、AWS EC2标准Linux
例如,下面是一个开始:
1 2 3 4 5 6 7 8 | from threading import Thread def postpone(function): def decorator(*args, **kwargs): t = Thread(target = function, args=args, kwargs=kwargs) t.daemon = True t.start() return decorator |
预期用途:
1 2 3 | @postpone def foo(): pass #do stuff |
号
我继续在大规模生产中使用这个实现,没有任何问题。
装饰器定义:
1 2 3 4 5 6 | def start_new_thread(function): def decorator(*args, **kwargs): t = Thread(target = function, args=args, kwargs=kwargs) t.daemon = True t.start() return decorator |
示例用法:
1 2 3 | @start_new_thread def foo(): #do stuff |
号
随着时间的推移,堆栈已经更新和转换,没有失败。
原来是python 2.4.7,django 1.4,gunicorn 0.17.2,现在是python 3.6,django 2.1,waitress 1.1。
如果使用任何数据库事务,Django将创建一个新的连接,需要手动关闭:
1 2 3 4 5 6 | from django.db import connection @postpone def foo(): #do stuff connection.close() |
芹菜是一个异步任务队列/作业队列。它有很好的文档记录,非常适合您的需要。我建议你从这里开始
在Django进行异步处理最常见的方法是使用芹菜和
如果没有太多的新工作,Tomadvisil的方法很有效。如果许多持久的作业在短时间内运行,从而产生大量线程,那么主进程将受到影响。在这种情况下,可以使用带有协程的线程池,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # in my_utils.py from concurrent.futures import ThreadPoolExecutor MAX_THREADS = 10 def run_thread_pool(): """ Note that this is not a normal function, but a coroutine. All jobs are enqueued first before executed and there can be no more than 10 threads that run at any time point. """ with ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: while True: func, args, kwargs = yield executor.submit(func, *args, **kwargs) pool_wrapper = run_thread_pool() # Advance the coroutine to the first yield (priming) next(pool_wrapper) |
。
1 2 3 4 5 6 7 8 9 | from my_utils import pool_wrapper def job(*args, **kwargs): # do something def handle(request): # make args and kwargs pool_wrapper.send((job, args, kwargs)) # return a response |