并发编程之进程

首先,我们呢需要了解什么是进程呢?

并发编程之进程

狭义:进程就是正在进行的程序

广义:是操作系统分配的基本单位

程序:是一个没有生命的实体,等待处理器赋予生命,一旦程序有了生命就变成进程了。

程序和进程的区别:

1、程序是指令和数据的有序集合,其本身没有任何含义,是一个静态的资源。

     进程是程序在系统中的一次执行过程。

2、程序可以作为软件长期存在,进程是有一定的生命周期的。

进程三状态:

就绪态:运行的条件都已经满足,正在等待CPU执行
执行态:CPU正在执行器功能
等待态:等待某些条件满足

有了对进程的初步了解,那么怎样创建一个进程呢?

import time
# 导包
import multiprocessing
def test1():
    while True:
        print("大*")
        time.sleep(1)
def test2():
    while True:
        print("小胖手")
        time.sleep(1)
# 定义一个主函数来分别执行2个进程的代码
def main():
    # 分别创建test1、test2  2个进程 target的值代表要执行的进程
    p1 = multiprocessing.Process(target=test1)
    p2 = multiprocessing.Process(target=test2)
    # 启动p1和p2
    p1.start()
    p2.start()
# 程序入口 常规写法:
if __name__ == "__main__":
    main()

 在这里,我们引入一个概念,并行与并发

我们举个例子,比如我们两个人在吃午饭。你在吃饭的整个过程中,吃了米饭、吃了蔬菜、吃了牛肉。吃米饭、吃蔬菜、吃牛肉这三件事其实就是并发执行的。对于你来说,整个过程中看似是同时完成的的。但其实你是在吃不同的东西之间来回切换的。

还是我们两个人吃午饭。在吃饭过程中,你吃了米饭、蔬菜、牛肉。我也吃了米饭、蔬菜和牛肉。我们两个人之间的吃饭就是并行的。两个人之间可以在同一时间点一起吃牛肉,或者一个吃牛肉,一个吃蔬菜。之间是互不影响的。

看到这里,是不是还是有点迷茫呢?我们再来看一张图,直观感受一下两者的区别

并发编程之进程

 以上可以看出,

        并行:同一时刻,多个任务同时执行 

        并发:同一时间,多个任务同时执行 

并行与并发的区别:

        微观上:并行是指同一时间点上,多个任务真正同时执行

        宏观上:并发是指在一个时间段内,多个任务走走停停

有进程,当然就有子进程,我们代码实现一下吧!

# 导包
# import time
# from multiprocessing import Process
# 创建函数--子进程
def work1():
    while True:
        print("我是子进程嘻嘻嘻")
        time.sleep(1)
# 程序入口
if __name__ == "__main__":
    # 创建子进程对象
    p1 = Process(target=work1)
    # 启动
    p1.start()
    while True:
        print("我是主进程,哈哈哈")
        time.sleep(1)
深入了解process
参数说明:
target:如果传递了函数的引用,就可以认为要执行该子进程的代码
args:给target指定的函数传递参数,参数以元组的形式传递,如果元组中只有一个值,需要加逗号
kwargs:给target指定的函数传递参数,参数以字典的形式传递
name:给进程起名字
group:指定进程组
import time
from multiprocessing import Process
# 创建函数--子进程
def work1(*args,**kwargs):
    while True:
        print(args)
        print(kwargs)
        time.sleep(1)
# 程序入口
if __name__ == "__main__":
    # 创建子进程对象
    p1 = Process(target=work1,args=("大木",19),kwargs={"性别":"男"})
    # 启动
    p1.start()
    while True:
        print("大木二货,哈哈哈")
        time.sleep(1)
说明:1、右键run的时候就会创建一个进程,这个进程就称为主进程
      2、在程序中创建的work1为子进程
      3、创建进程和启动进程时需要使用target参数和start()方法
      4、根据题意来判断需不需要在process里传args和kwargs参数
注意:必须写程序入口
Process创建实例对象的常用方法:
start:启动子进程
terminate:不管认为是否完成,立即终止子进程
join([timeout]):是否等待子进程结束之后,再执行主进程,或等待多少秒
is_alive:判断子进程是否还活着

Process创建实例对象的常用属性:
name:进程名字
pid:进程的id--pid

multiprocessing是一个模块

现在我们已经基本了解了进程,那么进程间是如何实现通信的呢?

# 进程间数据的隔离性
# 定义一个全局变量 列表
lst = [11,22]
# 导包
import multiprocessing
import time
# 第一个进程 向列表中添加数据
def work1():
    for i in range(3):
        lst.append(i)
        time.sleep(1)
        print(lst)
# 第二个进程对列表不做任何改变
def work2():
    print(lst)
# 程序入口
if __name__ == '__main__':
    p1 = multiprocessing.Process(target=work1)
    p1.start()
# join([timeout]):是否等待子进程结束之后,再执行主进程,或等待多少秒
    # 让p1这个进程执行完再执行p2
    p1.join()
    p2 = multiprocessing.Process(target=work2)
    p2.start()

# 输出结果:[11, 22, 0]
        # [11, 22, 0, 1]
       # [11, 22, 0, 1, 2]  进程1操作之后的结果
        # [11, 22]          进程2操作之后的结果
# 总结:进程间数据具有隔离性,进程之间不能共享全局变量
队列:一种数据结构
特点:先进先出
当存满数据再次存储会出现阻塞的状况
当数据已经全部取完,再继续取数据也会出现阻塞
import multiprocessing
ret = multiprocessing.Queue(3) #该队列有3个值
#存数据  put
ret.put(11)
ret.put("22")
ret.put({"小明":"白白胖胖"})
# 检测是否为满
# print(ret.full())
# 检测是否为空
# print(ret.empty())
# 取数据 get
print(ret.get())  #11
print(ret.get())  #22
print(ret.get())  #[11,22]
# print(ret.get())  #阻塞
# get_nowait以异常的方式告诉我们已经取完数据了
print(ret.get_nowait())

接下来,我们一起了解一下进程池!

进程池:需要创建多个进程比如成千上万个进程时,如果使用Process手动创建非常费时间

同步与异步:是提交任务的两种方式

同步:提交任务后在原地进行等待,直到任务运行完毕拿到任务的返回值才进行下一行代码

异步:提交完代码不在原地等待直接进行下一次

阻塞与非阻塞:

阻塞:程序一旦发生阻塞就会停在原地,并且立刻释放CPU资源

非阻塞:即使遇到I/O阻塞,也不会停在原地

# 定义一个池子,池子里有固定的进程数,有需求来了,
# 再进程池中加一个任务,如果任务满了则需等待
import multiprocessing
import os
import time
# 创建进程
def func(data):
    print("进程%s--打印传入的参数%s" %(os.getpid(),data))
    time.sleep(1)
# 程序入口:
if __name__ == '__main__':
    # 创建进程池 参数代表最大进程数
    po = multiprocessing.Pool(3)
    for i in range(10):
        # po.apply(func,args=(i,))
        po.apply_async(func,args=(i,))
    print("我是主进程")
    po.close()
    po.join()
apply和apply_async提交方式的区别:
apply:同步提交  按顺序执行
apply_async:异步提交  任务都是异步

今天,我们一起学习了进程、子进程、进程间的通信以及进程池,下节我们继续学习线程,拜拜!

并发编程之进程

 

上一篇:想让你的Python编程健步如飞,只需掌握这六大技巧!


下一篇:关于multiprocessing中的logging的数据打印到本地失败或重复问题