【笔记】2022.5.20 多进程

1. 多进程概念

(1)一个应用程序默认只有一个进程,一个进程中默认有一个线程。多进程指的是一个应用程序有多个进程

(2)如果所有的任务是相同的任务就直接用一个进程中添加多个线程的方案来解决问题

例如:如果要加工1000个玩具:一个进程,多个线程

(3)如果所有的任务可以分成两种或多种任务,可以每一种任务对应一个进程

例如:如果要加工800个玩具和400个蛋糕:两个进程,每个进程中多个线程

(4)如果希望应用程序中除了主进程以外有别的进程(子进程),就需要在程序中创建进程对象

RIGHT Example:

from time import sleep
from multiprocessing import Process, current_process
from threading import Thread, current_thread


def func1(x, y):
    sleep(1)
    print('子进程', current_process(), current_thread())
    # 在这个函数中创建的线程就是子进程中的线程
    t2 = Thread(target=func3)
    t2.start()


def func2():
    print('func2', current_process(), current_thread())


def func3():
    print('func3', current_process(), current_thread())


if __name__ == '__main__':
    print('主进程', current_process(), current_thread())
    # 1. 创建进程对象
    p = Process(target=func1, args=(10, 20))

    # 2. 启动线程
    p.start()

    # 3. 阻塞
    p.join()
    print('----------------完成------------------')

2. 多进程数据通信


2.1 进程队列概念

不同进程中的数据不能直接共享。在一个进程中定义的全局变量不能在另外的进程中使用。如果想要让一个或者多个数据在不同进程中进行传递,只有一个方法:使用进程队列


2.2 进程队列的使用

RIGHT Example:

from threading import Thread
from multiprocessing import Process, Queue


def func2(qt: Queue):
    print('子进程:', qt.get())
    qt.put('哈哈哈')


if __name__ == '__main__':
    # (1)创建队列对象
    q = Queue()

    # (2)
    b = 100
    q.put(b)

    # (3)将队列对象以参数的形式传递到子进程对应的函数中
    p1 = Process(target=func2, args=(q,))
    p1.start()
    p1.join()

    # (4)获取数据
    print('主进程的l2:', q.get())

2.3 案例

RIGHT Example:

import requests
import os
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Process, Queue


def get_all_id():
    url = 'https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js'
    resp = requests.get(url)
    return [x['heroId'] for x in resp.json()['hero']]


def download_img(img_url, path):
    resp = requests.get(img_url)
    with open(path, 'wb') as f:
        f.write(resp.content)


def get_skins(hero_id):
    url = f'https://game.gtimg.cn/images/lol/act/img/js/hero/{hero_id}.js'
    res = requests.get(url)
    data = res.json()
    # 获取英雄名称
    hero_name = data['hero']['name']
    # 创建英雄名称对应的文件夹
    if not os.path.exists(f'所有英雄/{hero_name}'):
        os.mkdir(f'所有英雄/{hero_name}')
        print(f'{hero_name}创建成功')
    skins = data['skins']
    # 把获取到的英雄皮肤保存到队列中,传递到子进程中
    q.put(skins)


def download_one(name, skin_name, img_url):
    resp = requests.get(img_url)
    with open(f'所有英雄/{name}/{skin_name}.jpg', 'wb') as f:
        f.write(resp.content)
        print(f'----------{skin_name}-------------')


def download_skin(q: Queue):
    # 在子进程中创建线程池,同时下载多个皮肤
    pool2 = ThreadPoolExecutor(20)

    while True:
        data = q.get()
        if data == 'end':
            break
        else:
            for x in data:
                mainImg = x.get('mainImg')
                if mainImg:
                    hero_name = x['heroName']
                    skin_name = x['name']
                else:
                    continue
                pool2.submit(download_one, hero_name, skin_name, mainImg)


if __name__ == '__main__':
    # 1. 在主进程的主线程中获取所有英雄的id
    all_id = get_all_id()

    # 2. 在主进程中创建线程池获取每个英雄的信息
    pool = ThreadPoolExecutor(20)
    pool.map(get_skins, all_id)

    # 3. 创建子进程完成每个英雄的皮肤下载操作
    q = Queue()  # 传递皮肤数据
    p1 = Process(target=download_skin, args=(q,))
    p1.start()

    pool.shutdown()
    q.put('end')
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sprite.Nym

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值