python网络编程三--异步编程之协程

异步编程之协程(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  # python3.4版本使用协程装饰器 + yield。
def sleep(x):
    for i in range(3):
        print("sleep {}".format(i))
        yield from asyncio.sleep(x)


async def new_sleep(x):  # python3.5开始,语言通过`async def`关键字原生支持定义协程函数。通过`async def`关键字定义的协程函数,可以使用`asyncio.iscoroutinefunction()`判断是不是协程函数;使用`asyncio.iscoroutine`判断是不是协程对象。
    for i in range(3):
        print("new sleep:{}".format(i))
        await asyncio.sleep(x)  # 使用`async def`,则函数内就不能用yield了,yield语句用await来替换,也就是说这种语法有它自己的关键字了,虽然原理都一样。


if __name__ == '__main__':
    show_thread()
    # 事件循环是asyncio提供的核心运行机制
    loop = asyncio.get_event_loop()  # 获取一个事件循环对象对象
    print("is coroutine function:{}.".format(asyncio.iscoroutinefunction(new_sleep)))
    task = [sleep(3), new_sleep(3)]
    # loop.run_until_complete(sleep(3))  # 运行至指定的future对象运行完成
    # loop.is_running()  # 事件是否在运行
    # loop.stop()  # 停止事件
    loop.run_until_complete(asyncio.wait(task))  # asyncio.wait(task),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 server和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)  # http://127.0.0.1:9998/1?name=12301
        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)  # http://127.0.0.1:9998/
        app.router.add_get("/{id}", self.get_html_handle)  # http://127.0.0.1:9998/12301

        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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个两个四个三

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值