• python日志打印和写入并发简易版本实现


    大家一般都用logging日志打印,但logging是线程安全的,多进程也有很多介绍,引入一些文件锁,对logging做好配置,能过支持。

    但通过测试,发现多进程时还是容易出现重复写入文件或者打印正常漏写入文件的问题。

    我的日志需求比较简单,能够区分文件,正确的写入日志文件。

    引入文件锁;日志写入函数封装到一个操作_Logger类中; 日志名称和写入级别封装到一个业务类Logger中。

    本范例基于python3实现。本范例20个进程并发,分别写入3个文件,每s每个文件写入超过100行数据,日志文件中没有数据冗余,也没有数据遗漏。

    image

    # -*-coding:utf-8-*- 
    """
    Author:yinshunyao
    Date:2017/3/5 0005下午 10:50
    """
    # import logging
    import os
    import time
    # 利用第三方系统锁实现文件锁定和解锁
    if os.name == 'nt':
    import win32con, win32file, pywintypes
    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
    LOCK_SH = 0 # The default value
    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
    __overlapped = pywintypes.OVERLAPPED()


    def lock(file, flags):
    hfile = win32file._get_osfhandle(file.fileno())
    win32file.LockFileEx(hfile, flags, 0, 0xffff0000, __overlapped)

    def unlock(file):
    hfile = win32file._get_osfhandle(file.fileno())
    win32file.UnlockFileEx(hfile, 0, 0xffff0000, __overlapped)

    elif os.name == 'posix':
    from fcntl import LOCK_EX


    def lock(file, flags):
    fcntl.flock(file.fileno(), flags)

    def unlock(file):
    fcntl.flock(file.fileno(), fcntl.LOCK_UN)
    else:
    raise RuntimeError("File Locker only support NT and Posix platforms!")
     



    class _Logger:
    file_path = ''
        #初始化日志路径

    @staticmethod
    def init():

    if not _Logger.file_path:
    _Logger.file_path = '%s/Log' % os.path.abspath(os.path.dirname(__file__))
    return True


    @staticmethod
    def _write(messge, file_name):
    if not messge:
    return True
    messge = messge.replace(' ', ',')
    file = '{}/{}'.format(_Logger.file_path, file_name)
    while True:
    try:
    f = open(file, 'a+')
    lock(f, LOCK_EX)
    break
    except:
    time.sleep(0.01)
    continue

    # 确保缓冲区内容写入到文件
    while True:
    try:
    f.write(messge + ' ')
    f.flush()
    break
    except:
    time.sleep(0.01)
    continue

    while True:
    try:
    unlock(f)
    f.close()
    return True
    except:
    time.sleep(0.01)
    continue
        @staticmethod
    def write(message, file_name, only_print=False):
    if not _Logger.init(): return
    print(message)
    if not only_print:
    _Logger._write(message, file_name)



    class Logger:
    def __init__(self, logger_name, file_name=''):
    self.logger_name = logger_name
    self.file_name = file_name
        # 根据消息级别,自定义格式,生成消息

    def _build_message(self, message, level):
    try:
    return '[%s] [%5s] [%8s] %s'
    % (time.strftime('%Y-%m-%d %H:%M:%S'), level, self.logger_name, message)
    except Exception as e:
    print('解析日志消息异常:{}'.format(e))
    return ''


    def warning(self, message):
    _Logger.write(self._build_message(message, 'WARN'), self.file_name)

    def warn(self, message):
    _Logger.write(self._build_message(message, 'WARN'), self.file_name)

    def error(self, message):
    _Logger.write(self._build_message(message, 'ERROR'), self.file_name)

    def info(self, message):
    _Logger.write(self._build_message(message, 'INFO'), self.file_name, True)

    def debug(self, message):
    _Logger.write(self._build_message(message, 'DEBUG'), self.file_name)
     
    # 循环打印日志测试函数


    def _print_test(count):
    logger = Logger(logger_name='test{}'.format(count), file_name='test{}'.format(count % 3))
    key = 0
    while True:
    key += 1
    # print('{}-{}'.format(logger, key))
    logger.debug('%d' % key)
    logger.error('%d' % key)


    if __name__ == '__main__':
    from multiprocessing import Pool, freeze_support
    freeze_support()
        # 进程池进行测试
    pool = Pool(processes=20)
    count = 0
    while count < 20:
    count += 1
    pool.apply_async(func=_print_test, args=(count,))
    else:
    pool.close()
    pool.join()
     
    好记性不如烂笔头
  • 相关阅读:
    Codeforce-Power Tower(欧拉降幂)
    Caesar Cipher
    BZOJ-1143-祭祀river(二分图-偏序集最大反链)
    商务英语中级第三版 MODULE2 Task 3: Listen to the presentation and write what each refers to.
    计算机网络第一章学习笔记
    第一篇博客随笔
    子页面传递数组给父页面
    第6课第4节_Binder系统_驱动情景分析_服务注册过程_分析
    opencv Mat 与MFC中的CImage相互转换
    多文档中建立一个对话框类,通过这个方法来在其他类中得到对话框对象指针,访问对话框成员
  • 原文地址:https://www.cnblogs.com/inns/p/6591860.html
Copyright © 2020-2023  润新知