单/多线程--协程--异步爬虫

免责声明:本文仅做技术交流与学习...

目录

了解进程和线程

单个线程(主线程)在执行

多线程

线程池

协程(爬虫多用)

假异步:(同步)

真异步:

爬虫代码模版

异步-爬虫

同步效果--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)
​

9+秒结束!!! ---没有异步呀---

因为time是一个同步模块,

复制代码
time.sleep()  # 属于同步操作代码。
# 只要在异步程序中出现了同步操作,异步就被中断

真异步:

复制代码
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)

4+秒 , 好快呀...


爬虫代码模版

复制代码
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.get(url) # 异步效果中断,那怎么结合呢???

只要出现同步操作,异步就会被终断.

-------->


异步-爬虫

复制代码
因为requests模块是同步的,如果在异步协程中编写同步代码,异步效果没有。
​
如何解决?
更换支持异步的请求模块
aiohttp  == requests
pip install aiohttp
pip install aiofiles

同步效果--19+秒

复制代码
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

异步效果--7+秒

复制代码
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
​

相关推荐
musk121213 分钟前
electron 打包太大 试试 tauri , tauri 安装打包demo
前端·electron·tauri
q567315231 小时前
R语言初学者爬虫简单模板
开发语言·爬虫·r语言·iphone
万少1 小时前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL1 小时前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl022 小时前
java web5(黑马)
java·开发语言·前端
Amy.Wang2 小时前
前端如何实现电子签名
前端·javascript·html5
今天又在摸鱼2 小时前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿2 小时前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再2 小时前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref
jingling5552 小时前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架