进程(二)

***************************Day05********************************

一、(进程)写一个简单的群聊聊天室

1、功能 : 类似qq群聊

    1. 进入聊天室需要输入姓名,姓名不能重复
     2. 有人进入聊天室会向其他人发送通知
       xxx 进入了聊天室
     3. 一个人发消息,其他人会收到消息
       xxx 说 : xxxxxxxx
     4. 某人退出聊天室,其他人也会收到通知
       xxx 退出了聊天室
     5.管理员喊话:服务端发送消息所有的客户端都就收到
       管理员说:xxxxx
    功能模型:转发
    需要的技术:套接字通信 udp套接字
    用户存储:字典或列表
    消息收发的随意性:多进程

2、代码设计:

     1、封装 将每个功能封装为函数
      2、接口测试(每实现一步就测试一步)

3、代码编写流程

    搭建网络连接 --》创建多进程 --》 每个进程功能编写 --》 项目功能模块实现

4、进入聊天室

     客户端:输入姓名 将信息发给服务端(L name)
              等待服务端回复  根据回复判断是否登录成功
      服务端:接收请求信息  判断请求类型  判断用户名是否存在
              如果存在回复不能登录  如果不存在回复可以登录并插入到数据结构
          发送通知给其他用户

5、聊天

     客户端:创建父子进程 发送聊天请求/接受聊天信息
      服务端:接受请求信息 讲消息转发给其他客户端

6、退出聊天

     客户端 : 发送消息退出  Q  name
                 接受回复
            退出程序
      服务端 : 接受消息
                判断请求类型
            从用户结构删除对应用户
            告知所有人,xxx退出

7、管理员消息

二、multiprocessing 模块创建进程

  1. 需要将要做的事情封装成函数
   2. 使用multiprocessing模块中提供的类Process创建进程对象
   3. 通过进程对象属性设置和Process初始化进程进行进程的设置,绑定要执行的函数
   4. 启动进程,会自动执行进程绑定的函数
   5. 完成进程的回收

三、创建进程对象:Process()

  功能:创建进程对象
   参数:name:  给进程起的名称 (默认Process-1)
         target:要绑定的函数
         args:  元组,给target函数按照位置传参
         kwargs: 字典,给target函数按照键值对传参

四、启动进程与回收子进程

1、p.start()

  功能 : 启动进程
  * terget函数会自动执行,此时进程真正被创建。

2、p.join([timeout])

  功能: 阻塞等待回收子进程(子进程退出)
   参数: 超时时间
     * 使用multiprocessing创建子进程,同样子进程复制父进程的全部代码段(内存空间),父子进程各自执行互不影响,父子进程有各自的运行空间
     * 如果不使用join回收子进程,则子进程退出后会成为僵尸进程
     * 使用multiprocessing创建子进程,往往父进程只是用来创建进程回收进程(功能就是创建子进程回收子进程,所有事件交给子进程完成)
     * 子进程也是有自己特有的PID等资源

注意:

    1、如果子进程从父进程拷贝对象,对象和网络或者文件相关联,那么父子进程会使用同一套对象属性,互相有一定关联性
    2、如果在子进程中单独创建对象,则和父进程完全没有关联
 cookie:
   获取文件大小
   size = os.path.getsize("./timg.jpeg")

总结:
   1. 如何处理僵尸进程
      * 通过wait  waitpid
      * 通过创建二级子进程,让一级子进程退出
   2. multiprocessing创建进程
      * Process 类 创建进程对象
      * 通过start启动进程
      * 通过join回收子进程
****************************Day06*****************************

一、Process进程对象属性

  p.start() 启动进程
   p.join()  阻塞等待回收子进程(子进程退出)
   p.is_alive()  判断进程生命周期(alive)状态,处于生命周期得到True,否则返回False
   p.name 进程名称 默认为Process-1 
   p.pid : 创建的新的进程的PID号
   p.daemon 
       认状态为False 主进程退出不会影响子进程执行
       如果设置为True  则子进程会随着主进程结束而结束 
     * daemon 属性设置要在start() 前
     * 设置daemon为True,则一般不需要加join(一般不和join一起使用)

二、创建自定义进程类

  1、编写类继承Process
   2、编写自己的__init__,同时加载父类init方法
       (即在自定义类中加载父类__init__以获取父类属性,同时可以自定义新的属性)
   3、重写run方法,可以通过生成的对象调用start自动执行该方法

三、多进程优缺点

   优点:可以使用计算机多核,进行任务的并发执行,提高执行效率
            空间独立,数据安全
            运行不受其他进程影响,创建方便
    缺点:进程的创建和删除消耗的系统资源较多

四、进程池技术

1、产生原因:

  如果有大量任务需要多进程完成,则可能需要频繁的创建删除进程,给计算机带来较多的资源消耗。

2、原理:

     创建适当的进程放入进程池,用来处理待处理事件。处理完毕后进程不销毁,仍然在进程池中等待处理其他事件。进程的复用降低了资源的消耗

