web-dev-qa-db-ja.com

Python Django

一部の機能は、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
38
tomcounsell

私は、この実装を大規模かつ実稼働で問題なく使用し続けました。

デコレータの定義:

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()
59
tomcounsell

Celery は非同期タスクキュー/ジョブキューです。十分に文書化されており、必要なものに最適です。始めることをお勧めします こちら

15
Glyn Jackson

Django=で非同期処理を行う最も一般的な方法は、 Celery および Django-celery

3
Thomas Orozco

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
0
bombs