如何使Python中的异步线程并行运行?

问题描述 投票:0回答:2

我试图通读asyncio示例,但未能找到最简单的示例(在我看来)。假设我有一个“正常”功能,需要1秒钟。我用time.sleep(1)调用来模拟。如何以三个调用可以异步运行的方式包装该函数,以使总执行时间为1秒?

我可以通过使用线程来实现,但不能使用异步。

这里是一个例子:

import asyncio
import time
from threading import Thread

from datetime import datetime
from math import sqrt

def heavy_cpu(n):
    print(f"{n} --> start: {datetime.now()}")
    time.sleep(1)
    # for i in range(5099999):
    #     _ = sqrt(i) * sqrt(i)
    print(f"{n} --> finish: {datetime.now()}")

async def count(n):
    await asyncio.sleep(0.0000001)
    heavy_cpu(n)

async def main_async():
    await asyncio.gather(count(1), count(2), count(3))

def test_async():
    s = time.perf_counter()
    asyncio.run(main_async())
    elapsed = time.perf_counter() - s
    print(f"asyncio executed in {elapsed:0.2f} seconds.")

# ========== asyncio vs threading =============

def main_thread():
    threads = [Thread(target=heavy_cpu, args=(n,)) for n in range(1, 4)]
    for t in threads:
        t.start()
    for t in threads:
        t.join()

def test_thread():
    s = time.perf_counter()
    main_thread()
    elapsed = time.perf_counter() - s
    print(f"thread executed in {elapsed:0.2f} seconds.")

if __name__ == "__main__":
    test_async()
    test_thread()

输出:

1 --> start: 2020-05-12 18:28:53.513381
1 --> finish: 2020-05-12 18:28:54.517861
2 --> start: 2020-05-12 18:28:54.518162
2 --> finish: 2020-05-12 18:28:55.521757
3 --> start: 2020-05-12 18:28:55.521930
3 --> finish: 2020-05-12 18:28:56.522813
asyncio executed in 3.01 seconds.

1 --> start: 2020-05-12 18:28:56.523789
2 --> start: 2020-05-12 18:28:56.523943
3 --> start: 2020-05-12 18:28:56.524087
1 --> finish: 2020-05-12 18:28:57.5265992 --> finish: 2020-05-12 18:28:57.526689
3 --> finish: 2020-05-12 18:28:57.526849

thread executed in 1.00 seconds.

问题:为什么每个异步finish步骤[1,2,3]都需要1秒钟?如何使它真正异步?

python python-asyncio
2个回答
2
投票
如果实际上是故意使用time.sleep的方式(您清楚地知道asyncio.sleep存在),那么异步就是这样工作的;任何不自愿(直接或间接通过await将控制权返回给事件循环的任务)都将在其他任务[

1
投票
除了执行速度外,可能还有其他原因使用线程或异步。例如,在GUI程序中,通常只有一个线程可以更新GUI。如果您在此线程中执行较长的计算,则应用程序将冻结,直到计算完成。因此,通常最好在辅助线程中进行计算,或者如果您的GUI平台支持,则在另一个异步任务中进行计算。
© www.soinside.com 2019 - 2024. All rights reserved.