zoukankan      html  css  js  c++  java
  • 进程

    首先,什么是进程:进程就是正在运行的程序,或程序的运行过程,这是一个高度总结的概念。

    串行:一个程序完完整整的运行完毕,然后运行下一个程序。           #记住是完完整整的运行完毕

    并发:并发其实就是我们人眼看起来是同时运行的。  #单核计算机可以实现并发,利用cpu的多道技术

    并行:就是同一时间,运行着多个进程      #并行只有在多个cpu的计算机,才可以实现。

    开启子进程的两种方式

    方式一:
    
    from multiprocessing import Process
    
    def task(n):
    
      print(n)
    
    if __name__ == '__main__':
    
      p1 = Process(target = task,args(5,))       #记住args后面跟着是元组,如果只有一个参数的话,记得加个逗号
    
      p1.start()           #这里只是向操作系统发出一个启动一个进程的请求,并不是立马就造出一个进程
    
    方式二:
    
    from multiprocessing import Process
    
    class Myprocess(Process)          #记得要继承Process
    
      def run(self):    #这里必须是 run,名字不能改
    
        pass
    
    if __name__ == '__main__':
    
      p1 = Myprocess()
      p1.start()        #相当于是p1.run()

    孤儿进程和僵尸进程

    当运行父程序,产生一系列的子进程,即使父进程的代码运行完毕,父进程也不会结束,他会等待产生的子进程全部运行完毕,统一回收子进程的僵 尸状态,然后再运行完毕。

      僵尸进程是指:子进程运行完毕后,之后把其占用的内存空间释放掉,但是会留下其pid号和占用使用内存的时间等数据,pid便于父进程去查看子 进程的运行状态,等着全部子进程运行完毕后,统一回收其僵尸状态。

      孤儿进程是指:假如子进程没有运行完毕,其父进程被意外终止掉了,这样的话,这些子进程运行完毕后,就会变成孤儿进程。其实孤儿进程和僵尸 进程的差别就是一个是有父进程,另一个是没有孤儿进程的。孤儿进程最终也会操作系统回收掉。

    总结:孤儿进程是无害的,因为它最终会有人给他回收资源。

         僵尸进程大部分情况也是无害的,因为他有他的父进程去回收其资源。但是如果内存中有大量的僵尸进程没有被清理,很有可能就是它的父进程一直 在运行,一直在产生没有意义的子进程,这样的会占用内存中的pid号,导致有软件不能打开。这种情况杀死僵尸进程是没有太大意义的,我们需要 去杀死掉其父进程,这样僵尸进程变成孤儿进程,自然会有人清理这些孤儿进程。

    守护进程:

      1 守护进程相等于也是一个’子进程‘,是由父进程产生。

      2 守护表示伴随的意思,当父进程运行完其代码后,就会跟着父进程一起完毕,不管其守护进程代码到底运行完了没有。

      3 守护进程中不能再开一个子进程。

    from multiprocessing import Process
    import time
    
    def task():
        time.sleep(1)
        print('我是守护进程')
    
    
    def fbb():
    
        print('我是子进程')
    
    
    if __name__ == '__main__':
        p1 = Process(target=fbb)
        p2 = Process(target=task)
        p2.daemon = True      #daemon 默认的是False,想要他变成守护进程,把daemon设置成True,必须在向操作系统发出建立新进程请去之前设置
    
        p1.start()
        p2.start()
    
        p1.join()   #p1子进程运行完毕才会父程序的下一行代码
        print('父进程')
    守护进程代码
    from multiprocessing import Process
    import time, os, random
    
    
    def task():
        print('%s is running..............' % os.getpid())  # 通过os模块的功能能查看到当前进程的pid号  os.getpid()
        time.sleep(random.randint(1, 3))                    # 查看父进程的pid号  os.getppid()
        print('%s is done ................' % os.getpid())
    
    
    if __name__ == '__main__':
        p1 = Process(target=task)
        p1.start()
        print(p1.pid)   # 在p1发出start()请求的时候,操作系统就给p1的pid给了一个id号,pid相对于p1的一个数据属性
        p1.join()       # p1子进程运行完毕,操作系统就就回收了p1子程序在操作系统上的pid,所以说通过tasklist并不能查找到该pid的程序
        print(p1.pid)   # 这条命令会打印出p1的pid号,这是p1的一个数据属性,就算操作系统回收了操作系统上的pid,但是p1的pid属性是不会发送变化的,但是p1这个属性是没有意义的
    
    
        print('父程序')
    查看pid
    # from multiprocessing import Process
    # import time, os,random
    #
    #
    # def task():
    #     print('%s is running..............' % os.getpid())
    #     time.sleep(random.randint(1,3))
    #     print('%s is done ................' % os.getpid())
    #
    #
    # if __name__ == '__main__':
    #     p1 = Process(target=task)
    #     p2 = Process(target=task)
    #     p3 = Process(target=task)
    #
    #     p1.start()     #start()是向操作系统发出新建一个进程的请求,并不是马上就造出一个进程,什么时候是操作说的算的
    #     p2.start()
    #     p3.start()
    #
    #     p1.join()      #p1,p2,p3是同时的运行的,等待的是父程序,p2,p3并不用等待
    #     p2.join()
    #     p3.join()
    #
    #
    #
    #     print('父进程')
    
    
    
    # # 利用for循环去除重复的代码
    # from multiprocessing import Process
    # import time, os,random
    #
    #
    # def task():
    #     print('%s is running..............' % os.getpid())
    #     time.sleep(random.randint(1,5))
    #     print('%s is done ................' % os.getpid())
    #
    #
    # if __name__ == '__main__':
    #     l = []
    #     for i in range(10):
    #         p = Process(target=task)
    #         l.append(p)
    #         p.start()
    #         print(p.pid)
    #     for a in l:
    #         a.join()
    #
    #
    #
    #     print('父进程')
    #
    #
    # #   p.join() 是让父程序在那里等待p子程序运行完毕后,才开始执行下一行代码,并且回收p子程序的僵尸状态
    join方法
    # from multiprocessing import Process, Lock
    # import os, json, time, random
    #
    #
    # def select():
    #     time.sleep(random.randint(1, 3))
    #     with open('a.txt', 'r', encoding='utf-8') as f:
    #         dic = json.load(f)
    #     print('%s 查看余票 %s' % (os.getpid(), dic['count']))
    #
    #
    # def buy():
    #     with open('a.txt', 'r', encoding='utf-8') as f:
    #         dic = json.load(f)
    #     time.sleep(random.randint(1, 2))
    #     if dic['count'] > 0:
    #         dic['count'] -= 1
    #         with open('a.txt', 'w', encoding='utf-8') as f:
    #             json.dump(dic, f)
    #         print('%s 购票成功' % os.getpid())
    #
    #     else:
    #         print('%s 购票失败' % os.getpid())
    #
    #
    # def task(mutex):
    #     select()
    #
    #     mutex.acquire()
    #     buy()
    #     mutex.release()
    #
    #
    # if __name__ == '__main__':
    #     mutex = Lock()
    #     for i in range(10):
    #         p = Process(target=task,args=(mutex,))
    #         p.start()
    
    # 写一个买票的小程序
    from multiprocessing import Process,Lock
    import json, os, time, random
    
    
    def select():  # 查看余票
        time.sleep(random.randint(1, 3))
        with open('a.txt', 'r', encoding='utf-8') as f:
            dic = json.load(f)
    
        print('%s 查看剩余票为:%s' % (os.getpid(), dic['count']))
    
    
    def buy():  # 购票
        with open('a.txt', 'r', encoding='utf-8') as f:
            dic = json.load(f)
        time.sleep(random.randint(1, 3))
        if dic['count'] > 0:
            dic['count'] -= 1
            with open('a.txt', 'w', encoding='utf-8') as f:
                json.dump(dic, f)
            print('%s 购票成功' % os.getpid())
        else:
            print('%s 购买失败,票卖完了' % os.getpid())
    
    
    # def task():
    #     select()
    #     buy()
    #
    #
    # if __name__ == '__main__':
    #     for i in range(10):    #模拟10个人进行买票的过程
    #         p = Process(target=task)
    #         p.start()
    
    # 分析 如果多进程去执行task()这个买票的过程,那么其中查看余票和买票的环节都是并发执行的,在查看余票环节用并发实行是没有问题,但是在购票环节  呢,我们看到是一张卖给了五个人,这样是完全违背现实生活的。
    # 总结一点:我们对数据的查看操作是完全可用并发去执行,但是对一个数据进行修改时,不能用用并发执行,这样数据就会变得混乱。所以对数据进行篡改操作 必须要一个人改完后,另外一个才可以去进行修改。相对于串行吧。
    
    
    #解决上面的问题multiprocessing 里面有一个LOCk的类,可以让某一段代码只能用串行去执行,这样保证了数据的安全性
    
    def task(lock):
    
        select()
    
        lock.acquire()   #开启互斥锁
        buy()
        lock.release()   #关闭互斥锁    开启互斥锁后,必须要关闭  buy()必须串行执行
                         #互斥锁一个非常谨慎,开发项目中用的时候要谨慎
    if __name__ == '__main__':
        lock = Lock()    #创建一个锁的对象
        for i in range(10):
            p = Process(target=task,args=(lock,))      #args 后面必须时元组形式
            p.start()
    互斥锁
    # 进程间通信(IPC)的两种方式:
    #         1 PIPE(管道)
    #         2 Queue(管道 + 互斥锁)   队列
    
    
    from multiprocessing import Queue
    
    q = Queue()  # Queue()里面可以规定队列可以装多少个数据   使用队列一般放小一些的数据
    
    q.get()  # 在队列中取一个 block=True, timeout=None   锁是默认开启的,阻塞的时间也没有限制  如果q里面没有值,会报错
    q.put('first')  # 在队列中放一个 block=True, timeout=None   锁是默认开启的,阻塞的时间也没有限制  如果q里面放满了,会报错
    
    # 队列:先进先出
    进程之间的通信
    # 生产者消费者模型:
    #         生产者:在程序中表示产生数据的任务
    #         消费者:在程序中表示处理数据的任务
    
    #         生产者————>(某种中间介质:队列)<————消费者
    #         生产者消费者模型:平衡生产者与消费者之间的工作能力,从而提高程序整体处理数据的速度
    
    
    # 例子1:
    # from multiprocessing import Process, Queue
    # import time, random
    #
    #
    # def producers(name, food, q):
    #     for i in range(4):
    #         res = '%s%s' % (food, i)
    #         time.sleep(random.randint(1, 3))
    #         q.put(res)      #往q队列里一直放
    #         print('%s 生产了 %s' % (name, res))
    #
    #
    # def consumption(name, q):
    #     while True:
    #         time.sleep(random.randint(1, 3))
    #         res = q.get()    #从q队列中一直取
    #         print('%s 吃了 %s' % (name, res))
    #
    #
    # if __name__ == '__main__':
    #     q = Queue()
    #     # 生产者
    #     p1 = Process(target=producers, args=('wy', '冰渴落', q))
    #     p2 = Process(target=producers, args=('cyp', '大脚板', q))
    #     p3 = Process(target=producers, args=('yjp', '正新鸡排', q))
    #     # 消费者
    #     c1 = Process(target=consumption, args=('zh', q))
    #     c2 = Process(target=consumption, args=('dsb', q))
    #
    #     c1.start()
    #     c2.start()
    #     p1.start()
    #     p2.start()
    #     p3.start()
    #
    #     print('主进程')
    
    # 对例子进行分析:从结果可以看出一直运行到最后,父进程还是没有停止,但父程序的代码已经执行完毕,那原因就出在子进程那里,子进程的程序没有执行完 毕,所以父进程就不能结束。最后得知:生产者生产完毕了,生产者的子进程代码已经运行完毕。但是消费者还在那里等着从q队列中取值,所以消费者子进程 一直没有运行完毕,父进程也在等着消费者子进程运行完,所以父程序就不能关闭。
    #
    生产者消费者模型一
    # 根据例子1,我们想到的解决方法就是,生产者生产完毕后,再给消费者发送一个结束信息,消费者收到后,就结束子进程,这样的话,父进程也能关闭。
    # 例子2
    # from multiprocessing import Process, Queue
    # import time, random
    
    
    # def producers(name, food, q):
    #     for i in range(4):
    #         res = '%s%s' % (food, i)
    #         time.sleep(random.randint(1, 3))
    #         q.put(res)  # 往q队列里一直放
    #         print('%s 生产了 %s' % (name, res))
    #     q.put(None)  # 在生产者生产完毕后,发送一个结束信息
    #
    #
    # def consumption(name, q):
    #     while True:
    #         time.sleep(random.randint(1, 3))
    #         res = q.get()  # 从q队列中一直取
    #         if res is None: break  # 消费者判断收到结束信息,收到就break掉
    #         print('%s 吃了 %s' % (name, res))
    #
    #
    # if __name__ == '__main__':
    #     q = Queue()
    #     # 生产者
    #     p1 = Process(target=producers, args=('wy', '冰渴落', q))
    #     p2 = Process(target=producers, args=('cyp', '大脚板', q))
    #     p3 = Process(target=producers, args=('yjp', '正新鸡排', q))
    #     # 消费者
    #     c1 = Process(target=consumption, args=('zh', q))
    #     c2 = Process(target=consumption, args=('dsb', q))
    #
    #     c1.start()
    #     c2.start()
    #     p1.start()
    #     p2.start()
    #     p3.start()
    #
    #     print('主进程')
    
    # 加了一个结束信号,子进程和父进程能顺利执行完毕。但是有了一个新问题,就是有一些生产者生产食物快,导致发送了一个结束信号,但同时其他生产者还在 生产食物,所以一个消费者取到结束信号,就停止了,但是此时生产者生产的食物还没有结束,导致消费者并没有把生产者产生的食物吃完。
    # 根据前面例子的分析: 1 生产者生产完毕要发生一个结束信息
    #                   2 必须要生产者全部生产完毕后,才能发这个结束信息。
    #例子3
    # from multiprocessing import Process, Queue
    # import time, random
    #
    #
    # def producers(name, food, q):
    #     for i in range(4):
    #         res = '%s%s' % (food, i)
    #         time.sleep(random.randint(1, 3))
    #         q.put(res)  # 往q队列里一直放
    #         print('%s 生产了 %s' % (name, res))
    
    
    
    # def consumption(name, q):
    #     while True:
    #         time.sleep(random.randint(1, 3))
    #         res = q.get()  # 从q队列中一直取
    #         if res is None: break  # 消费者判断收到结束信息,收到就break掉
    #         print('%s 吃了 %s' % (name, res))
    #
    #
    # if __name__ == '__main__':
    #     q = Queue()
    #     # 生产者
    #     p1 = Process(target=producers, args=('wy', '冰渴落', q))
    #     p2 = Process(target=producers, args=('cyp', '大脚板', q))
    #     p3 = Process(target=producers, args=('yjp', '正新鸡排', q))
    #     # 消费者
    #     c1 = Process(target=consumption, args=('zh', q))
    #     c2 = Process(target=consumption, args=('dsb', q))
    #
    #     c1.start()
    #     c2.start()
    #     p1.start()
    #     p2.start()
    #     p3.start()
    #
    #     p1.join()
    #     p2.join()
    #     p3.join()
    #     q.put(None)    #等p1,p2,p3全部运行完毕,然后在加入结束信息,这样队列最后是结束信息,消费者收到结束信息就结束消费者进程
    #     q.put(None)
    #     print('主进程')
    
    
    # 上面那个例子有个缺陷,就是我们提前已经知道消费者有了几个,根据这样我们就加了几个结束信息,但实际上,我们不应该知道。
    
    # 终极版本的
    
    from multiprocessing import Process, JoinableQueue
    import time, random
    
    
    # def producers(name, food, q):  # 生产者
    #     for i in range(3):
    #         res = '%s%s' % (food, i)
    #         time.sleep(random.randint(1, 3))
    #         q.put(res)
    #         print('%s 生产 %s' % (name, res))
    #
    #
    # def consumption(name, q):  # 消费者
    #     while True:
    #         time.sleep(random.randint(1, 3))
    #         res = q.get()
    #         print('%s 吃了 %s' % (name, res))
    #         q.task_done()
    
    
    def producers(name, food, q):
        for i in range(3):
            res = '%s%s' % (food, i)
            time.sleep(random.randint(1, 3))
            q.put(res)
            print('%s 生产了 %s' % (name, res))
    
    
    def consumption(name, q):
        while True:
            time.sleep(random.randint(1, 3))
            res = q.get()
            print('%s 吃了 %s' % (name, res))
            q.task_done()
    
    
    if __name__ == '__main__':
        q = JoinableQueue()
    
        p1 = Process(target=producers, args=('wy', '冰渴落', q))
        p2 = Process(target=producers, args=('cyp', '大脚板', q))
        p3 = Process(target=producers, args=('yjp', '正新鸡排', q))
        c1 = Process(target=consumption, args=('zh', q))
        c2 = Process(target=consumption, args=('dsb', q))
        c1.daemon = True
        c2.daemon = True
        p1.start()
        p2.start()
        p3.start()
        c1.start()
        c2.start()
    
        p1.join()
        p2.join()
        p3.join()
    
        q.join()
    
        print('主进程')
    生产者消费者模型二
  • 相关阅读:
    计算机组成原理:“性能”是什么?
    试题 基础练习 Huffuman树
    最小堆的插入删除函数
    特殊函数
    进程控制
    进程的描述
    进程管理
    生成和配置Linux操作系统
    系统调用
    Shell脚本编程
  • 原文地址:https://www.cnblogs.com/zhuchunyu/p/9317669.html
Copyright © 2011-2022 走看看