python异步(Async)编程

python异步(Async)编程

异步和同步的概念

同步:一个一个步骤的往下执行。只有在上一步完成后,程序才会进入下一个步骤。例子:批处理程序、命令行程序

异步:不用于同步的是,系统不会等待执行步骤完成后再继续执行下一个步骤。

异步的优势

同步网络服务器,在需要处理大量的访问请求的时候,服务器有多少个处理单元就只能处理多少个请求,且这些请求处理会涉及到网络速度、文件IO速度、数据库处理速度等不需要处理单元过多干涉的操作。结果会导致同步网络服务器陷入低效率的工作状态。而异步编程技术允许您的程序通过释放 CPU 来做其他工作来利用相对较慢的 IO 进程。

使用例子

同步程序

import queue

def task(name, work_queue):
    if work_queue.empty():
        print(f"Task {name} nothing to do")
    else:
        while not work_queue.empty():
            count = work_queue.get()
            total = 0
            print(f"Task {name} running")
            for x in range(count):
                total += 1
            print(f"Task {name} total: {total}")

def main():
    """
    This is the main entry point for the program
    """
    # Create the queue of work
    work_queue = queue.Queue()

    # Put some work in the queue
    for work in [15, 10, 5, 2]:
        work_queue.put(work)

    # Create some synchronous tasks
    tasks = [(task, "One", work_queue), (task, "Two", work_queue)]

    # Run the tasks
    for t, n, q in tasks:
        t(n, q)

if __name__ == "__main__":
    main()

非阻塞调用(异步友好)的协作并发程序

import asyncio
from codetiming import Timer

# async定义为异步函数
async def task(name, work_queue):
    timer = Timer(text=f"Task {name} elapsed time: {{:.1f}}")
    while not work_queue.empty():
        delay = await work_queue.get()
        print(f"Task {name} running")
        timer.start()
        await asyncio.sleep(delay)	# 创建一个非阻塞延迟,执行上下文切换回调用者main()
        timer.stop()

async def main():
    """
    This is the main entry point for the program
    """
    # Create the queue of work
    work_queue = asyncio.Queue()

    # Put some work in the queue
    for work in [15, 10, 5, 2]:
        await work_queue.put(work)	# 到达await关键字,发生上下文切换

    # Run the tasks
    with Timer(text="\nTotal elapsed time: {:.1f}"):
        await asyncio.gather(
            asyncio.create_task(task("One", work_queue)),
            asyncio.create_task(task("Two", work_queue)),
        )

if __name__ == "__main__":
    asyncio.run(main())

异步(非阻塞)HTTP调用

import asyncio
import aiohttp
from codetiming import Timer

async def task(name, work_queue):
    timer = Timer(text=f"Task {name} elapsed time: {{:.1f}}")
    async with aiohttp.ClientSession() as session:
        while not work_queue.empty():
            url = await work_queue.get()
            print(f"Task {name} getting URL: {url}")
            timer.start()
            async with session.get(url) as response:
                await response.text()
            timer.stop()

async def main():
    """
    This is the main entry point for the program
    """
    # Create the queue of work
    work_queue = asyncio.Queue()

    # Put some work in the queue
    for url in [
        "http://google.com",
        "http://yahoo.com",
        "http://linkedin.com",
        "http://apple.com",
        "http://microsoft.com",
        "http://facebook.com",
        "http://twitter.com",
    ]:
        await work_queue.put(url)

    # Run the tasks
    with Timer(text="\nTotal elapsed time: {:.1f}"):
        await asyncio.gather(
            asyncio.create_task(task("One", work_queue)),
            asyncio.create_task(task("Two", work_queue)),
        )

if __name__ == "__main__":
    asyncio.run(main())

拓展概念

可等待的对象氛围三种类型:协程、任务和Future.
当遇到可等待对象,进程会发生上下文切换(任务调度)

协程

async def main():
    print('runing...')
    await asyncio.sleep(2)

注意,直接调用协程并不会使其调度执行。

有三种方式运行一个协程:1. asyncio.run(main()) 2. await main() 3. asyncio.create_task(main())

任务

用来“并行的”调度协程。

当一个协程通过 asyncio.create_task() 等函数被封装为一个任务,该协程会被自动调度执行。

task = asyncio.create_task(main())
await task

Future

通常情况下 没有必要 在应用层级的代码中创建 Future 对象。这是一种特殊的 低层级 可等待对象。(有什么应用场景,我目前还不清楚)

API

创建任务

asyncio.create_task(main())

休眠:挂起当前任务,以允许其他任务运行。

await asyncio.sleep(1)

“并发”运行任务

await asyncio.gather(
    asyncio.create_task(task("One", work_queue)),
    asyncio.create_task(task("Two", work_queue)),
)

总结

异步编程经常用在存在很多IO操作的场景。我们要记住用asyncio来并发运行任务,仍然是单进程程序,与同步单进程不同的是,有任务调度的概念,且可等待对象协程被作为一个任务调度。

参考

[1] Getting Started With Async Features in Python. LINK

[2] 协程与任务高层级API介绍

posted @ 2021-06-04 18:58  小肚腩的世界  阅读(13205)  评论(0编辑  收藏  举报