Python爬虫——多线程爬虫如何实现?

2023-11-19

1.多任务

多任务指的是在同一时间不同任务需要同时进行的场景,比如边听歌边刷题,边看电视边吃饭…

  • 要实现多任务的进行,我们首先会想到的方式如下:
import time

# 吃饭
def Eat():
    for i in range(4):
        print('eating...')
        time.sleep(1)
# 看电视
def Watch():
    for i in range(4):
        print('watching...')
        time.sleep(1)

if __name__ == '__main__':
    Eat()
    Watch()
    
# --结果:--
# eating...
# eating...
# eating...
# eating...
# watching...
# watching...
# watching...
# watching...

嗯,,,但这是同时进行吗?仔细一想他们是有先后顺序的吧。

2.主线程与子线程

2.1 何谓线程、主线程及子线程

  • 线程:每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。
  • 主线程:程序启动时自己执行本身的代码的线程
    子线程:用户自己创建的线程
  • 主线程和子线程之间的关系:主线程是在子线程结束之后再执行的
  • 实现方式:join()方法,使子线程结束后再执行主线程;setDaemon()守护线程,不会等待子线程,有空就执行
    看看代码和结果消化一下吧!
import threading
import time

def speak():
    # 子线程
    print('A先说!')
    time.sleep(1)

if __name__ == '__main__':
    for i in range(5):
        t = threading.Thread(target=speak)
        t.start()
    print('B有话要说!')

结果(执行了几十次吧)出现了以下三种情况:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在t.start()后面添加

t.join()

时间会按照先后顺序来了,但是结果确实只有第三种了,剩下的setDaemon()加了与没加效果一样

2.2 查看线程数量

有事我们需要查看有哪些进程运行了可以使用:threading.enumerate()

例如:

import threading
import time

def speak():
    # 子线程
    print('A先说!')
    time.sleep(1)

if __name__ == '__main__':
    for i in range(5):
        t = threading.Thread(target=speak)
        t.setDaemon(True)
        t.start()
    print('B有话要说!')
    print(threading.enumerate())
    print('共有'+str(len(threading.enumerate()))+'个线程...')
    
# ---结果:---
# A先说!
# # A先说!
# # A先说!
# # A先说!
# # A先说!B有话要说!
# # [<_MainThread(MainThread, started 10900)>, <Thread(Thread-1, started daemon 5192)>, <Thread(Thread-2, started daemon 11456)>, <Thread(Thread-3, started daemon 12488)>, <Thread(Thread-4, started daemon 10588)>, <Thread(Thread-5, started daemon 4780)>]
# # 
# # 共有6个线程...

2.3 创建子线程

当然,为了简化子线程的创建,我们通过类的继承来实现,而我们所需要实现的内容,都在run方法之中进行重写。

import threading
import time

class MyThread(threading.Thread):
    # 继承threading.Thread类创建子线程
    def __init__(self,name):
        super().__init__(name=name)
    def run(self):
        for i in range(3):
            print('我是{}{}'.format(self.name,i))

if __name__ == '__main__':
    thread = MyThread('子线程')
    thread.start()
    
# --结果:--
# 我是子线程0
# 我是子线程1
# 我是子线程2

2.4 线程间的通信

  • 在⼀个函数中,对全局变量进⾏修改的时候,是否要加global要看是否对全局变量的指向进⾏了修改,如果修改了指向,那么必须使⽤global,仅仅是修改了指 向的空间中的数据,此时不⽤必须使⽤global
  • 线程是共享全局变量
  • 多线程参数的使用:threading.Thread(target=test, args=(num,))

3.线程间的资源竞争

  • 一个线程写入以及读取不会对资源的分配产生影响,但是当多个线程进行写入和读取时,他们之间就会产生资源竞争
  • 具体的资源竞争我们可以通过一个实例来进进行查看
import threading
import time

num = 0
def Thread1(nums):
    global num
    for i in range(nums):
        num += 1
    print('Thread1---{}'.format(num))

def Thread2(nums):
    global num
    for i in range(nums):
        num += 1
    print('Thread1---{}'.format(num))

