网站搭建笔记精简版-廖雪峰教程学习@[三川水祭]
仅作学习交流使用,将来的你会感谢现在拼命努力的自己!!!
目录
什么是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', 'www.sohu', 'www.163']]
# 使用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的工作方式
进程、线程、协程之概念理解
更多推荐
网站搭建笔记精简版---廖雪峰WebApp实战-Day2:编写Web App骨架笔记
发布评论