异步编程之协程(asyncio模块)
协程:协程是在用户空间,基于生成器(yield),在单线程内(而非多线程的操作系统调度),实现的一种非抢占式调度;当一个协程主动让出控制权,另一个协程才会被调度。。python3.4引入。
协程在单线程内完成,没有多线程切换带来的开销 单线程内调度,不需要锁机制 多CPU下,多进程+协程,实现进程并发,同时发挥协程在单进程的优势。
1 asyncio模块
通过asyncio模块实现协程,asyncio模块其实是一个框架,包括异步IO,事件循环、协程、任务等内容。
1、问题引入: 以下示例,在单线程内,通过生成器(yield语句)完成任务调度,让两个函数交替执行,看似并行。这种调度是在用户空间由用户设计的,而不是通过多线程或多进程由操作系统调度。协程就是基于yield实现的。
def foo1():
for i in range(3):
print("foo1:{}".format(i))
yield
def foo2():
for i in range(3):
print("foo1:{}".format(i))
yield
a = foo1()
b = foo2()
for i in range(3):
next(a)
next(b)
2、事件循环: 事件循环是asyncio提供的核心运行机制 理解示例:
import asyncio
from tool.show_thread import show_thread
@asyncio.coroutine
def sleep(x):
for i in range(3):
print("sleep {}".format(i))
yield from asyncio.sleep(x)
async def new_sleep(x):
for i in range(3):
print("new sleep:{}".format(i))
await asyncio.sleep(x)
if __name__ == '__main__':
show_thread()
loop = asyncio.get_event_loop()
print("is coroutine function:{}.".format(asyncio.iscoroutinefunction(new_sleep)))
task = [sleep(3), new_sleep(3)]
loop.run_until_complete(asyncio.wait(task))
loop.close()
2 使用协程实现群聊
import asyncio
async def my_handle(client_reader, client_writer):
while True:
data = await client_reader.read(1024)
print("client reader:{}".format(dir(client_reader)))
print("client writer:{}".format(dir(client_writer)))
client = client_writer.get_extra_info("peername")
msg = "{} your message {}".format(client, data.decode()).encode()
client_writer.write(msg)
await client_writer.drain()
def my_chat(*args):
ip = "127.0.0.1"
port = 9998
loop = asyncio.get_event_loop()
chat = asyncio.start_server(my_handle, ip, port, loop=loop)
server = loop.run_until_complete(chat)
print("current socket:{}".format(server))
try:
loop.run_forever()
except Exception as e:
print(e)
pass
finally:
server.close()
loop.close()
if __name__ == '__main__':
my_chat()
3 aiohttp模块
使用aiohttp模块实现http serve r和http client 示例:
import asyncio
from aiohttp import web
from aiohttp import ClientSession
class MyServer:
@classmethod
async def get_html_index_handle(cls, req: web.Request):
return web.Response(text=req.path, status=201)
@classmethod
async def get_html_handle(cls, req: web.Request):
print(req.match_info)
print(req.query_string)
return web.Response(text=req.match_info.get("id", "0000"), status=200)
def implement_server(self):
app = web.Application()
app.router.add_get("/", self.get_html_index_handle)
app.router.add_get("/{id}", self.get_html_handle)
web.run_app(app, host="127.0.0.1", port=9998)
class MyClient:
@classmethod
async def get_html(cls, url: str):
async with ClientSession() as session:
async with session.get(url) as res:
print(res.status)
print(await res.text())
def implement_client(self):
url = "http://127.0.0.1:9998/ziroom-web"
loop = asyncio.get_event_loop()
loop.run_until_complete(self.get_html(url))
loop.close()
|