目录
了解进程和线程
单个线程(主线程)在执行
多线程
线程池
协程(爬虫多用)
假异步:(同步)
真异步:
爬虫代码模版
异步-爬虫
同步效果--19+秒
异步效果--7+秒
# --------------------> # ------> # -------> # --------> # 1-线程 #线程:执行一个软件后的操作---点赞,签到,评论等等 #进程:执行一个软件
一家公司里面人去做事. 1人,2人,多人... (要合理分配,合理运用.) --30万的资本,养不起10000人呀. 1个进程必须要有一个线程,--- 线程不是越多越好. 单线程/多线程 进程:资源单元 线程:执行单元
# 每一个py程序默认都有一个线程的, print("111")
from threading import Thread # alt + enter 快捷键导包 def func(name): for i in range(1, 1000): print("func函数在执行---" + str(i),name) # func() # 这样写就是主线程执行. # 创建线程对象,分配线程的任务是func (公司招人要分配任务) t = Thread(target=func,args=('my name xiaodi',)) # args的参数必须是一个元组. # 启动线程: (员工先忙完手头工作,然后真正工作) t.start() # 线程的状态,可以开始工作的状态了,具体的执行时间由CPU决定. t1 = Thread(target=func,args=('xiaosedi',)) t1.start() # 主线程不会受到子线程(其他线程)的干扰. 主线程该干什么就干什么. for i in range(1, 1000): print("主---" + str(i)) # 多个线程都输出到控制台上,就会乱. # 传参在创建线程对象时也要传. # 线程数由电脑的CPU决定,如果处理不好,反而会效率下降.
# 线程池 :一次性开辟一些线程,直接给线程池提交任务,具体的任务到底哪个线程执行,是由线程池分配的 from concurrent.futures.thread import ThreadPoolExecutor def func(name): for i in range(1000): print(name, 'func函数执行', i) # 创建一个有50个线程的线程池.(合理的利用资源~) # -----执行10次func函数,每个func函数执行1000次. with ThreadPoolExecutor(50) as t: # t = ThreadPoolExecutor(50) for i in range(10): # 给线程去提交任务 t.submit(func, name=f'线程{i}') # 等待线程池中的任务全部执行完毕,才会继续执行 print('print执行了')
import asyncio import time def func(): print("函数开始") time.sleep(3) # 当到此时,当前线程为阻塞状态,CPU不会为当前程序提供工作. print("函数结束") func() # 阻塞代码:(必须要等待某个结果等等 # input(等待输入) time.sleep(强制等待) requests(请求网络,client<->server有时间差, # 程序基于 i(input) o(output) 操作时,线程机会处于阻塞状态,CPU就不会提供工作. # ---阻塞的时候就会干等着,---怎么让CPU在干等着的时候也做点事情呢?--->协程!!! # 协程:当程序遇见了io操作的时候,可以选择性的切换到其它任务上。 # 多任务异步操作:
import asyncio import time async def func1(): print('func1函数开始') time.sleep(3) # 属于同步操作代码。 # 只要在异步程序中出现了同步操作,异步就被中断 # await asyncio.sleep(3) print('func1函数结束') async def func2(): print('func2函数开始') time.sleep(2) # await asyncio.sleep(2) print('func2函数结束') async def func3(): print('func3函数开始') time.sleep(4) # await asyncio.sleep(4) print('func3函数结束') # 拿到函数的对象 f1 = func1() f2 = func2() f3 = func3() tasks = [ # 创建一个任务 f1, f2, f3 ] start = time.time() # 如果是多个任务,需要一个asyncio.wait(任务列表)搭配 asyncio.run(asyncio.wait(tasks)) print(time.time() - start)
import asyncio import time async def func1(): print('func1函数开始') # time.sleep(3) # 属于同步操作代码 await asyncio.sleep(3) # 异步休眠代码 --不是强制性的休眠,而是挂起,让他先去忙别的东西,等好了再回来. print('func1函数结束') async def func2(): print('func2函数开始') # time.sleep(2) await asyncio.sleep(2) print('func2函数结束') async def func3(): print('func3函数开始') # time.sleep(4) await asyncio.sleep(4) print('func3函数结束') #async def main(): # f1 = func1() # f2 = func2() # f3 = func3() # tasks = [ # f1,f2,f3 # # 创建一个任务 # # asyncio.create_task(func1()), # # asyncio.create_task(func2()), # # asyncio.create_task(func3()) # ] # await asyncio.wait(tasks) # start = time.time() # asyncio.run(main()) # print(time.time() - start) f1 = func1() f2 = func2() f3 = func3() tasks = [ f1, f2, f3 # 创建一个任务 ] start = time.time() # 如果是多个任务,需要一个asyncio.wait(任务列表)搭配 asyncio.run(asyncio.wait(tasks)) print(time.time() - start)
import asyncio async def download(url): print('准备开始下载') # await asyncio.sleep(2) # 网络请求 # requests.get(url) # 异步效果中断,那怎么结合呢??? print('下载完成') async def main(): urls = [ '地址1', '地址2', '地址3', ] # tasks = [] # for url in urls: # tasks.append(download(url)) # 列表推导式写法 循环url列表,每循环一次,创建一个任务 tasks = [download(url) for url in urls] await asyncio.wait(tasks) asyncio.run(main())
因为requests模块是同步的,如果在异步协程中编写同步代码,异步效果没有。 如何解决? 更换支持异步的请求模块 aiohttp == requests pip install aiohttp pip install aiofiles
import time import requests urls = [ 'https://www.cgwallpapers.com/wallpapers_free_wreoiux/wallpaper_christian_dimitrov_02_1920x1080.jpg', 'https://www.cgwallpapers.com/wallpapers_free_wreoiux/wallpaper_pablo_carpio_17_1920x1080.jpg', 'https://www.cgwallpapers.com/wallpapers_free_wreoiux/wallpaper_dejian_wu_04_1920x1080.jpg' ] t = time.time() for url in urls: res = requests.get(url).content # 文件名 name = url.split('/')[-1] with open(name, 'wb') as f: f.write(res) print(f'requests花费时间===》{time.time() - t}') # requests花费时间===》19.635247230529785
import asyncio import time import aiofiles import aiohttp urls = [ 'https://www.cgwallpapers.com/wallpapers_free_wreoiux/wallpaper_christian_dimitrov_02_1920x1080.jpg', 'https://www.cgwallpapers.com/wallpapers_free_wreoiux/wallpaper_pablo_carpio_17_1920x1080.jpg', 'https://www.cgwallpapers.com/wallpapers_free_wreoiux/wallpaper_dejian_wu_04_1920x1080.jpg' ] async def download(url): print('准备开始下载--->') # s = aiohttp.ClientSession() == requests #拿到对象 # s.get() s.post === requests.get() requests.post() # -------------------------------------- # aiohttp requests # res.text() res.text # res.read() res.content # res.json() res.json() # -------------------------------------- async with aiohttp.ClientSession() as s: async with s.get(url) as res: # 写入文件 name = url.split('/')[-1] # 文件正常操作: # with open(name,'wb')as f: # f.write(await res.read()) # 文件异步操作: async with aiofiles.open(name, 'wb') as f: await f.write(await res.read()) print('下载完成') async def main(urls): tasks = [download(url) for url in urls] await asyncio.wait(tasks) t = time.time() asyncio.run(main(urls)) print(f'aiohttp花费时间===》{time.time() - t}') # aiohttp花费时间===》7.244250774383545