Python爬虫之多进程介绍

1 进程介绍

(1)概念
进程是正在执行的程序。
程序:没有执行的代码,是⼀个静态的。
1)进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。
2)多线程就是开启多个线程,每个线程之间是不会互相通信互相干扰的,适用于密集计算。
在这里插入图片描述
(2)线程和进程的对比
进程:能够完成多任务,一台电脑上可以同时运行多个QQ
线程:能够完成多任务,一个QQ中的多个聊天窗口
根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
具体我们通过下面这段代码运行,比较不同

import multiprocessing
import threading
import time

def demo1():
    while True:
        print('--1--')
        time.sleep(1)

def demo2():
    while True:
        print('--2--')
        time.sleep(1)

def main():
    # 多线程
    t1 = threading.Thread(target=demo1)
    t2 = threading.Thread(target=demo2)
    t1.start()
    t2.start()

    # # 多进程
    # p1 = multiprocessing.Process(target=demo1)
    # p2 = multiprocessing.Process(target=demo2)
    # p1.start()
    # p2.start()

if __name__ == '__main__':
    main()

任务管理器进程显示:
当用进程模式运行代码:
在这里插入图片描述
当用线程模式运行代码:
在这里插入图片描述

2 进程间的通信

2.1 进程队列使用

进程队列方法使用与进程使用方法类似,但进程提供了属于自己的模块

'''
# Queue 就是对数据结构中的栈和队列这种数据结构的封装
# 初始化Queue(maxsize):创建一个先进先出的队列。
# qsize():返回队列的大小。
# empty():判断队列是否为空。
# full():判断队列是否满了。
# get():从队列中取最后一个数据。
# put():将一个数据放到队列中。
'''
from multiprocessing import Queue # 进程的队列

q = Queue(3)
# 存数据
q.put(1)
q.put(2)
q.put(3)
q.put(4) # 堵塞
q.put_nowait(4) # queue.Full 报错
# 取值
print(q.get())
print(q.get())
print(q.get())
print(q.get()) # 堵塞
# 判断
q.empty()  # 判断队列是否为空。
q.full()  # 判断队列是否为满

2.2 进程间不共享全局变量

2个进程可以理解为2个py文件分别进行,这种情况下变量是无法共享的

import multiprocessing
import time
a = 1

def demo1():
    global a
    a += 1
    print(a)

def demo2():
    global a
    print(a)

def main():
    p1 = multiprocessing.Process(target=demo1)
    p2 = multiprocessing.Process(target=demo2)
    p1.start()
    time.sleep(1)
    p2.start()

if __name__ == '__main__':
    main()

在这里插入图片描述
结果a在demo2并没有改变,仍为1.说明进程间不共享全局变量

2.3 进程间的通信

举个例子,进程间的通信就像网易云音乐和QQ音乐两个进程,要想播放同一首音乐只能某一个程序先把这首歌下载下来,才能在另外一个播放器播放。
实现方式主要是通过数据存储在(from multiprocessing import Queue 模块进行)内部进行通信,单独的(from queue import Queue )的方式不能通信
在这里插入图片描述

'''
通过数据存储在queue内部进行通信
'''
import multiprocessing
from multiprocessing import Queue # 进程的队列
import time

# 下载数据
def download(q):
    q.put(1)
    q.put(2)
    q.put(3)
    print('------数据下载完毕-----')

# 获取数据
def getdata(q):
    print(q.get(1))
    print(q.get(2))
    print(q.get(3))
    print('------数据获取完毕-----')

def main():
    q = Queue(3)
    p1 = multiprocessing.Process(target=download,args=(q,))
    p2 = multiprocessing.Process(target=getdata,args=(q,))
    p1.start()
    time.sleep(1)
    p2.start()

if __name__ == '__main__':
    main()

# 结果
# ------数据下载完毕-----
# 1
# 2
# 3
# ------数据获取完毕-----

单独的(from queue import Queue )的方式不能通信 —— 报错

'''
单独的(from queue import Queue )的方式不能通信
'''

import multiprocessing
from queue import Queue # 进程的队列
import time
# 下载数据
def download(q):
    q.put(1)
    q.put(2)
    q.put(3)
    print('------数据下载完毕-----')

# 获取数据
def getdata(q):
    print(q.get(1))
    print(q.get(2))
    print(q.get(3))
    print('------数据获取完毕-----')

def main():
    q = Queue(3)
    p1 = multiprocessing.Process(target=download,args=(q,))
    p2 = multiprocessing.Process(target=getdata,args=(q,))
    p1.start()
    time.sleep(1)
    p2.start()

if __name__ == '__main__':
    main()

在这里插入图片描述

3 进程池间的通信

当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态生成多个进程
但是如果是上百甚至上千个目标,手动的去创建的进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法

from multiprocessing import Pool
import os, time, random

def worker(msg):
    t_start = time.time()
    print('%s开始执行,进程号为%d' % (msg, os.getpid()))

    time.sleep(random.random() * 2)
    t_stop = time.time()
    print(msg, "执行完成,耗时%0.2f" % (t_stop - t_start))

if __name__ == '__main__':
    po = Pool(3)  # 定义一个进程池
    for i in range(0, 6):
        po.apply_async(worker, (i,))  # 把进程放进进程池内

    print("--start--")
    po.close()  # 满了,关闭进程池,开始运行
    po.join()   # 子进程结束,主进程开始
    print("--end--")

'''
结果:
--start--
0开始执行,进程号为14828
1开始执行,进程号为133580
2开始执行,进程号为219592  #  进程池3个进程(进程0、进程1、进程2)开始运行
1 执行完成,耗时0.23
3开始执行,进程号为133580   # 进程1运行完毕,进程1退出,进程3占据进程1位置,开始运行
0 执行完成,耗时0.43
4开始执行,进程号为14828   # 进程0运行完毕,进程0退出,进程4占据进程1位置,开始运行
4 执行完成,耗时0.68
5开始执行,进程号为14828
2 执行完成,耗时1.12
3 执行完成,耗时0.98
5 执行完成,耗时0.65
--end--
'''
'''
队列 + 进程池间的通信
'''
import multiprocessing

def demo1(q):
    print(1)
    q.put('a')

def demo2(q):
    print(2)
    print(q.get())


if __name__ == '__main__':

    q = multiprocessing.Manager().Queue()  # 进程池之间进程间的通信
    po = multiprocessing.Pool(2)

    po.apply_async(demo1,args=(q,))   # demo1 放入进程池
    po.apply_async(demo2,args=(q,))  # demo2 放入进程池

    po.close()   # 满了,关闭进程池,开始运行
    po.join()

# 结果为:
# 1
# 2
# a
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值