• python的多进程、logging模


    一、多进程multiprocessing

    1、Process类

    • Process类遵循了Thread类的API,减少了学习的难度
    举例 :单线程、多线程和多进程的比较
    
        import multiprocessing
        import datetime
    
        #计算
        def calc(i):
            sum = 0
            for _ in range(1000000):
                sum += 1
    
            print(i, sum)
    
        if __name__ == "__main__":
            start = datetime.datetime.now()
            ps = []
            for i in range(5):
                #多进程
                p = multiprocessing.Process(target=calc, args=(i,), name="cal-{}".format(i))
                ps.append(p)
                p.start()
            for p in ps:
                p.join()
    
            delta = (datetime.datetime.now() - start).total_seconds()
            print(delta)
            print('===end===')
    
    
    
        单线程,多线程都跑了4分钟,而多进程用了1分钟,这是真并行
        

    2、进程间同步

    • 进程间同步提供了和线程同步一样的类,使用的方法一样,使用的效果也类似,不过,进程间代价要高于线程,而且底层实现是不同的,只不过python屏蔽了这些,让用户简单使用
    • multiprocessing还提供共享内存,服务器进程来共享数据,还提供了Queue队列,Pipe管道用于进程间通信

    3、通信方式不同

    • 多进程就是启动多个解释器进程,进程间通信必须序列化,反序列化
    • 数据的线程安全性问题

    4、进程池的举例

    进程池的举例
        
    import multiprocessing
    import datetime
    
    #计算
    def calc(i):
        sum = 0
        for _ in range(1000000):
            sum += 1
        print(i, sum)
    
    if __name__ == "__main__":
        start = datetime.datetime.now()
        p = multiprocessing.Pool(5)
        for i in range(5):
            p.apply_async(calc, args=(i,))
        p.close()
        p.join()
        delta = (datetime.datetime.now() - start).total_seconds()
        print(delta)
        print('end============')

    5、多进程,多线程的选择

    • CPU密集型:CPython中使用到了GIL,多线程的时候锁互相竞争,且多核优势不能发货,Python多进行效率更高
    • IO密集型:合适是用多线程,减少IO序列化开销,且在IO等待的时候,切换到其他线程继续执行,效率不错

    二、logging模块

    •  日志级别 数值
    •  CRITICAL  50
    •  ERROR     40
    •  WARNING   30,默认级别
    •  INFO      20
    •  DEBUG     10
    •  NOTSET    0
    • 日志级别指的是生产日志的事件的严重程度,设置一个级别后,严重程度低于设置值的日志消息将被忽略

    1、格式字符串

    • 1、日志消息内容 %(message)s :当调用Formatter.format()时设置
    • 2、asctime      %(asctime)s : 创建LogRecord时的可读时间,默认情况下,它的格式为时间
    • 3、函数名       %(funcName)s :日志调用所在的函数名
    • 4、日志级别名称 %(levelname)s : 消息的级别名称'DEBUG','INFO','WARNING','ERROR','CRITICAL'
    • 5、模块         %(module)s    : 模块名
    • 6、进程ID       %(process)d   :  进程ID
    • 7、进程名称     %(processName)s : 进程名
    • 8、线程ID       %(thread)d    : 线程ID
    • 9、线程名称     %(threadName)s : 线程名字

    2、默认级别 举例

        import logging
    
        FORMAT  = '%(asctime)-15s	Thread  info: %(thread)d %(threadName)s %(message)s'
        logging.basicConfig(format=FORMAT)
    
        logging.info('I am {}'.format(20))   #info不显示
        logging.warning('I am {}'.format(20))   #warning默认级别

    3、构建消息

    import logging
    
        FORMAT  = '%(asctime)-15s	Thread  info: %(thread)d %(threadName)s %(message)s'
        logging.basicConfig(format=FORMAT,level=logging.INFO)
    
    
        logging.info('I am {}'.format(20))   #单一字符串
        logging.warning('I am %d %s', 20, 'years old')   #c风格
    
        上例是基本的使用方法,大多数时候,使用的是info,正常运行信息的输出

    4、日志级别和格式字符串扩展的例子

    import logging
    
        FORMAT  = '%(asctime)-15s	Thread info: %(thread)d %(threadName)s %(message)s %(school)s'
        logging.basicConfig(format=FORMAT,level=logging.WARNING)
    
        d = {'school': 'magedu.com'}
    
        logging.info('I am %s %s', 20, 'years old', extra=d)
        logging.warning('I am %s %s', 20, 'years old', extra=d)   #c风格

    5、输出到文件

        import logging
        logging.basicConfig(format='%(asctime)s %(message)s', filename='c:/test')
        for _ in range(5):
            logging.warning('this event was logged')

    6、Logger类

    •  使用工厂方法返回一个Logger类:logging.getLogger([name=None])
    •  指定name,返回一个名称为name的Logger实例,如果再次使用相同的名字,是实例化一个对象
    •  未指定name,返回Logger实例,名称是root,即根Logger
    •  Logger是层次结构的,使用.点号分割,如'a','a.b'或’a,b,c,d',a是a.b的父parent

    7、总结

    • 每一个Logger实例的level如同入口,让水流进来,如果这个门槛太高,信息就进不来;例如log3.warning('log3),如果log3定义的级别高,就不会有信息通过log3
    • 如果level没有设置,就用父logger,如果父logger的level没有设置,继续找父的父的,最终可以找到root上,如果root设置了就他的,如果没有设置,root的默认值是WARNINF
    • 消息传递流程:
    •   在某个logger上产生某种级别的消息,首先和logger的level检查,如果消息level低于logger
    •   的EffectiveLevel有效级别,消息丢弃,如果通过检查后,消息交给交给logger所有的handler处理,
    •   每一个handler需要和自己的level比较来决定是否处理
  • 相关阅读:
    是非人生 — 一个菜鸟程序员的5年职场路 第7节
    是非人生 — 一个菜鸟程序员的5年职场路 第11节
    是非人生 — 一个菜鸟程序员的5年职场路 第8节
    动态调用Webservice
    (转) C# FileStream复制大文件
    是非人生 — 一个菜鸟程序员的5年职场路 第12节
    是非人生 — 一个菜鸟程序员的5年职场路 第16节
    是非人生 — 一个菜鸟程序员的5年职场路 第9节
    c#中模拟键盘(转)
    是非人生 — 一个菜鸟程序员的5年职场路 第15节
  • 原文地址:https://www.cnblogs.com/jiangzuofenghua/p/11451300.html
Copyright © 2020-2023  润新知