Python网络编程 —— 进程

进程

进程:通俗理解就是一个运行的程序或者软件,进程是操作系统资源分配的基本单位

一个程序至少有一个进程,一个进程至少有一个线程,多进程可以完成多任务

进程的状态

工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态

进程的使用

导入进程模块:

import multiprocessing

用进程完成多任务

import multiprocessing
import time


def sing():
    for i in range(10):
        print("唱歌中...")
        time.sleep(0.2)

def dance():
    for i in range(10):
        print("跳舞中...")
        time.sleep(0.2)

if __name__ == "__main__":
    # 创建对应的子进程执行对应的任务
    sing_process = multiprocessing.Process(target=sing)
    dance_process = multiprocessing.Process(target=dance)

    # 启动进程执行对应的任务
    sing_process.start()
    dance_process.start()

Process类参数介绍
import multiprocessing
import os


def show_info(name,age):
    print("show_info:", multiprocessing.current_process())

    # 获取进程的编号
    pritn("show_info pid:", multiprocessing.current_process().pid, os.getpid)
    print(name, age)

if __name__ == "__main__":
    # 创建子进程
    # group: 进程组,目前只能使用None
    # target: 执行的目标任务
    # args: 以元组方式传参
    # kwargs: 以字典方式传参
    sub_prcess = multiprocessing.Process(group=None, target=show_info, arg=("杨幂", 18))
    sub_prcess.start()

进程之间不共享全局变量
import multiprocessing
import time


# 全局变量
g_list = []

# 添加数据
def add_data():
    for i in range(15):
        g_list.append(i)
        time.sleep(0.1)
    print("add_data:", g_list)

# 读取数据
def read_data():
    print("read_data:", g_list)

if __name__ == "__main__":
    # 创建添加数据的子进程
    add_process = multiprocessing.Process(target=add_data)
    # 创建读取数据的子进程
    read_process = multiprocessing.Process(target=read_data)

    # 启动进程
    add_process.start()
    # 主进程等待添加数据的子进程执行完成以后再执行读取进程的操作
    add_process.join()
    # 代码执行到此说明添加数据的子进程把任务执行完成了
    read_process.start()

创建子进程其实就是对主进程资源的拷贝

主进程会等待所有的子进程执行完成程序再退出

import multiprocessing
import time


# 工作任务
def work():
    for i in range(10):
        print("工作中...")
        time.sleep(0.3)

if __name__ == "__main__":
    # 创建子进程
    sub_prcess = multiprocessing.Process(target=work)
    # 查看进程的守护状态
    # print(sub_prcess.daemon)
    # 守护主进程,主进程退出子进程直接销毁,不再执行子进程里面的代码
    # sub_prcess.daemon = True
    # 启动进程执行对应的任务
    sub_process.start()

    # 主进程延时1s
    time.sleep(1)
    print("主进程执行完了")
    # 主进程退出之前把所有的子进程销毁
    sub_prcess.terminate()
    exit()

总结: 主进程会等待所有的子进程执行完成程序再退出

获取进程pid
# 获取进程pid
import multiprocessing
import time
import os


def work():
    # 获取当前进程编号
    print("work进程编号:", os.getpid())
    # 获取父进程编号
    print("work父进程编号:", os.getppid())

    for i in range(10):
        print("工作中...")
        time.sleep(1)
        # 扩展:根据进程编号杀死对应的进程
        # os.kill(os.getpid(), 9)

if __name__ == '__main__':
    # 获取当前进程的编号:
    print("当前进程编号:", multiprocessing.current_process().pid)

    # 创建子进程
    sub_process = multiprocessing.Process(target=work)
    # 启动进程
    sub_process.start()


    # 主进程执行打印信息操作
    for i in range(20):
        print("我在主进程中执行...")
        time.sleep(1)
运行结果:

当前进程编号: 624
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
work进程编号: 1312
work父进程编号: 624
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...
我在主进程中执行...

***Repl Closed***
进程间通信——Queue

可以使用multiprocessing模块Queue实现多进程之间的数据传递,Queue本身是一个消息队列程序

import multiprocessing


