1. asyncio
asyncio是Python3.4中引入的异步编程库,提供了高效的异步I/O框架,可用于编写高性能的并发编程。其主要特点如下:
1.1 协程
asyncio基于协程(coroutine)编写,协程是一种用户态的轻量级线程,与操作系统的线程不同,协程之间的切换不需要切换到操作系统内核态,因此开销非常小。
下面的示例展示了使用asyncio编写的协程:
import asyncio
async def hello_world():
print("Hello World!")
loop = asyncio.get_event_loop()
loop.run_until_complete(hello_world())
在上面的代码中,定义了一个async函数hello_world,然后使用asyncio的get_event_loop方法获取一个事件循环loop,使用loop的run_until_complete方法执行hello_world协程。
1.2 异步I/O
asyncio提供了基于事件驱动的异步I/O框架,支持TCP、UDP、SSL/TLS、子进程等协议和功能。
下面的示例展示了如何使用asyncio实现一个简单的TCP服务器:
import asyncio
async def handle_echo(reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print(f"Received {message} from {addr!r}")
print(f"Send: {message!r}")
writer.write(data)
await writer.drain()
print("Close the connection")
writer.close()
async def main():
server = await asyncio.start_server(handle_echo, '127.0.0.1', 8888)
addr = server.sockets[0].getsockname()
print(f"Serving on {addr}")
async with server:
await server.serve_forever()
asyncio.run(main())
在上面的代码中,定义了一个handle_echo协程,该协程处理接收到的客户端请求。main协程创建一个TCP服务器,监听本地地址127.0.0.1和端口8888。当有一个客户端连接时,handle_echo协程会被调用来处理该客户端的请求。
2. trio
trio是一个基于async/await的异步I/O库,专注于简化异步编程的复杂性,使得编写正确的并发代码更容易、更自然、更高效。
2.1 Nurseries
trio使用Nursery来管理协程,它类似于Python的with语句,可以同时管理多个协程,保证所有协程正常运行和关闭:
import trio
async def child1():
print('child1 started')
await trio.sleep(1)
print('child1 ended')
async def child2():
print('child2 started')
await trio.sleep(2)
print('child2 ended')
async def parent():
async with trio.open_nursery() as nursery:
nursery.start_soon(child1)
nursery.start_soon(child2)
trio.run(parent)
上面的代码中,child1和child2为子协程,parent为父协程,通过使用open_nursery方法创建一个nursery,然后使用start_soon方法向该nursery中添加子协程,最后使用trio.run方法来运行父协程。
2.2 Cancel Scopes
trio中的协程可以被取消,当一个协程被取消时,其所有的嵌套协程也会被取消。trio中的取消机制是通过cancel_scope实现的。
import trio
async def child1():
try:
while True:
print('child1')
await trio.sleep(1)
except trio.Cancelled:
print('child1 cancelled')
async def child2():
try:
while True:
print('child2')
await trio.sleep(1)
except trio.Cancelled:
print('child2 cancelled')
async def parent():
async with trio.open_nursery() as nursery:
nursery.start_soon(child1)
nursery.start_soon(child2)
await trio.sleep(3)
nursery.cancel_scope.cancel()
trio.run(parent)
上面的代码中,当父协程(parent)运行了3秒时,就会取消所有嵌套在该协程中的子协程(child1和child2)。
3. curio
curio是一个异步I/O库,它使用async/await语法,提供了面向对象的并发模型,可以简化异步编程的复杂性。
3.1 Task
curio中的Task类封装了一个可以运行的协程,可以使用它来启动、取消以及等待协程的执行。
import curio
async def my_coro():
await curio.sleep(1)
return 'result'
async def main():
task = await curio.spawn(my_coro)
result = await task.join()
print(result)
curio.run(main)
上面的代码中,定义了一个my_coro协程,它会在1秒后返回'result'。main协程创建一个Task对象来启动my_coro协程,并使用Task对象的join方法来等待协程执行完毕并获取其返回值。
3.2 Queue
curio中的Queue类是线程安全的,可以用来在协程之间安全地传递数据,在代码中使用Queue时需要小心,以避免死锁。
import curio
async def sender(queue):
for i in range(5):
await queue.put(i)
async def receiver(queue):
while True:
value = await queue.get()
print(value)
async def main():
queue = curio.Queue()
tasks = [
await curio.spawn(sender, queue),
await curio.spawn(receiver, queue)
]
await curio.gather(*tasks)
curio.run(main)
上面的代码中,sender协程向队列中放入5个数值,receiver协程从队列中获取数值并输出。在main协程中,创建了一个Queue对象,并使用gather方法同时启动了sender和receiver协程。
4. uvloop
uvloop是一个高性能Python异步I/O库,它使用Cython构建,基于libuv库实现,提供了比标准的asyncio库更高的性能。
4.1 Loop
uvloop使用uvloop.Loop来创建事件循环,它与asyncio的Loop对象具有完全相同的API,并提供了更高的性能和更低的延迟。
import asyncio
import uvloop
async def hello_world():
print("Hello World!")
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
loop = asyncio.get_event_loop()
loop.run_until_complete(hello_world())
上面的代码中,使用uvloop库创建了uvloop的事件循环,并使用asyncio的set_event_loop_policy方法将uvloop设置为默认的事件循环实现,然后使用get_event_loop方法获取事件循环并运行hello_world协程。
4.2 TCP
uvloop提供了TCPServer和TCPClient类,可用于创建高性能的TCP服务器和客户端。
import uvloop
import asyncio
async def handle_echo(reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print(f"Received {message} from {addr!r}")
print(f"Send: {message!r}")
writer.write(data)
await writer.drain()
print("Close the connection")
writer.close()
async def main():
server = await asyncio.start_server(handle_echo, '127.0.0.1', 8888)
async with server:
await server.serve_forever()
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
asyncio.run(main())
上面的代码是一个使用uvloop实现的TCP服务器示例,与asyncio的实现很相似,在main协程中使用asyncio的start_server方法创建一个TCP服务器,并使用server_forever方法开始监听来自客户端的请求。
5. trio_asyncio
trio-asyncio是一个异步I/O库,它提供了一个trio.EventLoopPolicy类,可以将asyncio的事件循环嵌入到trio应用程序中。
5.1 TrioPolicy
trio_asyncio提供了一个TrioPolicy类,实现了一个asyncio的事件循环 policy,可以将其设置为默认的policy,允许在trio中使用asyncio异步I/O。
import asyncio
import trio
import trio_asyncio
async def hello_world():
print("Hello World!")
async def main():
policy = trio_asyncio.TrioPolicy()
asyncio.set_event_loop_policy(policy)
loop = asyncio.get_event_loop()
loop.set_default_executor(trio_asyncio.AsyncioExecutor())
await trio.to_thread.run_asyncio(loop.run_until_complete, hello_world())
trio.run(main)
上面的代码中,使用trio_asyncio的TrioPolicy将异步I/O库asyncio的事件循环嵌入到trio应用程序中,使用TrioPolicy创建一个事件循环,然后使用run_asyncio方法在trio的执行上下文中执行事件循环。
5.2 TrioSemaphore
trio_asyncio还提供了一个TrioSemaphore类,它是trio和asyncio之间的信号量,可以在trio和asyncio之间同步并发的访问。
import asyncio
import trio
import trio_asyncio
async def async_fn():
async with trio_asyncio.open_trio_semaphore(1) as sem:
await sem.acquire()
await asyncio.sleep(1)
sem.release()
async def main():
async with trio.open_nursery() as nursery:
for i in range(3):
nursery.start_soon(async_fn)
trio.run(main)
上面的代码中,首先在async_fn协程中创建了一个TrioSemaphore信号量,然后使用open_trio_semaphore方法创建了一个与asyncio关联的信号量,并使用nursery开启了几个dev协程,这些协程是运行在trio中,但能够与异步I/O库asyncio进行同步并发访问。
总结
Python中有很多高性能的异步I/O库,其中包括asyncio、trio、curio、uvloop以及trio_asyncio。这些库都以不同的方式提供了异步编程的支持,可以根据实际需求选择适合的库来开发高性能并发应用程序。