爬虫-协程及语法
一、什么是协程
在单线程中,一个线程在运行的过程中,如果遇到一些IO操作的时候,CPU会停止等待,此时线程会处于阻塞状态,为了更好的利用CPU,
当线程阻塞的时候,让线程去做其他的事情,从而提高CPU的利用率,如下面代码
import time def fun(): print("开始打印,然后休息3s") time.sleep(3) print("休息3秒再干") if __name__ == '__main__': fun()
在上面的过中,有3秒,cpu不是为你所用,有可能阻塞或做其他的事情,如何想让CPU一直未其所用
当线程在遇到IO操作的时候,将线程中的任务切换进行切换,切换到非IO操作中,等原来的IO执行完成后,在恢复执行原来的任务,就是协程
如果需要协程,需要改进;
import time import asyncio async def fun(): print("开始打印,然后休息3s") time.sleep(3) print("休息3秒再干") if __name__ == '__main__': fun()
运行结果:
RuntimeWarning: coroutine 'fun' was never awaited fun() RuntimeWarning: Enable tracemalloc to get the object allocation traceback
这是因为,当函数前面加上async后,就是一个协程对象,类似一个生成器,执行方式就不是这样了,应该是下面的方式
import time import asyncio async def fun(): print("开始打印,然后休息3s") time.sleep(3) print("休息3秒再干") if __name__ == '__main__': coroutine = fun() print(coroutine) #<coroutine object fun at 0x000001B69F1993C0> asyncio.run(coroutine) #利用run去运行协程对象
运行时间并效果并不明显,看下面代码
import asyncio import time async def func1(): print("fun1,start") await asyncio.sleep(4) print("fun1,end") async def func2(): print("fun2,start") await asyncio.sleep(2) print("fun2,end") async def func3(): print("fun3,start") await asyncio.sleep(3) print("fun3,end") async def main(): print("satrt") tasts = [ #创建协程列表 asyncio.create_task (func1()), asyncio.create_task (func2()), asyncio.create_task (func3()) ] await asyncio.wait(tasts) if __name__ == "__main__": satrt = time.time() asyncio.run(main()) end = time.time() print(end-satrt)
运行结果,正常运行至少时间在 4 + 2+ 3 = 9s,现在只有4s多
satrt fun1,start fun2,start fun3,start fun2,end fun3,end fun1,end 4.024667501449585
说明:协议等待用await:当任务被挂起后,cpu会自动切换到其他任务中去,await一般写在函数里,不能放在main入口里
await asyncio.wait(tasts)
等价下面的写法
lop = asyncio.get_event_loop()
lop.run_until_complete(asyncio.run(tasts))
利用协程爬虫:
import asyncio import time async def download(url): print("开始抓取") await asyncio.sleep(3) #网络请求的过程,这里不是request.get()了 print("下载完成",url) # return "这是源代码" async def main(): urls = [ "http://www.baidu.com", "http://huawei.com", "http://sougou.com" ] #生成任务列表 tasks = [] for url in urls: d = download(url) tasks.append(d) await asyncio.wait(tasks) if __name__ == '__main__': asyncio.run(main()) #启动协程