爬虫-协程及语法

一、什么是协程

  在单线程中,一个线程在运行的过程中,如果遇到一些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())  #启动协程
posted @ 2024-01-18 20:52  zhang0513  阅读(2)  评论(0编辑  收藏  举报