if __name__ == '__main__':
    t1 = threading.Thread(target=Thread1, args=(1000000,))
    t2 = threading.Thread(target=Thread2, args=(1000000,))
    t1.start()
    t2.start()
    time.sleep(2)
    print('main---{}'.format(num))
    
# --结果:--
# Thread1---1074807
# Thread1---1400032
# main---1400032

以上结果显示,输出的结果不为我们所认为正确的答案,其原因就是资源竞争,那么何谓资源竞争?

  • 当系统中供多个进程所共享的资源,不足以同时满足它们的需要时,引起它们对资源的竞争而产生死锁。

4.互斥锁与死锁

4.1 互斥锁

  • 当多个线程⼏乎同时修改某⼀个共享数据的时候,需要进⾏同步控制
    某个线程要更改共享数据时,先将其锁定,此时资源的状态为"锁定",其他线程不能改变,直到该线程释放资源,将资源的状态变成"⾮锁定",其他的线程才能再次锁定该资源。互斥锁保证了每次只有⼀个线程进⾏写⼊操作,从⽽保证了多线程情况下数据的正确性
import threading
# 创建锁
mutex = threading.Lock()
# 锁定锁
mutex.acquire()
# 解锁
mutex.release()

4.2 死锁

  • 在线程间共享多个资源的时候,如果两个线程分别占有⼀部分资源并且同时等待对⽅的资源,就会造成死锁
    上个代码仔细再体会一下:
import threading
import time

# 创建锁A、B
mutexA = threading.Lock()
mutexB = threading.Lock()

class thread1(threading.Thread):
    def run(self):
        mutexA.acquire()
        print('thread1--A上锁成功')
        time.sleep(1)
        mutexB.acquire()
        print('thread1--B上锁成功')
        mutexA.release()
        mutexB.release()

class thread2(threading.Thread):
    def run(self):
        mutexB.acquire()
        print('thread2--B上锁成功')
        time.sleep(1)
        mutexA.acquire()
        print('thread2--A上锁成功')
        mutexB.release()
        mutexA.release()

if __name__ == '__main__':
    T1 = thread1()
    T2 = thread2()
    T1.start()
    T2.start()
    
# --结果:--
# thread1--A上锁成功
# thread2--B上锁成功

4.3 避免死锁

  • 程序设计时要尽量避免
  • 添加超时时间等

5.Queue线程

相信大家对于数据结构中的栈和队列都不陌生吧,栈在这里我们不做介绍,我们就看看队列Queue

  • 在线程中,访问⼀些全局变量,加锁是⼀个经常的过程。如果你是想把⼀些数据存储到某个队列中,那么Python内置了⼀个线程安全的模块叫做queue模 块。Python中的queue模块中提供了同步的、线程安全的队列类,包括 FIFO(先进先出)队列Queue,LIFO(后⼊先出)队列LifoQueue。这些队列都实现了锁原语(可以理解为原⼦操作,即要么不做,要么都做完),能够在多线程中直接使⽤。可以使⽤队列来实现线程间的同步。其相关方法如下:
方法 功能
empty() 判断队列是否为空
full() 判断队列是否满
put() 向队列中放入元素
get() 从队列中取出元素
qsize() 获取队列长度
from queue import Queue

q = Queue(3)

# 判断队列是否为空
print(q.empty())        #True

# 判断队列是否满了
print(q.full())         #False

# 放入元素
q.put(111)
q.put(444)
q.put(666)
# 设置timeout或put_nowait当队列满了直接跳出
# q.put(886,timeout=2)

# 获取队列长度
print(q.qsize())        #3

# 获取元素
print(q.get())          #111
print(q.get())          #444
print(q.get())          #666

6.线程同步的实现

例如实现以下会话:
老师:小明?
小明:到。
老师:给我讲讲同步线程的实现吧!
小明:我…试试吧!

代码如下:

import threading

class XiaoMing(threading.Thread):
    def __init__(self,cond):
        super().__init__(name='小明')
        self.cond = cond
    def run(self):
        self.cond.acquire()
        self.cond.wait()
        print('{}:在。'.format(self.name))
        self.cond.notify()

        self.cond.wait()
        print('{}:我...试试吧!'.format(self.name))
        self.cond.notify()
        self.cond.release()

