一部の機能は、Webサーバーで非同期に実行する必要があります。電子メールの送信またはデータの後処理は、一般的な使用例です。
関数を非同期で実行するデコレータ関数を記述する最良の(またはほとんどのPythonic)方法は何ですか?
私のセットアップは一般的なものです:Python、Django、GunicornまたはWaitress、AWS EC2標準Linux
たとえば、ここから始まります。
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
望ましい使用法:
@postpone
def foo():
pass #do stuff
私は、この実装を大規模かつ実稼働で問題なく使用し続けました。
デコレータの定義:
def start_new_thread(function):
def decorator(*args, **kwargs):
t = Thread(target = function, args=args, kwargs=kwargs)
t.daemon = True
t.start()
return decorator
使用例:
@start_new_thread
def foo():
#do stuff
時間が経つにつれて、スタックは確実に更新および移行されました。
元々Python 2.4.7、Django 1.4、Gunicorn 0.17.2、now Python 3.6、Django 2.1、ウェイトレス1.1。
データベーストランザクションを使用している場合、Djangoは新しい接続を作成します。これは手動で閉じる必要があります。
from Django.db import connection
@postpone
def foo():
#do stuff
connection.close()
Django=で非同期処理を行う最も一般的な方法は、 Celery および Django-celery
。
tomcounsellのアプローチは、求人があまり多くなければうまく機能します。多くの長期ジョブが短時間で実行され、したがって多数のスレッドが生成されると、メインプロセスが悪影響を受けます。この場合、コルーチンでスレッドプールを使用できます。
# 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)
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