Python爬虫中的多线程、线程池

进程和线程的基本介绍

进程是一个资源单位,线程是一个执行单位,CPU调度线程来执行程序代码。

当运行一个程序时,会给这个程序分配一个内存空间,存放变量等各种信息资源,而这个内存空间可以说是一个进程, 一个进程默认情况下会有一个线程,称为主线程(因为执行是靠线程的,CPU调度线程来执行程序代码,如果没有线程,那么进程中的资源就不能被使用,代码也就不能被执行)

做个比喻:一个进程相当于一个公司,公司里有各种办公资源,而公司里的员工就相当于线程,工作由员工使用办公资源完成, 如果没有员工,那么那些办公资源不会自动把工作完成,而一个公司必须至少有一个员工,不然公司还能自己成立嘛?

单线程

def func():
    for i in range(3):
        print('func: ', i)


if __name__ == '__main__':
    
    func()
    for i in range(3):
        print('main: ', i)

执行效果:

 

多线程(写法一)

from threading import Thread

# 多线程
def func():
    for i in range(3):
        print('func: ', i)


if __name__ == '__main__':
    # 创建一个线程,target参数是告诉这个线程该干什么事
    # 就比如招聘了一个新员工,要给他安排任务
    # 此处给线程的任务就是调用func方法
    t = Thread(target=func)
    # 启动线程,告诉线程可以开始干活了
    # 注意,start方法只是说线程的状态是工作状态,但是什么时候真的开始执行,由CPU决定
    # 就是说线程已经随时准备就绪,等待CPU的调度执行
    t.start()
    for i in range(3):
        print('main: ', i)


# 多线程
def func(name):
    for i in range(3):
        print(name, i)


if __name__ == '__main__':
    # 要给func传递参数,则可以利用args参数
    # 注意,args接收的是元祖,所以只有一个参数的话,要加上逗号
    t1 = Thread(target=func, args=('线程1',))
    t1.start()
    
    # 创建第二个线程
    t2 = Thread(target=func, args='线程2',)
    for i in range(3):
        print('main: ', i)

 执行结果:

多线程(写法二)

from threading import Thread

# 多线程(写法二)
# 自定义线程类,要继承 Thread
class MyThread(Thread):
    def run(self):  # 重写run方法
        for i in range(3):
            print('子线程: ', i)


if __name__ == '__main__':
    t = MyThread()
    # 注意,不能 t.run() ,否则就相当于方法调用,那么就是单线程而不是多线程
    # 必须通过start方法调用
    # t.run()  # 错误

    # 调用start方法时,start方法会自己去调用run方法
    # 所以当线程被执行时,执行的是run方法里的代码逻辑
    t.start()
    for i in range(3):
        print('主线程: ', i)

执行效果

创建多进程

和创建多线程差不多 

from multiprocessing import Process

def func():
    for i in range(3):
        print('子进程:', i)

# 创建进程比创建线程所耗费的资源要多很多,所以一般我们使用的都是线程
if __name__ == '__main__':
    # 如果打印结果不是混着的,应该也是正常的,因为我执行的时候结果和单线程一样
    p = Process(target=func)
    p.start()
    for i in range(3):
        print('主进程:', i)

线程池和进程池基本介绍

假设现在我们要爬取一个网站的评论信息,这个网站的评论由于有很多,被分为1000页,那么我们可以用for循环去爬取每一页的评论数据,但我们想提高效率,利用线程来完成。

我们可以创建1000个线程,每个线程分别爬取一个分页,但是创建线程也需要耗费时间和资源,创建1000个线程的效率可能不一定比for循环效率高。

那我们可以考虑少创建一些线程,比如创建50个线程,然后让这50个线程依次去爬取1000个分页的评论,这就是线程池的作用。我们不需要关心这50个线程的具体调度情况,比如哪个进程爬取了哪些网页之类的,我们只需要知道,这50个线程会一起合作,完成1000个URL的爬取任务即可。而具体的每个线程的调度安排由线程池管理。

所以线程池就是一次性开辟一些线程(如一次性开辟50个线程),我们用户直接给线程池提交某个任务(比如爬取1000个URL),由线程池安排这50个线程去共同完成这个任务。

线程池代码如下,进程池的使用和线程池一样,只需要把 ThreadPoolExecutor 换成 ProcessPoolExecutor就行

# ThreadPoolExecutor 线程池, ProcessPoolExecutor 进程池
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

def task(name):
    print('执行任务', name)

