进程

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

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

并发:并发其实就是我们人眼看起来是同时运行的。  #单核计算机可以实现并发,利用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('主进程')
生产者消费者模型二
posted @ 2018-07-16 14:58  朱春雨  阅读(231)  评论(0编辑  收藏  举报