深圳比较大的做网站设计公司,做h5免费的网站有,wordpress.conf,电子工程网介绍协程
基本概念
协程#xff1a;当程序执行的某一个任务遇到了IO操作时#xff08;处于阻塞状态#xff09;#xff0c;不让CPU切换走#xff08;就是不让CPU去执行其他程序#xff09;#xff0c;而是选择性的切换到其他任务上#xff0c;让CPU执行新的任务#xff…协程
基本概念
协程当程序执行的某一个任务遇到了IO操作时处于阻塞状态不让CPU切换走就是不让CPU去执行其他程序而是选择性的切换到其他任务上让CPU执行新的任务当原来的任务不处于阻塞状态后CPU可以快速的回到之前的任务继续执行这样就不用让原本的程序去排队等待CPU调度。
微观上看任务是一个一个的切换执行切换条件就是某一个任务有IO操作 而宏观上我们看到的是多个任务一起执行这就是多任务异步操作。上面的一切的前提就是单线程的情况下因为多线程可以多个线程同时干多件事。
import timedef func():print(first, hi!)# 让程序睡眠3秒钟此时线程处于阻塞状态CPU不为线程工作# 当我们爬取一个网页时向一个url发送请求会通过网络传输将请求发送到服务器# 然后服务器会处理请求、准备数据、将数据通过网络传输回客户端等工作# 这一系列的操作也会耗费时间所以在从发送请求开始到接收服务器返回的数据这一段时间内# 即在网络请求返回数据之前程序也处于阻塞状态# 程序进行处于IO操作时是处于阻塞状态的time.sleep(3)print(second, hello..)if __name__ __main__:func()协程和线程的区别个人理解
昨天仔细想的时候感觉协程和线程很像不知道它们之间的区别在哪然后百度了一下在这里说一下自己的理解很不官方不懂的可以百度一下别人写的会比较详细和专业。
打个比喻一个公司有很多员工老板给每个员工分配任务员工之间各有分工每个人负责自己的工作如果遇到一个很会压榨人的老板就会给每个员工安排很多任务。员工在完成自己分配到的多个任务时因为自己只有一个人不能同时把多个任务一起干所以肯定是某个时刻内只干一件事。但是为了提高工作效率在某个任务需要等待时员工肯定不能傻傻的等着而是利用这个等待的时间去干另一个任务毕竟手上被万恶的资本家分配了很多活比如正在跑的一个程序A要运行很久那么在这个程序A运行的时间里员工肯定去写另一个程序B了如果这个程序B写完后也要运行很久那么员工就会去完成程序C或者此时程序A运行完了接着完成程序A.....
上面所说的一个公司有多个员工那么每个员工相当于一个线程多个员工各有分工干自己的活就是多个线程之间独立完成自己的工作。而一个员工充分利用时间完成多个任务从一段时间上看宏观如一周内员工同时完成多个任务但是实际上微观某个时刻员工只做一件事这每一个任务就是协程所以协程实际上是一个单线程宏观上同步完成多个任务微观上异步完成多个任务。
协程可以充分的让一个线程忙起来提高效率不然当某个任务阻塞时线程就处于空闲的等待状态这使得线程资源没有得到充分利用执行效率也大打折扣就像老板想让打工人一刻都不停的给他创造价值一样。
用Python编写协程的程序
单个异步任务
有四种方式但这里只选择其中的一种如以下代码所示
import asyncio# 这种写法就是普通的函数
# def func():
# print(你好我是张三)
#
#
# if __name__ __main__:
# func()# 在函数前面加async关键字就表明该函数是异步协程函数
async def func():print(你好我是张三)if __name__ __main__:# func() # 如果直接调用会得到一个警告RuntimeWarning: ...g func() # 此时函数是一个异步协程函数执行函数得到一个协程对象输出coroutine object func at 0x000001F823066960sys:1: RuntimeWarning: coroutine func was never awaitedprint(g)asyncio.run(g) # 协程程序的运行需要asyncio模块的支持多个异步任务
import asyncio
import time# 在函数前面加async关键字就表明该函数是异步协程函数
async def func1():print(你好我是张三)time.sleep(3)print(你好我是张三)async def func2():print(你好我是李四)time.sleep(2)print(你好我是李四)async def func3():print(你好我是王五)time.sleep(4)print(你好我是王五)if __name__ __main__:f1 func1()f2 func2()f3 func3()# 把多个异步任务放到一个列表中tasks [f1, f2, f3]t1 time.time()# 一次性启动多个异步任务协程asyncio.run(asyncio.wait(tasks))t2 time.time()print(t2 - t1) 上面三个函数是异步协程操作理论上执行时间应该会小于9秒因为异步任务会在某一个任务阻塞时去调用其他任务但是观察上述代码执行时间发现和同步执行三个函数效果一样都是用了9秒多如下图。出现这种的情况的原因是函数里的time.sleep()是同步操作而异步协程函数中出现同步操作的时候异步就中断了也就是说当异步函数中有同步操作时CPU不会切换去调用其他任务而是像同步函数那样执行完一个任务再去执行另一个任务在这个例子中就是执行完func1再执行func2再执行func3。 修改上述代码实现异步操作效果如下
import asyncio
import time# 在函数前面加async关键字就表明该函数是异步协程函数
async def func1():print(你好我是张三)# time.sleep(3) # 异步程序中出现同步操作会中断异步即不会切换任务执行# 异步操作代码表示挂起任务让任务睡眠3秒然后切换CPU去执行其他任务await asyncio.sleep(3)print(你好我是张三)async def func2():print(你好我是李四)# time.sleep(2)await asyncio.sleep(2)print(你好我是李四)async def func3():print(你好我是王五)# time.sleep(4)await asyncio.sleep(4)print(你好我是王五)# 一般不会直接像下面那样调用多个异步任务而是把它包装在一个异步协程函数里
# if __name__ __main__:
# f1 func1()
# f2 func2()
# f3 func3()
# # 把多个异步任务放到一个列表中
# tasks [f1, f2, f3]
# t1 time.time()
# # 一次性启动多个异步任务协程
# asyncio.run(asyncio.wait(tasks))
# t2 time.time()
# print(t2 - t1)async def main():# 写法一不推荐# await 都是写在异步协程函数里即与async配套使用# await后一般跟协程对象、task等对象# await表示挂起某个异步任务即是执行某个异步任务# await asyncio.create_task(func1())# await asyncio.create_task(func2())# await asyncio.create_task(func3())# 写法二推荐tasks [# asyncio.create_task(func1()) 把协程对象包装成task对象asyncio.create_task(func1()),asyncio.create_task(func2()),asyncio.create_task(func3())]# 这里await作用和上面一样表示挂起协程对象即会异步执行tasks列表中的异步任务await asyncio.wait(tasks)if __name__ __main__:t1 time.time()asyncio.run(main())t2 time.time()print(t2 - t1) 使用异步模拟爬虫程序
import asyncioasync def download(url):print(开始下载...)await asyncio.sleep(2)print(下载完成!)async def main():tasks []urls [url1, url2, url3]for url in urls:d download(url) # 得到一个异步协程对象# asyncio.create_task(d) 把协程对象包装成task对象tasks.append(asyncio.create_task(d))await asyncio.wait(tasks)if __name__ __main__:asyncio.run(main())
异步发送http请求
以下代码是根据多个图片地址异步下载图片
import asyncio
# 下载命令pip install aiohttp
import aiohttp# 图片地址
urls [https://img95.699pic.com/photo/50165/7667.jpg_wh860.jpg,https://bpic.588ku.com/back_origin_min_pic/20/04/19/f753e29e3dbe2ad75b8f6d6053199faa.jpg
]async def download(url):file_name url.rsplit(/, 1)[1]# aiohttp.ClientSession()对象等价于requests模块所以也有get、post方法# 且用法差不多async with aiohttp.ClientSession() as req: # req aiohttp.ClientSession()# 因为是异步操作所以要加上async关键字# with的作用和文件操作中的with类似可以管理上下文在使用完req对象之后会自动关闭# req.get(url) 发送请求获取图片数据async with req.get(url) as resp: # resp req.get(url)# 这里的文件读写操作也是IO操作也是会造成阻塞所以也可以通过异步协程来完成# 具体可以学习aiofiles模块来实现with open(file_name, modewb) as f:# resp.content.read()是异步操作所以前面要加await表示挂起# 挂起的意思就是resp.content.read()什么时候有东西了什么时候写入文件# 即什么时候有需要的内容了什么时候进行对应的操作# resp.content.read() 表示以字节的形式读取返回的数据的内容# 在这里就是读取图片的字节数据然后存入文件即保存图片数据f.write(await resp.content.read())# req.close() 使用with之后不用手动写上这句话print(file_name, 下载完成)async def main():tasks [asyncio.create_task(download(url)) for url in urls]await asyncio.wait(tasks)if __name__ __main__:asyncio.run(main())
使用异步爬虫爬取西游记小说内容
详见异步爬取西游记