并编程复习——进程

并发编程

1、并发编程

'''
操作系统的发展史

输入输出设备>>>:IO操作即(input和output)

- 手工操作穿孔卡片
- 批处理(磁带)
- 脱机批处理系统

一步步的优化,其实都是在提高计算机CPU利用率的问题(问题在于时串行并且没有空间上的复用)
'''

2、多道技术

# 多道技术的产生
'''
解决cpu在执行程序,遇到io时,不干活的情况
串行:一个程序完完整整的运行完毕,才能运行下一个程序
并发:看上去像同时运行
'''
# 多道技术:
'''
 1.空间上的复用(多个程序共一套硬件设备,它是多道技术实现时间上的复用的基础,不然还要去硬盘读数据)
 2.时间上的复用(单个cpu的电脑上,起多个应用程序。cpu快速切换,给人的感觉是同时运行)
 3.一个任务占用cpu时间过长或被操作系统强行剥夺走cpu的执行权限(比起串行效率反而降低)
 4.一个任务执行过程中遇到io操作,也会被操作系统强行剥夺走cpu的执行权限(比起串行效率提高)
'''

3、进程理论

  • 什么是进程?

    • 程序就是一堆代码

    • 进程就是正在运行的程序

      注:同一个程序打开两次就是两个进程

  • 并发与并行

    • 并发:看起来像是同时运行,单个cpu+多道技术就可以实现并发,(并行也属于并发)

    • 并行:同时运行,只有具备多个cpu才能实现并行

4、同步异步阻塞非阻塞

# 同步和异步:针对任务的提交方式
	同步:提交任务之后原地等待任务的返回结果,期间不做任何事
    异步:提交任务之后,不等待任务的返回结果,执行下一行代码
# 阻塞和非阻塞
	阻塞:遇到IO操作
    非阻塞:就绪或者运行状态

5、进程的状态

6、进程的创建方式

  • multiproces模块

    multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。

  • Process 类介绍

Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)

强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
# 参数介绍
1 group参数未使用,值始终为None
3 target表示调用对象,即子进程要执行的任务
5 args表示调用对象的位置参数元组,args=(1,2,'egon',)
7 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
9 name为子进程的名称
# 方法介绍
 1 p.start():启动进程,并调用该子进程中的p.run() 
 2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  
 4 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
 5 p.is_alive():如果p仍然运行,返回True
 7 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程 
# 属性介绍
1 p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
2 
3 p.name:进程的名称
    
5 p.pid:进程的pid
6 
7 p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
8 
9 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可
  • 创建进程的方式
# 方式1:(函数方法)
from multiprocessing import Process
import time

def task(name):
    print('%s is running' %name)
    time.sleep(3)
    print('%s is over' %name)

if __name__ == '__main__':
    p1 = Process(target=task,args=('king',))# args:是元组类型,注意
    p1.start()
    print('主')
    
# 方式2:(类方法)
from multiprocessing import Process
import time

class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name=name
    # 重写run方法
    def run(self):
        print('%s is runnig'%self.name)
        time.sleep(3)
        print('%s is over' %self.name)

if __name__ == '__main__':
    obj = MyProcess('egon')
    obj.start()
    print('主')

  • join 方法
from multiprocessing import Process
import time

def task(name,n):
    print('%s is running'%name)
    time.sleep(n)
    print('%s is over'%name)


if __name__ == '__main__':
    start_time = time.time()
    p_list = []
    for i in range(3):
        p = Process(target=task,args=('子进程%s'%i,i))
        p.start()
        p_list.append(p)
    for i in p_list:
        i.join()
    # p1 = Process(target=task,args=('egon',1))
    # p2 = Process(target=task,args=('jason',2))
    # p3 = Process(target=task,args=('kevin',3))
    # start_time = time.time()
    # p1.start()  # 千万要知道,这句话只是告诉操作系统需要进程
    # p2.start()
    # p3.start()
    # # p1.join()  # 主进程等待子进程结束 才继续运行
    # p3.join()
    # p1.join()
    # p2.join()
    print('主',time.time()-start_time)

# join的作用仅仅只是让主进程等待子进程的结束,不会影响子进程的运行
  • 守护进程
from multiprocessing import Process
import time

def task(name):
    print('%s 正活着'%name)
    time.sleep(3)
    print('%s 正常死亡'%name)


if __name__ == '__main__':
    p = Process(target=task,args=('egon总管',))
    p.daemon = True  # 必须在p.start开启进程命令之前声明
    p.start()
    print('皇帝jason正在死亡')
  • 进程之间的通讯

    进程彼此之间互相隔离,要实现进程间通信(IPC)

# 利用队列实现进程间通信
from multiprocessing import Queue
q = Queue(5)  # 产生一个最多能够存放五个数据的队列

# q.put(1)  # 往队列中存放数据,如果存放的数据个数大于队列最大存储个数,程序会阻塞
# q.put(2)
# q.put(3)
# print(q.full())
q.put(4)
# q.put(5)
# print(q.full())
# for i in range(6):
#     q.put(i)

# 存取数据
for i in range(5):
    q.put(i)  # for循环往队列里面存放数据
print(q.get())  # 取数据,get一次就取一个
print(q.get())
print(q.get())
q.get_nowait()  # 在队列有数据的情况下,跟get取值一样,当队列没有数据的情况下,取值直接报错
print(q.empty())  # 判断队列是否为空,需要注意的是,在并发的情况下,这个方法判断不准确!
print(q.get())
print(q.get())
print(q.empty())
# q.get_nowait()
# print(q.get())  # 如果队列为空,get会在原地等待队列中有数据过来
  • 生产者消费者模型
"""
生产者消费者模型
    生产者:做包子的  生产数据的
    消费者:买包子的  处理数据的

    解决供需不平衡的问题
        定义一个队列,用来存放固定数量的数据
        解决一个生产者和消费者不需直接打交道,两者都通过队列实现数据传输

    Queue:管道+锁
"""
from multiprocessing import Queue,Process,JoinableQueue
import time
import random


def producer(name,food,q):
    for i in range(5):
        data = '%s生产了%s%s'%(name,food,i)
        time.sleep(random.randint(1,3))
        print(data)
        q.put(data)  # 将生产的数据放入队列中


def consumer(name,q):
    while True:
        data = q.get()
        if data is None:break
        time.sleep(random.randint(1, 3))
        print('%s吃了%s'%(name,data))
        q.task_done()  # 告诉你的队列,你已经将数据取出并且处理完毕


if __name__ == '__main__':
    q = JoinableQueue()  # 生成一个队列对象
    p1 = Process(target=producer,args=('大厨egon','包子',q))
    p2 = Process(target=producer,args=('靓仔tank','生蚝',q))
    c1 = Process(target=consumer,args=('吃货owen',q))
    c2 = Process(target=consumer,args=('坑货kevin',q))
    p1.start()
    p2.start()
    c1.daemon = True
    c2.daemon = True
    c1.start()
    c2.start()
    # 等待生产者生产完所有的数据
    p1.join()
    p2.join()
    # 在生产者生产完数据之后,往队列里面放一个提示性的消息,告诉消费者已经没有数据,你走吧,不要等了
    # q.put(None)
    # q.put(None)
    q.join()  # 等待队列中数据全部取出
    print('主')


原文地址:https://www.cnblogs.com/king-home/p/10896526.html