[Python] 线程安全的单例模式日志模块

"""
我们的目的是借助单例模式,只生成一个logger。
当日志文件已经存在时,默认以追加方式写入。
"""
import logging
import os
import time
import sys
import threading


def synchronized(func):
    func.__lock__ = threading.Lock()

    def lock_func(*args, **kwargs):
        with func.__lock__:
            return func(*args, **kwargs)

    return lock_func


class SingletonType(type):
    _instances = {}

    @synchronized
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(SingletonType, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class Logger(metaclass=SingletonType):
    def __new__(cls, log_file=None, file_output=True, standard_output=True):
        """
        1. Logger的__new__只在创建第一个实例的时候被调用。
        2. 我们要返回的不是Logger类实例,而是使用内置logging模块创建的实例。
        """
        # 日志文件的路径
        if log_file is None:
            # 文件的当前目录
            current_path = os.path.dirname(os.path.realpath(__file__))
            current_time = time.strftime("%Y-%m-%d-%H%M%S", time.localtime())
            log_file = os.path.join(current_path, 'log_output', f'{current_time}.txt')
            os.makedirs(os.path.dirname(log_file), exist_ok=True)

        cls.logger = logging.getLogger(__name__)
        formater = logging.Formatter('%(asctime)s %(name)s [%(filename)s %(lineno)s] %(message)s')
        # 如果既不使用标准输出,也不使用日志文件输出,则选择标准输出
        if not file_output and not standard_output:
            standard_output = True
        if standard_output:
            # 标准输出
            standard_out = logging.StreamHandler(sys.stdout)
            standard_out.setFormatter(formater)
            cls.logger.addHandler(standard_out)    # 添加标准输出
        if file_output:
            # 日志文件输出
            file_out = logging.FileHandler(log_file, encoding='utf-8')
            file_out.setFormatter(formater)
            cls.logger.addHandler(file_out)    # 添加文件输出
            cls.logger.setLevel(logging.INFO)
        return cls.logger


if __name__ == '__main__':
    logger = Logger("Logger1")  # 只第一个名称有效
    logger2 = Logger("Logger2")
    logger3 = Logger("Logger3")
    logger.info("This is a info")
    print(logger is logger2, logger2 is logger3)
    print(not False and not False)

"""
有n个线程,向同一个信箱(信箱的大小为k)里传递消息,放入的消息为数字i(i=1...n),有m个线程从信箱里取数字,取出来将数字*10并打印。
"""
import time
import random
from threading import Thread, Semaphore, Lock
from Single import Logger

list_len = 5
in_index, out_index = 0, 0
in_lock, out_lock, output_lock = Lock(), Lock(), Lock()
message_list = [0 for x in range(list_len)]
full_semaphore, empty_semaphore = Semaphore(0), Semaphore(list_len)

def producer(name, num: int):
    global in_index, in_lock, output_lock, list_len, message_list, full_semaphore, empty_semaphore
    logger = Logger()
    output_lock.acquire()
    logger.info(f'{name} 初始化')
    output_lock.release()
    while True:
        # time.sleep(random.randint(1, 5))
        empty_semaphore.acquire()
        in_lock.acquire()
        output_lock.acquire()
        message_list[in_index] = num
        in_index = (in_index + 1) % list_len
        logger.info(f'{name}已经加入一个: {num}')
        output_lock.release()
        in_lock.release()
        full_semaphore.release()

def consumer(name):
    global out_index, out_lock, output_lock, list_len, message_list, full_semaphore, empty_semaphore
    logger = Logger()
    output_lock.acquire()
    logger.info(f'{name} 初始化')
    output_lock.release()
    while True:
        # time.sleep(random.randint(1, 5))
        full_semaphore.acquire()
        out_lock.acquire()
        output_lock.acquire()
        num = message_list[out_index] * 10
        out_index = (out_index + 1) % list_len
        logger.info(f'{name}已经取得一个: {num}')
        output_lock.release()
        out_lock.release()
        empty_semaphore.release()

if __name__ == '__main__':
    _ = []
    for i in range(1, 10):
        p = Thread(target=producer, args=(f'Producer-{i} ', i, ))
        p.start()
        _.append(p)
    for i in range(1, 10):
        c = Thread(target=consumer, args=(f'Consumer-{i} ', ))
        c.start()
        _.append(c)
    for t in _:
        t.join()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值