【愚公系列】《Python网络爬虫从入门到精通》024-多进程和创建进程的常用方式

举报
愚公搬代码 发表于 2025/05/01 00:06:30 2025/05/01
【摘要】 标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度博客之星TOP2,2023年度博客之星TOP2,2022年华为云十佳博主,2023年华为云十佳博主,2024年华为云十佳...
标题 详情
作者简介 愚公搬代码
头衔 华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。
近期荣誉 2022年度博客之星TOP2,2023年度博客之星TOP2,2022年华为云十佳博主,2023年华为云十佳博主,2024年华为云十佳博主等。
博客内容 .NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
欢迎 👍点赞、✍评论、⭐收藏

🚀前言

在如今这个数据驱动的时代,网络爬虫已成为获取信息的重要工具。然而,当面对复杂的网站结构和庞大的数据量时,传统的单进程爬虫往往难以满足迅速、高效的数据采集需求。为了解决这一问题,多进程爬虫应运而生,它通过并行处理来显著提升爬虫的性能,让我们能够更快地获取所需的信息。

在本期文章中,我们将深入探讨多进程爬虫的基本原理、实现方式以及在实际应用中的优势与挑战。我们将介绍如何利用Python等编程语言,搭建高效的多进程爬虫系统,帮助您在数据采集的过程中事半功倍

🚀一、多进程和创建进程的常用方式

🔎1.什么是进程

在了解进程之前,我们首先需要了解多任务的概念。多任务,顾名思义,就是指操作系统能够同时执行多个任务。例如,使用 Windows 或 Linux 操作系统时,你可以同时进行看电影、聊天、查看网页等操作。此时,操作系统在执行多个任务,而每个任务就是一个进程

你可以通过打开 Windows 的任务管理器来查看当前操作系统正在执行的进程,图11.8中就显示了这些进程。图中的进程不仅包括各种应用程序(如 QQ、谷歌浏览器等),还包括系统进程。

进程与程序的区别

进程(process)是计算机中已经在运行的程序的实体。它是程序(包括指令和数据)的真正运行实例,而程序本身仅仅是指令、数据及其组织形式的描述,并不具备实际运行功能。

例如,当你没有打开 QQ 时,QQ 只是一个程序。它的代码和数据只是存在磁盘上,还没有被操作系统加载到内存中并执行。但是,当你打开 QQ 时,操作系统为其分配了资源,并启动了一个新的进程来执行 QQ 程序。此时,QQ就成了一个进程。

此外,如果你再打开一个 QQ,操作系统将为第二个 QQ 创建一个新的进程。所以,即便是同一个程序,运行的多个实例也会分别拥有各自独立的进程。图11.9展示了这种情况。

在这里插入图片描述在这里插入图片描述

🔎2.创建进程的常用方式

Python中创建进程的常用模块包括:

  • os.fork():仅适用于UNIX/Linux/Mac系统,不兼容Windows。
  • multiprocessing模块:跨平台支持,适用于复杂进程管理。
  • Pool进程池:跨平台,适合批量创建进程任务。

本文重点介绍 multiprocessing模块和 Pool进程池。

🦋2.1 使用multiprocessing.Process类创建进程

multiprocessing模块提供Process类表示进程对象。

语法与参数

Process(group=None, target=None, name=None, args=(), kwargs={})
  • 参数说明:
    • group: 保留参数,始终为None
    • target: 进程启动时调用的可执行对象(函数)。
    • name: 进程别名(默认Process-N,N从1递增)。
    • args: 传递给target的位置参数元组。
    • kwargs: 传递给target的关键字参数字典。

基础示例

from multiprocessing import Process

def test(interval):
    print("我是子进程")

if __name__ == '__main__':
    print("主进程开始")
    p = Process(target=test, args=(1,))  # 实例化进程
    p.start()  # 启动子进程
    print("主进程结束")

运行结果 在这里插入图片描述

注意事项

  • 在IDLE中运行可能不显示子进程输出,建议使用命令行执行:python 文件名.py

☀️2.1.1 Process类常用方法

方法 说明
start() 启动子进程
is_alive() 判断进程是否在运行
join([timeout]) 等待进程结束(可设置超时时间)
terminate() 强制终止进程
run() 若未指定target,调用此方法执行逻辑

☀️2.1.2 Process类常用属性

属性 说明
name 进程别名(默认Process-N
pid 进程的PID值

☀️2.1.3 示例:Process类方法和属性演示

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

#两个子进程将会调用的两个方法
def  child_1(interval):
    print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid()))
    t_start = time.time()   # 计时开始
    time.sleep(interval)    # 程序将会被挂起interval秒
    t_end = time.time()     # 计时结束
    print("子进程(%s)执行时间为'%0.2f'秒"%(os.getpid(),t_end - t_start))