if __name__ == '__main__':
    # 创建有3个进程的进程池
    with ThreadPoolExecutor(3) as t:
        for i in range(6):  # 现在要完成6个任务,将这6个任务分配给3个线程
            # 向线程池t提交任务task, 任务task需要传惨直接在后面写上,如name=xxx
            t.submit(task, name=f'task{i}')

    # 只有上述线程池代码执行完成后,才会接着往下执行
    print('任务全部执行完毕...')

执行效果如下图:

 进程池的应用——爬取北京新发地的价格数据

import requests
from concurrent.futures import ThreadPoolExecutor


def download_one_page(cur_page):
    url = 'http://www.xinfadi.com.cn/getPriceData.html'
    data = {
        'limit': 20,
        'current': cur_page,  # 第多少页的数据
        'pubDateStartTime': '',
        'pubDateEndTime': '',
        'prodPcatid': '',
        'prodCatid': '',
        'prodName': ''
    }
    resp = requests.post(url, data=data)
    print(resp.json())


if __name__ == '__main__':
    # 可以分别对比for循环和用线程池两种爬取方式,会看到线程池的速度要快很多
    # for i in range(1, 101): 
    #     download_one_page(i)
    with ThreadPoolExecutor(10) as t:  # 创建有10个进程的进程池
        for i in range(1, 101):  # 数据太多了,这里只爬取前100页
            t.submit(download_one_page, cur_page=i)
    print('爬取北京新发地前100页数据完成!')

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/270821.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

论文阅读<CF-YOLO: Cross Fusion YOLO for Object Detection in Adverse Weather.....>

论文链接:https://arxiv.org/pdf/2309.08152.pdfhttps://arxiv.org/pdf/2206.01381.pdfhttps://arxiv.org/pdf/2309.08152.pdf 代码链接:https://github.com/DiffPrompter/diff-prompter 目前没有完整代码放出。 恶劣天气下的目标检测主要有以下三种解…

2023年12月【考试战报】|ORACLE OCP 19C考试通过

2023年10月【考试战报】|ORACLE OCP 19C考试通过-CSDN博客文章浏览阅读122次。自OCP认证进入中国以来,越来越被大多数DBA所认可,也越来越被企业所重视,90%以上DBA深造,都会选择OCP认证。随着OCP认证在全国范围内的普及&#xff0c…

ios 之 数据库、地理位置、应用内跳转、推送、制作静态库、CoreData

第一节:数据库 常见的API SQLite提供了一系列的API函数,用于执行各种数据库相关的操作。以下是一些常用的SQLite API函数及其简要说明:1. sqlite3_initialize:- 初始化SQLite库。通常在开始使用SQLite之前调用,但如果没有调用&a…

【MySQL】数据库之存储引擎

目录 一、什么是存储引擎 MySQL 整个查询执行过程,即MySQL的工作原理? 二、MyISAM 与 InnoDB 的区别? 三、如何查看当前表的存储引擎? 1.查看当前的存储引擎 2.查看数据库支持哪些存储引擎 四、如何设置存储引擎?…

使用 Jekyll 构建你的网站 - 初入门

文章目录 一、Jekyll介绍二、Jekyll安装和启动2.1 配置Ruby环境1)Windows2)macOS 2.2 安装 Jekyll2.3 构建Jekyll项目2.4 启动 Jekyll 服务 三、Jekyll常用命令四、目录结构4.1 主要目录4.2 其他的约定目录 五、使用GitLink构建Jekyll博客5.1 生成Jekyll…

Github 2023-12-25开源项目周报 Top15