3、使用方法:

     1、创建进程池,在池内放入适当的进程
      2、将事件加入到进程池等待队列
      3、不断取进程执行事件,直到所有事件执行完毕
      4、关闭进程池,回收进程

4、from multipeocessing import Pool

    1、Pool(processrs)
       功能:创建进程池对象
       参数:表示进程池有多少进程数量
       返回:进程池对象
     2、pool.apply_async(func,args,kwds)
       功能:将事件放入进程池队列执行
       参数:fun 要执行的事件函数
               args  以元组形式给func传参
               kwds  以字典形式给func传参
       返回值:返回一个进程池事件的对象(通过get()属性函数可以获取fun的返回值)
     3、pool.close()
       功能: 关闭进程池,无法再加入事件
     4、pool.join()
       功能: 回收进程池
     5、pool.map(func,iter)
       功能:将要执行的事件放入到进程池
       参数:func 要执行的函数
               iter 迭代对象,给func传参
       返回值:返回事件函数func的返回值列表

五、进程间通信(IPC)

  原因:进程空间相对独立,资源无法相互获取,此时在不同进程间通信需要专门方法。
   进程间通信方法:管道  消息队列  共享内存  信号  信号量    套接字

1、管道通信 Pipe

    1、通信原理:在内存中开辟管道空间,生成管道操作对象,多个进程使用“同一个”管道对象进行操作即可实现通信。
     2、multiprocessing  ---》 Pipe
        fd1,fd2 = Pipe(duplex = True)
        功能: 创建管道
        参数:默认True表示双向管道,如果设置为False则为单向管道
        返回值:两个管道对象fd1、fd2,分别表示管道的两端 
                如果是双向管道则均可以读写;如果是单向管道则fd1只读,fd2只写。
    3、fd.recv()
        功能:从管道读取信息
        返回值:读取到的内容
       * 当管道为空则阻塞
     4、fd.send(data)
        功能: 向管道写入内容
        参数:要写入的内容
      * 管道满时会阻塞
      * 可以发送python数据类型(几乎所有的)

2、消息队列

   1、队列:先进先出
     2、通信原理:在内存中建立队列数据结构模型。多个进程都可以通过队列存入内容,取出内容的顺序和存入顺序保持一致。
     3、创建队列
        q = Queue(maxsize = 0)
        功能:创建队列对象
        参数:maxsize 默认表示系统自动分配队列空间
              如果传入正整数则表示最多存放多少条消息。
        返回值 : 队列对象
     4、q.put(data,[block,timeout])
        功能:向队列中存入消息
        参数:data 要存的消息内容(支持python数据类型)
              block 默认True表示队列满时会阻塞,设置为False则为非阻塞
              timeout  超时时间(单位秒)
     5、data = q.get([block,timeout])
        功能: 获取队列消息
        参数:block 默认为True表示队列空时阻塞,设置为False则为非阻塞
              timeout 超时时间
        返回值:返回获取到的消息内容
     6、q.full()  判断队列是否为满
     7、q.empty() 判断队列是否为空
     8、q.qsize() 判断队列中消息数量
     9、q.close() 关闭队列

3、共享内存

    1、通信原理:在内存中开辟一块空间,对多个进程可见,进程可以写入输入,但是每次写入的内容会覆盖之前的内容。
     2、from multiprocessing import Value,Array
        obj = Value(ctype,obj)
        功能:开辟共享内存空间
        参数:ctype 要存储的数据类型(字符串,要转变的c的类型)
              obj 共享内存的初始化数据
        返回:共享内存对象
     3、obj.value 即为共享内存中的值,对其修改即修改共享内存
     4、obj = Array(ctype,obj)
        功能: 开辟共享内存空间
        参数: ctype 要存储的数据格式
               obj 要存入共享内存的数据内容,如:列表、字符串 表示要存入的内容,要求类型相同
          * 如果是整数则表示要开辟空间的个数
       返回值: 返回共享内存对象(可迭代对象)
              * 可以通过遍历过户每个元素的值
             e.g.  [1,2,3]  ---> obj[1] == 2
              * 如果存入的是字符串
             obj.value 表示字符串的首地址
  总结:
                  管道          消息队列           共享内存
     开辟空间     内存            内存                内存
     读写方式   两端读写        先进先出         每次覆盖上次内容
                双向/单向                  
     效率         一般             一般                 较快
     应用      多用于父子进程   应用灵活广泛   需要注意进行同步互斥操作(复杂)

