当我在主循环中处理请求时,如何从django视图运行异步函数以在后台运行?

ajsxfq5m  于 2023-03-13  发布在  Go
关注(0)|答案(3)|浏览(130)

正如我在标题中所说的,我希望有一个任务在后台运行,处理一个大型数据库查询,同时处理来自前端的请求。我甚至可以用async/asyncio做到这一点吗?我被告知这是可能的...
出于上下文的目的,我想做一些类似下面的事情,还要注意,我并不真的需要函数告诉我什么时候完成(尽管我确实想知道这是否可能),因为我只是检查.json文件是否最终被写入。

def post_data_view(request):
    if request.method == 'POST':
        ...
        do_long_query_in_the_background(some_data)
        return HttpResponse('Received. Ask me in a while if I finished.')

def is_it_done_view(request):
    if request.method == 'GET':
        data = find_json()
        if data:
            return JsonResponse(data)
        else:
            return HttpResponse('Not yet dude...')

async def do_long_query_in_the_background(data):
    # do some long processing...
    # dump the result to a result.json
    return

有人告诉我这是可以用异步的,但我真的觉得很难理解。对于上下文,我试图简化很多,即使这样,我发现我不太明白发生了什么:

async def f():
    while True:
        print(0)
        await asyncio.sleep(2)

asyncio.create_task(f())

即使我尝试的这段代码也失败了sys:1: RuntimeWarning: coroutine 'f' was never awaited,但它确实可以在控制台上工作,我不明白为什么会这样。
我还想知道,如果这是在所有可能和安全的线程做也许?
我对此感到非常沮丧,因为在其他线程中建议的一般解决方案似乎只是使用celery ,但对于一个并不那么复杂的问题来说,它确实感觉像是矫枉过正。

utugiqy6

utugiqy61#

async def f():
    while True:
        print(0)
        await asyncio.sleep(2)

asyncio.run(f())

asyncio的run方法设置事件循环并创建Task对象,调度它运行并等待它完成,然后再执行任何其他代码。
虽然看起来很简单,异步编程需要一个非常不同的编程方法,因为事情可以以任何顺序发生,你必须非常仔细地考虑什么顺序是重要的函数完成。
对于您的用例,您可以使用threading。您可以创建一个新线程,并让它在后台运行。在线程之间切换会降低性能,但如果大部分处理在服务器端完成,您的用户可能会有更好的体验。

#this runs forever as your loop never terminates
from threading import Thread
from time import sleep

def f():
    while True:
        print(0)
        await asyncio.sleep(2)

def main():
     print('starting new thread...')
     t = Thread(target=f)
     t.start()
     print('continuing other tasks...')
     sleep(5)
     print('still more things to do...')
mftmpeh8

mftmpeh82#

1.您需要使用aync定义视图函数。在您的情况下,它应该是:async def post_data_view(request):
1.在异步视图函数中:首先需要get循环,然后在循环中创建一个任务,应该是:

async def post_data_view(request):
        if request.method == 'POST':
        ....
        loop = asyncio.get_event_loop()
        loop.create_task(do_long_query_in_the_background(some_data))
        return HttpResponse('Received. Ask me in a while if I finished.')
4ktjp1zp

4ktjp1zp3#

我有一个完美的解决方案给你。正是你想要的。这个解决方案适用于达芙妮,因为它创建了一个全局循环,你可以在其中创建新任务,而不需要启动一个新循环。

from daphne.server import twisted_loop

# heres a view that you want to start a background function in
def hello_background(request):
    twisted_loop.create_task(long_task())

这将通过向全局循环添加一个事件来在后台运行任务。

相关问题