1.参考nonebot的run_sync的方法:

import asyncio
from functools import partial, wraps
import time
def run_sync(call):
    """一个用于包装 sync function 为 async function 的装饰器

    参数:
        call: 被装饰的同步函数
    """

    @wraps(call)
    async def _wrapper(*args, **kwargs):
        loop = asyncio.get_running_loop()
        pfunc = partial(call, *args, **kwargs)
        result = await loop.run_in_executor(None, pfunc)
        return result

    return _wrapper

s = time.time()
@run_sync
def p_secs(secs):
    print(f"{secs} start after begin {time.time()-s}s")
    time.sleep(secs)
    print(f"{secs} end after begin {time.time()-s}")
    return 0

# 创建一个协程并启动
task = [p_secs(10),p_secs(2),p_secs(6)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*task))
loop.close()

一般来说上面的输出如下

10 start after begin 0.004033803939819336s
2 start after begin 0.004033803939819336s
6 start after begin 0.004033803939819336s
2 end after begin 2.0071911811828613
6 end after begin 6.00560998916626
10 end after begin 10.018727540969849

使用修饰器快速打包sync函数到另外的一个线程执行,
避免io等待的操作阻塞主线程。

2.在py[3.9]版本使用to_thread创建线程

3.9 新版功能.->协程与任务-to_thread
由于 GIL 的存在,asyncio.to_thread() 通常只能被用来将 IO 密集型函数变为非阻塞的。 但是,对于会释放 GIL 的扩展模块或无此限制的替代性 Python 实现来说,asyncio.to_thread() 也可被用于 CPU 密集型函数。

import asyncio
import time
s = time.time()
def sleep_secs(secs=3):
    time.sleep(secs)
async def p_secs(secs):
    print(f"{secs} start after begin {time.time()-s}s")
    # await asyncio.gather(asyncio.to_thread(sleep_secs(secs)))
    await asyncio.gather(
        asyncio.to_thread(sleep_secs,secs),
        asyncio.sleep(0.1))
    print(f"{secs} end after begin {time.time()-s}")
# task = [p_secs(3),p_secs(2),p_secs(6)]
# asyncio.run(p_secs(3))
# 创建一个协程并启动
task = [p_secs(3),p_secs(2),p_secs(6),p_secs(9),p_secs(4),p_secs(1)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*task))
loop.close()

一般来说上面的输出如下

3 start after begin 0.009048700332641602s
2 start after begin 0.010601520538330078s
6 start after begin 0.010601520538330078s
9 start after begin 0.010601520538330078s
4 start after begin 0.010601520538330078s
1 start after begin 0.010601520538330078s
1 end after begin 1.0323760509490967
2 end after begin 2.0214357376098633
3 end after begin 3.0332844257354736
4 end after begin 4.022623777389526
6 end after begin 6.034776926040649
9 end after begin 9.032061576843262

更为简单,高效的方法

最后修改:2022 年 08 月 05 日 09 : 51 AM
如果觉得我的文章对你有用,请随意赞赏