网站搭建笔记精简版---廖雪峰WebApp实战-Day2:编写Web App骨架笔记

网站搭建笔记精简版-廖雪峰教程学习@[三川水祭]
仅作学习交流使用,将来的你会感谢现在拼命努力的自己!!!

目录

什么是IO
异步IO的背景知识
Web app骨架搭建
asyncio函数与aiohttp函数详解

什么是IO

IO意思是输入与输出,本地是内存,外地是磁盘或网页,本地往外地发送数据叫做输出Output,本地接收外地发送的数据叫做Input。IO包括同步IO与异步IO。举个栗子,背景是内存往磁盘写数据,内存输出这个数据需要0.1s,而磁盘接收这个数据需要10s
同步IO:当内存输出完数据后,处于等待状态,等磁盘接收完数据后继续执行接下来的步骤
异步IO:当内存输出完数据后,懒得等磁盘慢悠悠的写,就直接搞别的事情去了,等磁盘写完后,通知内存,然后内存才与磁盘继续往下执行项目。
而磁盘通知内存有两种方式,分别为回调模式与轮询模式。
回调模式:磁盘直接过去调用内存,开展下一步工作。
轮询模式:磁盘发个信息给内存,告诉内存已经完成工作,可开展下一步工作了,而内存在搞别的事情的时候则需要时不时的看一下消息,确定磁盘是否完成。当接收到消息后,才与磁盘共同开展下一步工作。

异步IO背景知识

面临问题:CPU执行速度高而IO设备执行速度低(龟速)。
解决方法:多线程和多进程、异步IO。
多线程的缺点:当线程数量较多时候,CPU资源主要用在线程之间的切换上,真正搞代码的资源少,性能严重下降。
进程:系统进行资源分配和调度的一个独立单位,有自己的内存空间
线程:是CPU调度和分派的基本单位,共享进程内存资源。
协程:使用yield函数,不断的在子程序之间进行切换的单条线程。是一种轻量级的线程,可以在不加锁的情况下访问全局变量。
迭代器:iter函数,迭代的对象从第一个元素开始访问,直到所有元素访问完后才可结束,或者通过StopIteration强制结束。对象可以使列表、元组和字符串。
生成器:yield函数,执行到当前进行阻塞,n = yield r的意思是当前函数接收到数据后将值传递给n,若n为None,则不执行,反之向下执行循环到该条函数处,阻塞,返回r,等待接收新一轮n值。
迭代器与生成器参考该网页。网页下的评论有更详细的解释。

Web app骨架搭建

该部分使用asyncio处理异步IO编程,实现单线程并发操作。进而使用aiohttp网络框架创建TCP网络服务器,不断使用轮询模式接收浏览器相应,通过解析浏览器发过来的请求,寻找相应的coroutine类执行函数,返回相应的Body response。coroutine类表示可并发且带有生成器的执行函数。

import logging; logging.basicConfig(level=logging.INFO)

import asyncio, os, json, time
from datetime import datetime

from aiohttp import web

# 将生成器index函数标记为coroutine
async def index(request):
    # 相应的格式,注意加上content_type='text/html'属性,否则会显示为下载文件。
    return web.Response(body=b'<h1>Awesome</h1>', content_type='text/html')

async def init(loop):
    app = web.Application(loop=loop)
    # 链接index函数与‘/'对象,当接收到GET '/'时候,延迟两秒,服务器返回Index。
    app.router.add_route('GET', '/', index)
    # 创建TCP服务,等待请求。
    srv = await loop.create_server(app.make_handler(), '127.0.0.1', 9000)
    # 生成日志信息
    logging.info('server started at http://127.0.0.1:9000...')
    return srv

# 使用轮询模式保证协程执行
loop = asyncio.get_event_loop()
# s使用init函数创建TCP服务,等待浏览器链接,并使用相关函数进行相应。
loop.run_until_complete(init(loop))
# 一直等着浏览器的链接请求。
loop.run_forever()

asyncio函数与aiohttp函数详解

asyncio函数:实现异步IO编程的函数。可利用一下代码进行实验。可参考本网页

import asyncio

# async等价于@asyncio.coroutine,将wget这个generator函数标记为coroutine对象
# 之后将该协程对象扔到get_event_loop函数中执行,实现异步IO操作。
async def wget(host):
    print('wget %s...' % host)
    connect = asyncio.open_connection(host, 80)
    # 调用connect,返回读与写两个IO,分别负责本地接收网页发送的消息与向网页发送消息两种模式。
    # await类似于yield from生成器
    reader, writer = await connect
    header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host
    writer.write(header.encode('utf-8'))
    # drain函数就是将write到缓存区的东西flush一下,提交给网页。
    await writer.drain()
    while True:
        # 循环读取网页返回来的信息
        line = await reader.readline()
        # 可查看读取的具体信息是什么
        #print(line)
        # 当读到'\r\n'时候代表网页相应头已经读取完成,之后就是body部分。
        if line == b'\r\n':
            break
        print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
    # Ignore the body, close the socket
    writer.close()

# 使用轮询模式保证协程执行
loop = asyncio.get_event_loop()
# 将多个coroutine对象封装成一个Task任务列表
tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
# 使用asyncio.wait(task)将任务并发执行。
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

aiohttp:aiohttp则是基于asyncio实现的HTTP框架,直接调用里面的函数就可使实现简单的本地HTTP服务器搭建。可利用一下代码进行实验。想了解具体机制的参考本网页,想了解函数中add_route机制的参考本网页

import logging; logging.basicConfig(level=logging.INFO)
import asyncio

from aiohttp import web

# 将生成器index函数标记为coroutine
async def index(request):
    # 延时两秒后继续执行之后的步骤
    await asyncio.sleep(2)
    # 相应的格式,注意加上content_type='text/html'属性,否则会显示为下载文件。
    return web.Response(body=b'<h1>Index</h1>', content_type='text/html')

# 将生成器hello函数标记为coroutine
async def hello(request):
    # 延时两秒后继续执行之后的步骤
    await asyncio.sleep(2)
    text = '<h1>hello, %s!</h1>' % request.match_info['name']
    # 相应的格式,head会自动生成,自己负责写body即可。
    return web.Response(body=text.encode('utf-8'), content_type='text/html')

# 将生成器init函数标记为coroutine
async def init(loop):
    app = web.Application(loop=loop)
    # 链接index函数与‘/'对象,当接收到GET '/'时候,延迟两秒,服务器返回Index。
    app.router.add_route('GET', '/', index)
    # 链接index函数与‘/hello/{name}'对象,当接收到GET '/hello/{name}'时候,
    # 延迟两秒,服务器取出{name}对象,并构造新的body进行返回。
    app.router.add_route('GET', '/hello/{name}', hello)
    # 创建TCP服务,等待请求。
    srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
    # 显示日志信息。
    logging.info('server started at http://127.0.0.1:9000...')
    return srv

# 使用轮询模式保证协程执行
loop = asyncio.get_event_loop()
# s使用init函数创建TCP服务,等待浏览器链接,并使用相关函数进行相应。
loop.run_until_complete(init(loop))
# 一直等着浏览器的链接请求。
loop.run_forever()

在浏览器输入localhost:8000,等两秒,网页会接收到返回信息并显示为index。接下来在浏览器输入localhost:8000/hello/handsome,等两秒,网页显示hello, handsome!。
参考博客
廖雪峰的官方网站
python之aiohttp源码解析——add_route和middleware的工作方式
进程、线程、协程之概念理解

猜你喜欢

转载自blog.csdn.net/suyiwei5993/article/details/83388162
今日推荐