if __name__ == "__main__":
    # 创建消息队列
    # 3:表示消息队列的最大个数
    queue = multiprocessing.Queue(3)
    # 存放数据
    queue.put(1)
    queue.put("hello")
    queue.put([1, 5, 8])
    # 总结:队列可以放入任意类型的数据

    # queue.put("xxx": "yyy")
    # 放入消息的时候不会进行等待,如果发现队列满了不能放入数据,那么会直接崩溃
    # 建议: 放入数据统一使用 put 方法
    # queue.put_nowait(("xxx": "yyy"))

    # 判断队列是否满了
    result = queue.full()
    print(result)
    # 判断队列是否为空,不靠谱(加延时可解决)
    result = queue.empty()
    print("队列是否为空:", result)

    # 获取队列消息个数
    size = queue.qsize()
    print("消息个数:", size)
    # 获取队列中的数据
    res = queue.get()
    print(res)
    # 如果队列空了,那么使用get方法会等待队列有消息以后再取值

消息队列Queue完成进程间通信的演练

import multiprocessing
import time


# 添加数据
def add_data(queue):
    for i in range(5):
        # 判断队列是否满了
        if queue.full():
            # 如果满了跳出循环,不再添加数据
            print("队列满了")
            break
        queue.put(i)
        print("add:", i)
        time.sleep(0.1)

def read_data(queue):
    while True:

        if queue.qsize == 0:
            print("队列空了")
            break

        result = queue.get()
        print("read:", result)


if __name__ == "__main__":
    # 创建消息队列
    queue = multiprocessing.Queue(3)

    # 创建添加数据的子进程
    add_process = multiprocessing.Process(target=add_data, args=(queue,))

    # 创建读取数据的子进程
    read_process = multiprocessing.Process(target=read_data, args=(queue,))

    # 启动进程
    add_process.start()
    # 主进程等待写入进程执行完成以后代码再继续往下执行
    add_process.join()
    read_process.start()
进程池Pool
进程池的概念

池子里面放的是进程,进程池会根据任务执行情况自动创建进程,而且尽量少创建进程,合理利用进程池中的进程完成多任务

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

初始化Pool时,可以指定一个最大进程数,当有新的请求提到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求,但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务。

进程池同步执行任务

进程池同步执行任务表示进程池中的进程在执行任务的时候一个执行完成另外一个才能执行,如果没有执行完会等待上一个进程执行

进程池同步实例代码

import multiprocessing
import time


# 拷贝任务
def work():
    print("复制中...", multiprocessing.current_process().pid)
    time.sleep(1)

if __name__ == '__main__':
    # 创建进程池
    #3:进程池中进程的最大个数
    pool = multiprocessing.Pool(3)
    # 模拟大批量的任务,让进程池去执行
    for i in range(5):
        # 循环让进程池执行对应的work任务
        # 同步执行任务,一个任务执行完成以后另外一个任务才能执行
        pool.apply(work)
运行结果:

复制中... 6172
复制中... 972
复制中... 972
复制中... 1624
复制中... 1624

***Repl Closed***
进程池异步执行任务

进程池异步执行任务表示进程池中的进程同时执行任务,进程之间不会等待

进程池异步实例代码

import multiprocessing
import time


# 拷贝任务
def work():
    print("复制中...", multiprocessing.current_process().pid)

    # 获取当前进程的守护状态
    # 提示:使用进程池创建的进程时守护主进程的状态,默认自己通过Process创建的进程是不守护主进程的状态
    # print(multiprocessing.current_process().daemon)
    time.sleep(1)

if __name__ == '__main__':
    # 创建进程池
    # 3:进程池中进程的最大个数
    pool = multiprocessing.Pool(3)
    # 模拟大批量的任务,让进程池去执行
    for i in range(5):
        # 循环让进程池执行对应的work任务
        # 同步执行任务,一个任务执行完成以后另外一个任务才能执行
        # pool.apply(work)
        # 异步执行,任务执行不会等待,多个任务一起执行
        pool.apply_async(work)

    # 关闭进程池,意思告诉主进程以后不会有新的任务添加进来
    pool.close()
    # 主进程等待进程池执行完成以后程序再退出
    pool.join()
运行结果:

复制中... 1848
复制中... 12684
复制中... 12684
复制中... 6836
复制中... 6836

***Repl Closed***

个人独立博客:www.limiao.tech
微信公众号:TechBoard


Leave a Comment