4、信号通信

    1、通信原理:一个进程向另一个进程发送一个信号来传递某种讯息,接受者根据接收到的信号进行相应的行为
     2、kill -l: 查看信号方式
     3、kill -sig PID: 向一个进程发送信号(sig(为1-64))
     4、关于信号
         信号名称  信号含义      默认处理方法
          SIGHUP   连接断开         终止
          SIGINT    CTRU-C发出   终止
          SIGQUIT   CTRU-\        终止
          SIGTSTP   CTRL-Z         暂停
          SIGKILL   终止一个进程(且不能被阻塞、处理或忽略)
          SIGSTOP  暂停一个进程(且不能被阻塞、处理或忽略)
          SIGALRM  时钟信号         终止

          SIGCHLD  子进程状态改变时给父进程发出    忽略
    5、Python发送信号
        signal
        os.kill(pig,sig)
         功能:发送信号
         参数:pid 目标进程PID号
               sig 要发送的信号

    6、信号通信方法
       1、import signal
          signal.alarm(sec)
              功能: 向自身发送时钟信号 --》SIGALRM
             参数: sec  时钟时间(秒)
         * 一个进程中只能有一个时钟,后来的时候会覆盖前面的时间
       2、程序的同步执行和异步执行:
            同步执行:程序按照步骤一步一步执行,呈现一个先后性和顺序性
            异步执行:在执行过程中利用内核记录延迟发生或者准备处理的事件,这样不影响应用层的持续执行。当事件发生时再由内核告知应用层处理
           * 信号是唯一的异步通信方法
       3、signal.pause()
           功能: 阻塞进程等待接收一个信号
       4、signal.signal(signum,handler)
            功能:处理信号
           参数:signum   要处理的信号
                    handler  信号的处理方法
                        可选值:SIG_DFL  表示使用默认的方法处理
                                  SIG_IGN  表示忽略这个信号
                    func    传入一个函数表示用指定函数处理(自定义函数)
                    自定义函数格式:def func(sig,frame)
                                                 sig:   捕获(接收)到的信号
                                                frame:信号结构对象
           * signal函数也是一个异步处理函数。只要执行了该函数,则进程任意时候接收到相应信号都会处理。
           * signal 是不能处理 SIGKILL SIGSTOP的
           * 父进程中可以用 signal(SIGCHLD,SIG_IGN)将子进程的退出交给系统处理
           * 信号是一种异步的进程间通信方法

总结:
1. 进程对象属性
    p.pid   p.name  p.is_alive()  p.daemon

2. 自定义进程类
    继承Process  重写run
3. 进程池   大量进程事件需要频繁创建删除进程
        Pool()   apply_async()   close()    join()    map()
4.进程间通信
      管道   消息队列   共享内存   信号  信号量  套接字
   管道: Pipe()    fd.recv()   fd.send()
   消息队列: Queue()  q.get()  q.put() q.full()
              q.empty()  q.qsize()  q.close()
   共享内存: Value()   Array()
   信号 :  kill  -l   
            kill  -sig  PID
            kill(pid,sig)
****************************Day07*****************************

一、信号量(信号灯)

    原理:给定一定的数量,对多个进程可见,并且多个进程都可以操作,进程通过对信号数量多少的判断执行各自的行为。
    multiprocessing --》Semaphore
     1、sem = Semaphore(num)
       功能 : 创建信号量对象
       参数 : 信号量的初始值
       返回 : 信号量对象
     2、sem.get_value()  获取当前信号量的值
     3、sem.acquire()      将信号量数量减1,当数量为0则阻塞
    4、sem.release()      将信号量数量加1

二、进程的同步互斥

   1、临界资源:多个进程或者线程都能够操作的共享资源
    2、临界区:操作临界资源的代码段
    3、同步:同步是一种合作关系,为完成某个任务,多进程或者多线程之间形成一种协调,按照约定或条件执行操作临界资源。
    4、互斥:互斥是一种制约关系,当一个进程或者线程使用临界资源时进行上锁处理,当另一个进程使用时会阻塞等待,直到解锁后才能继续使用。

三、Event 事件

  multiprocessing --》 Event
   1、创建事件对象
     e = Event()
   2、设置事件阻塞
     e.wait([timeout])
      功能:使进程处于阻塞状态,直到事件对象被set
      参数:timeout 为超时时间
   3、事件设置(当事件被设置后e.wait()不再阻塞)
     e.set()
      功能 : 让事件对象变为被设置状态
   4、清除设置(当事件设置被clear后 e.wait又会阻塞)
     e.clear()
      功能 : 使事件对象清除设置状态
   5、事件状态判断 
     e.is_set()
      功能:判断当前事件对象的状态

四、Lock 锁 

multiprocessing --》 Lock()
   1、创建对象
     lock = Lock()
   2、上锁:lock.acquire()  
    * 如果一个锁对象已经被上锁(处于上锁状态)则再调用acquire会阻塞
   3、解锁:lock.release() 
   4、with lock:  等同于lock.acquire()  上锁
         语句块
         ....
     * 语句块执行完自动解锁

总结:

  1. 信号处理   signal()
      * 异步通信方式 ---》 同步执行 异步执行
   2. 信号量   Semaphore()
         acquire()  删除
     release()  增加
     get_value()  获取
   3. 同步互斥机制 :
       解决了多个进程或者线程对共享资源的争夺
       Event   e.set  e.clear  e.wait
       Lock    lock.acquire()   lock.release()

posted on 2018-10-12 15:35  破天荒的谎言、谈敷衍  阅读(311)  评论(0)    收藏  举报

导航