【问题标题】:What is the simple way to run a non-blocking coroutine?运行非阻塞协程的简单方法是什么?
【发布时间】:2022-03-15 18:30:14
【问题描述】:

在 Go 语言中,以非阻塞方式运行另一个任务非常简单。

import "net/http"

func Call(request http.Request) http.Response {
    response := getResponse(request)
    go doTask(request)  // Non-blocking. No need to wait for result.
    return response
}

func getResponse(request http.Request) http.Response {
    // Do something synchronously here
    return http.Response{}
}

func doTask(r http.Request) {
    // Some task which takes time to finish
}

如何在 python 中实现这一点?

我试过这样:

import asyncio
import threading
from asyncio.events import AbstractEventLoop

loop: AbstractEventLoop

def initialize():
    global loop
    loop = asyncio.new_event_loop()
    thread = threading.Thread(target=run_event_loop)
    thread.start()

def run_event_loop():
    loop.run_forever()

def call(request):
    response = get_response(request)

    # This should not block
    asyncio.run_coroutine_threadsafe(do_task(request), loop)

    return response

def get_response(r):
    # Do something synchronously here
    return 42

async def do_task(r):
    # Some task which takes time to finish
    return

这行得通,但有点麻烦。

此外,python 代码仅使用 一个 线程来执行任务,而 Go 自动将任务分派给多个进程(Kotlin 也是如此)。

有没有更好的办法?

【问题讨论】:

  • 如果你需要运行一个非阻塞协程,你可以简单地使用asyncio.create_task(coroutine())。这假设您在事件循环线程中运行,这就是使用 asyncio 的程序的结构。
  • 线程不一定是事件循环线程,所以我不能简单地使用create_task。我猜loop.run_in_executor 是迄今为止我能选择的最佳选择。
  • 你甚至需要 asyncio 和一般的 async 吗?如果您只想调用同步函数而不等待它们完成,concurrent.futures 是实现目标的更简单的方法。

标签: python python-asyncio coroutine


【解决方案1】:

我们可以使用concurrent.futures 模块运行非阻塞任务。 ThreadPoolExecutor 对象用于此目的。您可以通过进行以下调整来修改您的代码以使用此方法:

from concurrent.futures import ThreadPoolExecutor


def call(request):
    response = get_response(request)

    with ThreadPoolExecutor(max_workers=4) as e:
        e.submit(do_task)

    return response

def get_response(r):
    # Do something synchronously here
    return 42

async def do_task(r):
    # Some task which takes time to finish
    return

response 将立即返回,do_task 将在返回结果后运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 2022-07-25
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多