我们在做爬虫的时候,都会遇到需要爬的数据量特别巨大的,如果按照以往的一 一下载的话,好费的时间很长,效率极低,所以我们可以利用线程加协程的方法大大提高爬虫的效率。
进程是资源单位,每一个进程里至少有一条线程
线程是执行单位,起到的每一个程序都会默认有一个主线程,演示如下:
from threading import Thread #导入多线程模块
def func ():
for i in range(1000):
print('func',i)
if __name__=='__main__':
t = Thead(target=func)#创建线程并给线程安排任务
t.start()#多线程状态为可以开始工作状态,具体执行时间由spu决定
- for i in range(1000):
- print('子线程',i)
- 面向对象写法:
class MyThread(Thread):
def run(self):
for i in range(1000):
print('子线程',i)
if __name__ =='__main__':
t =MyThread()
t.start()
for i in range(1000):
print ('主线程',i)
进程的写法跟线程的差不多,只需要导入的进程的模块,然后把要执行的对象加上去就好。
接下来就是多线程池的操作演示:
from concurrent.futures import ThreadPoolExecutor#多线程池模块
def f(name):
for i in range(1000):
print(name,i)if __name__ == '__main__':
with ThreadPoolExecutor(50)as t:#创建50个线程池来进行大批量的下载
for i in range(100):
t.submit(f,name=f"线程{i}")print("123")#等待线程池中的任务完全执行完毕,才继续执行(守护)
协程的概念:
import time from time import sleep def func(): print('我爱你') #让当前的线程处于阻塞状态,cpu是不会工作的 time.sleep(3) print('我真的很爱你') if __name__ == '__main__': func()
ibput() 程序也是处于阻塞状态 requests.get(bilbili)在网络请求返回数据之前,程序也是处于阻塞状态 一般情况下,当程序处于 IO操作的时候,线程都会处于阻塞状态 协程,当程序遇见了IO操作的时候,可以选择性的切换到其他任务上 在微观上是一个任务一个任务的进行切换,切换条件一般就是IO操作 在宏观上,我们能看到的其实是多个任务一起在执行 多任务异步操作 上方所讲的一起,都是在单线程的条件下
协程的创建方式:
import asyncio import time t1 =time.time() async def func1(): print('你好漂亮') time.sleep(3) print('想加你一个微信') async def func2(): print('你好漂亮') time.sleep(3) print('想加你一个微信') async def func3(): print('你好漂亮') time.sleep(3) print('想加你一个微信') if __name__ == '__main__': f1 =func1() f2 =func2() f3 = func3() task ={ f1,f2,f3 } #一次性启动多个任务(协程) asyncio.run(asyncio.wait(task)) t2 = time.time() print( t2-t1)#但是这个得出的结果是这样的
说明当程序出现了同步操作的时候,异步就中断了,但 这并不是我们想要的结果,要想解决这个问题我们嘚给它加点东西:
import asyncio import time t1 =time.time() async def func1(): print('你好漂亮') await asyncio.sleep(3) print('想加你一个微信') async def func2(): print('你好漂亮') await asyncio.sleep(3) print('想加你一个微信') async def func3(): print('你好漂亮') await asyncio.sleep(3) print('想加你一个微信') if __name__ == '__main__': f1 =func1() f2 =func2() f3 = func3() task ={ f1,f2,f3 } #一次性启动多个任务(协程) asyncio.run(asyncio.wait(task)) t2 = time.time() print( t2-t1)
注意:await是挂起的意思,一般这个操作都会在协程对象前面
用异步的操作代码,来处理这个问题得出的结果是:
不过这样太麻烦了,有个官方推荐的方法:
async def main(): task =[ asyncio.create_task(func1()),#转换成task对象 asyncio.create_task(func2()), asyncio.create_task(func3()) ] await asyncio.wait(task) if __name__ == '__main__': asyncio.run(main())
直接写一个异步总函数,需要的时候直接调用就好。省事,方便。也可以完美的套在我们的爬虫代码上