class Teacher(threading.Thread):
    def __init__(self,cond):
        super().__init__(name='老师')
        self.cond = cond
    def run(self):
        self.cond.acquire()
        # self.cond.wait()
        print('{}:小明?'.format(self.name))
        self.cond.notify()

        self.cond.wait()
        print('{}:给我讲讲同步线程的实现吧!'.format(self.name))
        self.cond.notify()
        self.cond.release()

if __name__ == '__main__':
    cond = threading.Condition()

    teacher = Teacher(cond)
    xiaoming = XiaoMing(cond)

    xiaoming.start()
    teacher.start()

ps:一定要把先进行的对话放在后面启动。否则会导致堵塞。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python爬虫——多线程爬虫如何实现? 的相关文章

  • 如何查看Databricks中的所有数据库和表

    我想列出 Azure Databricks 中每个数据库中的所有表 所以我希望输出看起来像这样 Database Table name Database1 Table 1 Database1 Table 2 Database1 Table
  • 使用 pythonbrew 编译 Python 3.2 和 2.7 时出现问题

    我正在尝试使用构建多个版本的 python蟒蛇酿造 http pypi python org pypi pythonbrew 0 7 3 但我遇到了一些测试失败 这是在运行的虚拟机上 Ubuntu 8 04 32 位 当我使用时会发生这种情
  • 通过 Scrapy 抓取 Google Analytics

    我一直在尝试使用 Scrapy 从 Google Analytics 获取一些数据 尽管我是一个完全的 Python 新手 但我已经取得了一些进展 我现在可以通过 Scrapy 登录 Google Analytics 但我需要发出 AJAX
  • 将 saxon 与 python 结合使用

    我需要使用 python 处理 XSLT 目前我正在使用仅支持 XSLT 1 的 lxml 现在我需要处理 XSLT 2 有没有办法将 saxon XSLT 处理器与 python 一起使用 有两种可能的方法 设置一个 HTTP 服务 接受
  • 使 django 服务器可以在 LAN 中访问

    我已经安装了Django服务器 可以如下访问 http localhost 8000 get sms http 127 0 0 1 8000 get sms 假设我的IP是x x x x 当我这样做时 从同一网络下的另一台电脑 my ip
  • OpenCV Python cv2.mixChannels()

    我试图将其从 C 转换为 Python 但它给出了不同的色调结果 In C Transform it to HSV cvtColor src hsv CV BGR2HSV Use only the Hue value hue create
  • 为 Anaconda Python 安装 psycopg2

    我有 Anaconda Python 3 4 但是每当我运行旧代码时 我都会通过输入 source activate python2 切换到 Anaconda Python 2 7 我的问题是我为 Anaconda Python 3 4 安
  • Python(Selenium):如何通过登录重定向/组织登录登录网站

    我不是专业程序员 所以请原谅任何愚蠢的错误 我正在做一些研究 我正在尝试使用 Selenium 登录数据库来搜索大约 1000 个术语 我有两个问题 1 重定向到组织登录页面后如何使用 Selenium 登录 2 如何检索数据库 在我解决
  • 如何使用Conda下载python包并随后离线安装?

    我知道通过 pip 我可以使用以下命令下载 Python 包 但 pip install 破坏了我的内部包依赖关系 当我做 pip download
  • 从字符串中删除识别的日期

    作为输入 我有几个包含不同格式日期的字符串 例如 彼得在16 45 我的生日是1990年7月8日 On 7 月 11 日星期六我会回家 I use dateutil parser parse识别字符串中的日期 在下一步中 我想从字符串中删除
  • 使用 Tkinter 显示 numpy 数组中的图像

    我对 Python 缺乏经验 第一次使用 Tkinter 制作一个 UI 显示我的数字分类程序与 mnist 数据集的结果 当图像来自 numpy 数组而不是我的 PC 上的文件路径时 我有一个关于在 Tkinter 中显示图像的问题 我为
  • Python pickle:腌制对象不等于源对象

    我认为这是预期的行为 但想检查一下 也许找出原因 因为我所做的研究结果是空白 我有一个函数可以提取数据 创建自定义类的新实例 然后将其附加到列表中 该类仅包含变量 然后 我使用协议 2 作为二进制文件将该列表腌制到文件中 稍后我重新运行脚本
  • OpenCV 无法从 MacBook Pro iSight 捕获

    几天后 我无法再从 opencv 应用程序内部打开我的 iSight 相机 cap cv2 VideoCapture 0 返回 并且cap isOpened 回报true 然而 cap grab 刚刚返回false 有任何想法吗 示例代码
  • 如何在Python中获取葡萄牙语字符?

    我正在研究葡萄牙语 角色看起来很奇怪 我怎样才能解决这个问题 代码 import feedparser import random Vou definir os feeds feeds conf feedurl http pplware s
  • BeautifulSoup 中的嵌套标签 - Python

    我在网站和 stackoverflow 上查看了许多示例 但找不到解决我的问题的通用解决方案 我正在处理一个非常混乱的网站 我想抓取一些数据 标记看起来像这样 table tbody tr tr tr td td td table tr t
  • 每个 X 具有多个 Y 值的 Python 散点图

    我正在尝试使用 Python 创建一个散点图 其中包含两个 X 类别 cat1 cat2 每个类别都有多个 Y 值 如果每个 X 值的 Y 值的数量相同 我可以使用以下代码使其工作 import numpy as np import mat
  • 如何在 Python 中追加到 JSON 文件?

    我有一个 JSON 文件 其中包含 67790 1 kwh 319 4 现在我创建一个字典a dict我需要将其附加到 JSON 文件中 我尝试了这段代码 with open DATA FILENAME a as f json obj js
  • Python 类继承 - 诡异的动作

    我观察到类继承有一个奇怪的效果 对于我正在处理的项目 我正在创建一个类来充当另一个模块的类的包装器 我正在使用第 3 方 aeidon 模块 用于操作字幕文件 但问题可能不太具体 以下是您通常如何使用该模块 project aeidon P
  • Python Selenium:如何在文本文件中打印网站上的值?

    我正在尝试编写一个脚本 该脚本将从 tulsaspca org 网站获取以下 6 个值并将其打印在 txt 文件中 最终输出应该是 905 4896 7105 23194 1004 42000 放置的动物 的 HTML span class
  • 如何使用 Pycharm 安装 tkinter? [复制]

    这个问题在这里已经有答案了 I used sudo apt get install python3 6 tk而且效果很好 如果我在终端中打开 python Tkinter 就可以工作 但我无法将其安装在我的 Pycharm 项目上 pip