根据Github Trendings的统计,本周(2023-12-25统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目7Go项目2非开发语言项目2Dart项目1TypeScript项目1Rust项目1Kotlin项目1 GPT-Engineer: 自然语言编…

DevC++ easyx实现视口编辑,在超过屏幕大小的地图上画点,与解决刮刮乐bug效果中理解C语言指针的意义

继上篇文案, DevC easyx实现地图拖动,超过屏幕大小的巨大地图的局部显示在屏幕的方法——用悬浮窗的原理来的实现一个视口-CSDN博客 实现了大地图拖动,但是当时野心不止,就想着一气能搓啥就继续搓啥,看着地图移动都搓…

nodejs+vue+微信小程序+python+PHP基于Android的共享自习室APP系统-计算机毕业设计推荐

1.用户端: 一、首页: (1)店面轮播图及位置、营业时间 (2)预约储物柜功能:选择储物柜号码、确认预约 (3)会员功能:解锁VIP座位、个人积分信息(查看…

STM32 cubeMX 光敏电阻AD转化实验

文章代码使用 HAL 库。 文章目录 前言一、光敏电阻介绍二、光敏电阻原理图解析三、ADC采样介绍1. 工作原理:2. ADC精度: 四、STM32 cubeMX配置ADC采样五、代码编写总结 前言 实验开发板:STM32F051K8。所需软件:keil5 ,…

解决ELement-UI三级联动数据不回显

目录 一.处理数据时使用this.$set方法来动态地设置实例中的属性,以确保其响应式。 二.检查数据格式是否正确 三.绑定v-if 确保每次执行 四.完整代码 一.处理数据时使用this.$set方法来动态地设置实例中的属性,以确保其响应式。 二.检查数据格式是否正确…

TypeScript下载安装,编译运行

TypeScript是拥有类型的JavaScript超集,它可以编译成普通、干净、完整的JavaScript代码。 简单理解:TypeScript就是加强版的JavaScript。 TypeScript最终会被编译成JavaScript代码,那么我们必然需要对应的编译环境 环境搭建前提&#xff1a…

简单的喷淋实验(2):(1)根据土壤湿度自动控制喷淋开关;(2)根据光照强度控制风扇以及灯的开关---嵌入式实训

目录 简单的喷淋实验(2): (1)根据土壤湿度自动控制喷淋开关; (2)根据光照强度控制风扇以及灯的开关---嵌入式实训 任务2: 具体过程: 所用的头文件: data_global.h …

人工智能_机器学习073_SVM支持向量机_人脸识别模型建模_预测可视化_网格搜索交叉验证最优化参数对比---人工智能工作笔记0113

接着上一节来说,可以看到我们已经找到了合适的参数,然后 我们可以看一下这里 gc.best_params_ 就可以打印出最合适的参数 然后我们把最合适串按说填入到代码中,然后进行计算,看看得分 可以看到得分,训练数据是1.0 然后测试数据得分是0.7857...对吧

nodejs+vue+微信小程序+python+PHP的热带野生动物园景点预约订票系统的设计与实现-计算机毕业设计推荐

管理员是系统的管理者,拥有系统的所有权限,通过系统设定的账号和密码登录后对系统进行管理,包括密码修改、用户管理。新闻公告的管理、景点管理、订单管理。管理员登录中,通过用户的登录名和密码到热带野生动物园景点预约订票系统…

three.js后处理(发光描边OutlinePass描边样式

效果&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><div class"box-right"></div>&…

WPS复选框里打对号,显示小太阳或粗黑圆圈的问题解决方法

问题描述 WPS是时下最流行的字处理软件之一&#xff0c;是目前唯一可以和微软office办公套件相抗衡的国产软件。然而&#xff0c;在使用WPS的过程中也会出现一些莫名其妙的错误&#xff0c;如利用WPS打开docx文件时&#xff0c;如果文件包含复选框&#xff0c;经常会出…

vue3+ts 代理的使用

简单封装request.ts import axios from "axios";// 1.创建axios对象 const serviceaxios.create();// 2.请求拦截器 service.interceptors.request.use(config>{return config; },error>{Promise.reject(error); })// 3.响应拦截器 service.interceptors…

助力打造清洁环境,基于YOLOv7开发构建公共场景下垃圾堆放垃圾桶溢出检测识别系统

公共社区环境生活垃圾基本上是我们每个人每天几乎都无法避免的一个问题&#xff0c;公共环境下垃圾投放点都会有固定的值班时间&#xff0c;但是考虑到实际扔垃圾的无规律性&#xff0c;往往会出现在无人值守的时段内垃圾堆放垃圾桶溢出等问题&#xff0c;有些容易扩散的垃圾比…

HarmonyOS应用程序包-(上)

应用程序包-(上) 1.应用程序包概述 用户应用程序泛指运行在设备的操作系统之上&#xff0c;为用户提供特定服务的程序&#xff0c;简称“应用”。一个应用所对应的软件包文件&#xff0c;称为“应用程序包”。 HarmonyOS提供了应用程序包开发、安装、查询、更新、卸载的管理…

王道考研计算机网络——数据链路层

码元和信号变化是一一对应的 低通&#xff1a;低于最高频率的可以通过 奈氏准则无噪声&#xff0c;香农定理有噪声 给出db&#xff0c;利用公式求出S/N 放到数字信道上传输就是基带信号&#xff0c;放到模拟信道上传输就是宽带信号 把基带信号调制成宽带信号之后&#xff0c;…