• 并编程复习——进程


    并发编程

    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('主')
    
    
    
  • 相关阅读:
    C++顺序性容器、关联性容器与容器适配器
    Groovy与Java集成常见的坑--转
    selenium打开chrome浏览器代码
    分组密码的工作模式--wiki
    linux下C语言多线程编程实例
    C语言多线程pthread库相关函数说明
    C语言使用pthread多线程编程(windows系统)二
    C语言使用pthread多线程编程(windows系统)一
    使用_beginThreadex创建多线程(C语言版多线程)
    浅谈C语言中的联合体
  • 原文地址:https://www.cnblogs.com/king-home/p/10896526.html
Copyright © 2020-2023  润新知