随机推荐

  • C#学习记录(47)MSSQL数据库

    引言 微软数据库是针对中小型企业的关系型数据库 操作简单易上手 首先介绍下C NET的数据库 以 ActiveX 数据对象 ADO 为基础 以 XML 扩展标记语言 为格式传送和接收数据 C NET应用程序 lt gt ADO NET lt
  • 特征值和特征向量的几何和物理意义

    原文 http blog 163 com renguangqian 126 blog static 1624014002011711114526759 FUCk 相见很晚 如果大学期间遇到这样的文章 线代必须90分以上 特征值和特征向量的几
  • vsCode中live server插件的安装及使用

    live server 插件是用来干嘛的 本地开发常常需要搭建临时的服务 作用 1 模拟服务器的方式打开页面 2 代码改动后 会自动刷新页面 安装 使用 1 使用要求 要求项目文件夹 Demo 要单独出现在vscode侧边栏 以下两种都可以
  • 软件设计风格(干货)-架构师之路(九)

    一 软件架构风格概念 Architecture架构 体系结构 软件体系结构风格是 描述某一特定应用领域中 系统组织方式 的惯用模式 架构风格定义一个系统家族 即 一个架构的定义 一个词汇表和一组约束 词汇表包含 一些构建和连接类型 而一组约
  • 你工作效率低,可能是因为不会Python

    前言 你是不是感觉你的工作非常无聊 每天有大量的重复性的工作要做 比如在我的工作中 就有很多类似的动作 每天早上要看我们DevOps流水线跑出的结果 查看各个微服务中的重复代码率是多少 有没有增加 CleanCode中的各项指标怎么样 代码
  • 微信加拿大服务器,微信新功能,在加拿大也可以任意刷人民币了

    原标题 微信新功能 在加拿大也可以任意刷人民币了 2018 6 11 加币 人民币 4 877 加币 美金 0 757 近日 微信悄悄上线了一项新功能 这就是 亲属卡 什么是 亲属卡 简单来说 就 是 你消费 别人买单 这项功能对于我们身在
  • 2021-01-10

    RIP 协议 一 合理分配IP地址 二 配置IP地址 三 运行RIPV 2 例R1 四 配置缺省路由 五 RIPV2 认证 例R1 六 配置空接口路由 防环 例R1 七 全网可通
  • 成员变量与局部变量的区别有哪些

    成员变量是在类内部定义的变量 在类的任何方法中都可以直接使用 其作用域为整个类 成员变量有默认值 如果没有给定初始值 数值类型默认为0 布尔类型默认为false 对象类型默认为null 局部变量是在方法 代码块 循环等内部定义的变量 其作用
  • 【羊了个羊】Burp抓取IOS微信小程序数据包

    描述 最近 小游戏 羊了个羊 在朋友圈刷屏 网友纷纷表示 游戏开发者多少有个病要治 本文记录 如何使用Burp抓取ios微信小程序数据包 工具准备 Burp 苹果手机 wifi 设置记录 手机和电脑连接同一wifi burp设置新代理 手机
  • 人脸分割 人脸解析 源码推荐

    2021年 有预训练 resnet50 126m 测试代码 python face warping test py i 0 e rtnet50 decoder fcn n 11 d cuda 0 Command line arguments
  • html js c 代码大全,js常用汇总

    javascript 代码库JS函数修改html的元素内容 及修改属性内容 document getElementById aid innerHTML World document getElementById aid href http
  • CBAM——即插即用的注意力模块(附代码)

    论文 CBAM Convolutional Block Attention Module 代码 code 目录 前言 1 什么是CBAM 1 Channel attention module CAM 2 Spatial attention
  • hexo的美化——拓展篇

    基础知识 css样式 hexo themes next source css 是next主题的样式文件 决定主题的外观 hexo themes next source css main styl 汇总css文件夹中所有的样式 hexo th
  • 一段有意思的异步代码片段

    毫不夸张的说 下面的代码会有一半的人输出错误 上代码 async function getCount id return id let count 0 async function addCount num count await getC
  • 深度学习入坑笔记之二---手写体图像识别问题

    深度学习入坑笔记之二 手写体图像识别问题 目录 前言 通过softmax进行手写体图像建模及识别 数据导入 softmax建模 训练模型 模型评估 通过卷积网络进行手写体图像建模及识别 初始化权重 定义卷积层及池化层 添加层 训练及评估模型
  • golang1.9编译openwrt运行程序 ,window7下liteide编译

    网上看了好多资料发现都很过时了 基本都是用的https github com gomini go mips32编译的 但是go1 9早就支持mips了 设置好编译参数 开始build 这时在go pkg下会出现linux mips目录 就是
  • 本地镜像发布到私有库

    情景 涉及机密的文件 公司不可能提供镜像给公网 所以需要创建一个私有仓库用于存放敏感的镜像 Docker Registry帮助我们搭建私有的仓库供团队使用 相当于一个私有的hub仓库 本地拉取registry镜像 运行私有库 相当于自己本地
  • BugkuCTF-MISC题FileStoragedat

    知识点 FileStorage是微信存储数据的一个文件夹 该文件夹下存放的是经过加密后微信里发送 接受的图片而形成的文件后缀为dat的文件 就是微信dat文件 想要做出此题 就得先弄懂微信dat文件形成的原因 微信的dat文件 将微信图片的
  • Java Elasticsearch多条件分组聚合查询

    需求 在项目开发中 需要从elasticsearch中查询日志数据 先统计每一天的日志调用量 然后在每一天的分组聚合基础上 再分组聚合统计成功和失败的日志调用量 代码 DateHistogramAggregationBuilder aggr
  • Python爬虫——多线程爬虫如何实现?

    Python爬虫 多线程爬虫 1 多任务 2 主线程与子线程 2 1 何谓线程 主线程及子线程 2 2 查看线程数量 2 3 创建子线程 2 4 线程间的通信 3 线程间的资源竞争 4 互斥锁与死锁 4 1 互斥锁 4 2 死锁 4 3 避