def  child_2(interval):
    print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid()))
    t_start = time.time()   # 计时开始
    time.sleep(interval)    # 程序将会被挂起interval秒
    t_end = time.time()     # 计时结束
    print("子进程(%s)执行时间为'%0.2f'秒"%(os.getpid(),t_end - t_start))

if __name__ == '__main__':
    print("------父进程开始执行-------")
    print("父进程PID:%s" % os.getpid())                  # 输出当前程序的ID
    p1=Process(target=child_1,args=(1,))                    # 实例化进程p1
    p2=Process(target=child_2,name="mrsoft",args=(2,))     # 实例化进程p2
    p1.start()  # 启动进程p1
    p2.start()  # 启动进程p2
    #同时父进程仍然往下执行,如果p2进程还在执行,将会返回True
    print("p1.is_alive=%s"%p1.is_alive())
    print("p2.is_alive=%s"%p2.is_alive())
    #输出p1和p2进程的别名和PID
    print("p1.name=%s"%p1.name)
    print("p1.pid=%s"%p1.pid)
    print("p2.name=%s"%p2.name)
    print("p2.pid=%s"%p2.pid)
    print("------等待子进程-------")
    p1.join() # 等待p1进程结束
    p2.join() # 等待p2进程结束
    print("------父进程执行结束-------")
在这里插入图片描述在这里插入图片描述

运行结果 在这里插入图片描述

🦋2.2 继承Process子类创建进程

通过自定义类继承Process类,重写run()方法实现复杂任务。

示例:子类化Process

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

#继承Process类
class SubProcess(Process):
    # 由于Process类本身也有__init__初识化方法,这个子类相当于重写了父类的这个方法
    def __init__(self,interval,name=''):
        Process.__init__(self)     # 调用Process父类的初始化方法
        self.interval = interval   # 接收参数interval
        if name:                   # 判断传递的参数name是否存在
            self.name = name    # 如果传递参数name,则为子进程创建name属性,否则使用默认属性
    #重写了Process类的run()方法
    def run(self):
        print("子进程(%s) 开始执行,父进程为(%s)"%(os.getpid(),os.getppid()))
        t_start = time.time()
        time.sleep(self.interval)
        t_stop = time.time()
        print("子进程(%s)执行结束,耗时%0.2f秒"%(os.getpid(),t_stop-t_start))

if __name__=="__main__":
    print("------父进程开始执行-------")
    print("父进程PID:%s" % os.getpid())                  # 输出当前程序的ID
    p1 = SubProcess(interval=1,name='mrsoft')
    p2 = SubProcess(interval=2)
    #对一个不包含target属性的Process类执行start()方法,就会运行这个类中的run()方法,
    #所以这里会执行p1.run()
    p1.start()  # 启动进程p1
    p2.start()  # 启动进程p2
    # 输出p1和p2进程的执行状态,如果真正进行,返回True,否则返回False
    print("p1.is_alive=%s"%p1.is_alive())
    print("p2.is_alive=%s"%p2.is_alive())
    #输出p1和p2进程的别名和PID
    print("p1.name=%s"%p1.name)
    print("p1.pid=%s"%p1.pid)
    print("p2.name=%s"%p2.name)
    print("p2.pid=%s"%p2.pid)
    print("------等待子进程-------")
    p1.join() # 等待p1进程结束
    p2.join() # 等待p2进程结束
    print("------父进程执行结束-------")
在这里插入图片描述在这里插入图片描述

关键点

  • 必须调用super().__init__()以确保父类初始化。
  • start()方法会自动调用子类的run()方法。

🦋2.3 使用进程池Pool创建进程

Pool类用于管理多个进程,适合批量任务处理。

Pool类核心方法

方法 说明
apply_async(func, args, kwds) 非阻塞方式并行执行任务
apply(func, args, kwds) 阻塞方式顺序执行任务
close() 关闭进程池,禁止添加新任务
join() 等待所有子进程结束(需在close()后调用)

示例:进程池使用

# -*- coding=utf-8 -*-
from multiprocessing import Pool
import os, time

def task(name):
    print('子进程(%s)执行task %s ...' % ( os.getpid() ,name))
    time.sleep(1)       # 休眠1秒

if __name__=='__main__':
    print('父进程(%s).' % os.getpid())
    p = Pool(3)                    # 定义一个进程池,最大进程数3
    for i in range(10):                 # 从0开始循环10次
        p.apply_async(task, args=(i,))  # 使用非阻塞方式调用task()函数
    print('等待所有子进程结束...')
    p.close()   # 关闭进程池,关闭后p不再接收新的请求
    p.join()    # 等待子进程结束
    print('所有子进程结束.')

运行结果 在这里插入图片描述

🦋2.4 总结

  • Process类:适合少量进程的精确控制。
  • 子类化Process:适合复杂任务封装。
  • Pool进程池:适合批量任务的高效并发处理。

通过灵活选择不同方式,可应对多进程编程中的各类场景。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。