zoukankan      html  css  js  c++  java
  • Python多进程

    由于Python的GIL,多线程未必是cpu密集型程序的好选择。

    多进程可以完全独立的进程环境中运行程序, 可以充分地利用多处理器。但是进程本身的隔离带来的数据不共享也是一个问题,而且线程比进程轻量级。

    multiprocessing

    process类

    Process类遵循了Thread类的API,减少了学习难度。

    先看一个例子,前面介绍的单线程、多线程比较的例子的多进程版本。

    import multprocessing
    import datetime
    
    #计算
    def cale(i):
        sum = 0
        for _ in range(1000000000):
            sum+=1
        print(i,sum)
        
    if __name__ =="__main__":
        start = datetime.datetime.now()
        
        ps = []
        for i in range(5):
            p = multprocesing.Process(target = cale,args = (i,),name = "cale-{}".format(i))
            ps.append(p)
            p.start()
        for p in ps:
            p.join()
            
        delta = (datetime.datetime.now()-start).total_seconds()
        print(delta)
        print("end===")

    单线程、多线程都跑了四分钟多,而多进程用了1分钟多,这是真并行。

    可以看出,几乎没有什么学习难度。

    注意:__name__ == "__main__,多进程代码一定要放在这下面执行。

    pid:进程ID

    exitcode:进程的退出状态码

    terminate():终止指定的进程

    进程间同步

    进程间同步提供了和线程同步一样的类,使用的方法一样,使用的效果也类似。不过,进程间代价要高于线程间,而且底层实现是不同的,只不过Python屏蔽了这些不同之处,让用户简单使用多进程。

    multprocessing还提供共享内存,服务器进程来共享数据,还提供了Queue队列,Pipe管道用于进程间通信。

    通信方式不同:

    1. 多进程就是启动多个解释器进程,进程间通信必须序列化,反序列化。
    2. 数据的线程安全性问题,由于每个进程中没有实现多线程,GIL可以说没什么用了。

    进程池举例

    multprocessing.Pool是进程池类。

    apply(self,func,args = (),kwargs= {}):阻塞执行,导致主进程执行其他子进程就像一个个执行。

    apply_async(self,func,args = (),kwargs = {},callback = none,error_callback = none):与apply方法用法一致,非阻塞执行,得到结果后会执行回调。

    close():关闭池,池不能再接受新的任务。

    terminate():结束工作进程,不再处理未处理的任务。

    join():主进程阻塞等待子进程的退出,join方法要在close或terminate之后使用。

    import multprocessing
    import datetime
    import logging
    
    #日志打印进程ID,进程名,线程ID、线程名
    logging.basicConfig(level = logging.INFO,format = "%(process)d %(processName)s %(thread)d %(message)s")
    
    #计算
    def cale(i):
        sum = 0
        for _ in range(1000):#增大这个值观察效果
            sum+=1
        logging.info("{}. in function".format(sum))
        return sum #进程要return,callback才可以拿到这个结果
        
    if __name__ =="__main__":
        start = datetime.datetime.now()
        
        pool = multprocessing.Pool(5)
        for i in range(5):
            #回调函数必须接受一个参数
            pool.apply_async(cale,args = (i,),callback = lambda x: logging.info("{}.in callback".format(x)))#异步执行
        pool.close()
        pool.join()
        delta = (datetime.datetime.now()=start).total_seconds()
        print(delta)
        print("end===")

    结果为:

    7032 SpawnPoolWorker-3 4528 1000. in function
    6756 MainProcess 7084 1000.in callback
    7032 SpawnPoolWorker-3 4528 1000. in function
    6756 MainProcess 7084 1000.in callback
    7032 SpawnPoolWorker-3 4528 1000. in function
    6756 MainProcess 7084 1000.in callback
    7032 SpawnPoolWorker-3 4528 1000. in function
    6756 MainProcess 7084 1000.in callback
    7032 SpawnPoolWorker-3 4528 1000. in function
    6756 MainProcess 7084 1000.in callback
    0.266
    end===

    多进程,多线程的选择

    1cpu密集型

    cpython中使用到了GIL,多线程的时候锁相互竞争,且多核优势不能发挥,Python多进程效率更高。

    2io密集型

    适合使用多线程,可以减少多进程间的IO序列化开销,且在io等待的时候,切换到其他线程继续执行,效率不错。

    应用

    请求/应答模型:web应用中常见的处理模型

    master启动多个worker工作进程,一般和cpu数据相同,发挥多核优势。

    worker工作进程中,往往需要操作网络IO和磁盘IO,启动多线程,提高并发处理能力。worker处理用户的请求,往往需要等待数据,处理完请求还要通过网络io返回相应。

    这就是nginx工作模式。

     
     
  • 相关阅读:
    Redis主从复制、哨兵Sentinel、集群简单介绍
    Redis集群
    Redis哨兵模式
    Redis主从架构
    Redis持久化方式
    缓存2.2——Redis并发竞争
    DOM内容梳理2
    纯js制作九宫格
    正则表达式内容梳理
    JavaScript之DOM详解
  • 原文地址:https://www.cnblogs.com/xpc51/p/11961574.html
Copyright © 2011-2022 走看看