python線程類改變類變量的操作代碼
python線程類改變類變量
python線程類改變類變量
#!/usr/bin/python3
import threading,time
class Rep2(threading.Thread):
delay = 5
def __init(self):
threading.Thread.__init__(self)
#self.delay = delay
pass
@classmethod
def get_delay(cls):
print('cls_delay:',cls.delay)
@classmethod
def set_delay(cls,delay):
cls.delay = delay
def run(self):
while True:
time.sleep(1)
print('run_delay:',self.delay)
# #測試1
a = Rep2()
# 需要調(diào)用線程類的start()方法而不是run()方法,調(diào)用run()方法類變量delay的值不會(huì)改變
a.start()
print("test1,started")
Rep2.get_delay()
time.sleep(5)
Rep2.delay = 2
Rep2.get_delay()
time.sleep(5)
Rep2.set_delay(222)
Rep2.get_delay()
'''
運(yùn)行結(jié)果1:
test1,started
cls_delay: 5
run_delay: 5
run_delay: 5
run_delay: 5
run_delay: 5
run_delay: 5
cls_delay: 2
run_delay: 2
run_delay: 2
run_delay: 2
run_delay: 2
cls_delay: 222
run_delay: 222
run_delay: 222
run_delay: 222
'''import threading,time
class Rep2():
delay = 5
def __init(self):
pass
#self.delay = delay
@classmethod
def get_delay(cls):
print('cls_delay:',cls.delay)
@classmethod
def set_delay(cls,delay):
cls.delay = delay
def run(self):
print('run_delay:',self.delay)
a = Rep2()
a.run()
print("test2,started")
Rep2.get_delay()
time.sleep(5)
Rep2.delay = 2
Rep2.get_delay()
time.sleep(5)
Rep2.set_delay(222)
Rep2.get_delay()
a.run()
'''
run_delay: 5
test2,started
cls_delay: 5
cls_delay: 2
cls_delay: 222
run_delay: 222
'''擴(kuò)展
python使用標(biāo)準(zhǔn)庫logging實(shí)現(xiàn)多進(jìn)程安全的日志模塊
前言
原本應(yīng)用的日志是全部輸出到os的stdout,也就是控制臺(tái)輸出。因其它團(tuán)隊(duì)要求也要保留日志文件,便于他們用其他工具統(tǒng)一采集,另一方面還要保留控制臺(tái)輸出,便于出問題的時(shí)候自己直接看pod日志。具體需求如下:
- 日志支持同時(shí)控制臺(tái)輸出和文件輸出
- 控制臺(tái)的輸出級(jí)別可以高點(diǎn),比如WARNING,個(gè)人這邊的實(shí)際情況是WARNING或ERROR就能判斷大部分問題。日志文件的輸出級(jí)別設(shè)置為INFO,如果控制臺(tái)日志找不到問題,可以具體看日志文件的內(nèi)容。
- 因?yàn)橛玫搅硕噙M(jìn)程,所以寫文件的時(shí)候要保證多進(jìn)程安全,避免日志內(nèi)容不會(huì)缺失。
- 日志文件可以設(shè)置自動(dòng)分割,避免長時(shí)間不清理導(dǎo)致硬盤存儲(chǔ)資源浪費(fèi)。
因?yàn)椴辉试S隨便使用第三方包,所以只能用標(biāo)準(zhǔn)庫的logging。一開始想的方法比較挫——對文件加鎖,但改來改去發(fā)現(xiàn)根本不能給別人review。翻python官方文檔的時(shí)候發(fā)現(xiàn)logging庫有個(gè)QueueHandler和QueueListener,簡單試了下感覺邏輯還算清楚,遂簡單整理了下代碼。
示例代碼
目錄結(jié)構(gòu)如下,main.py是入口腳本,logs目錄和app.log將有程序運(yùn)行時(shí)自動(dòng)生成,主要日志功能放在pkg/log.py文件中。pkg/__init__.py為空文件,僅用于標(biāo)識(shí)為python包。
.
├── main.py
├── logs
│ └── app.log
└── pkg
├── __init__.py
└── log.pypkg/log.py內(nèi)容如下,主要提供logger已經(jīng)配置好的日志對象,該對象先將日志記錄到QueueHandler,然后QueueListener從隊(duì)列中取日志,并分別輸出到控制臺(tái)和日志文件中。close_log_queue()方法將在主進(jìn)程結(jié)束時(shí)調(diào)用。
import logging
from logging.handlers import TimedRotatingFileHandler, QueueHandler, QueueListener
import sys
import os
# from queue import Queue
from multiprocessing import Queue
log_queue = Queue(-1)
queue_listener = ""
logdir = "logs"
logfile = f"{logdir}/app.log"
if not os.path.exists(logdir):
os.makedirs(logdir, exist_ok=True)
def set_formatter():
"""設(shè)置日志格式化器"""
fmt = "%(asctime)s | %(levelname)s | %(name)s | %(filename)s:%(lineno)d | %(funcName)s | %(message)s"
datefmt = "%Y-%m-%d %H:%M:%S"
return logging.Formatter(fmt, datefmt=datefmt)
def set_queue_handler():
# 不要給QueueHandler重復(fù)設(shè)置formatter, 會(huì)引起重復(fù)嵌套
handler = QueueHandler(log_queue)
handler.setLevel(logging.INFO)
return handler
def set_stream_handler(formatter: logging.Formatter):
# 輸出到控制臺(tái)的日志處理器
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.WARNING)
handler.setFormatter(formatter)
return handler
def set_timed_rotating_file_handler(formatter: logging.Formatter):
# 輸出到文件的日志處理器, 每天生成一個(gè)新文件, 最多保留10個(gè)文件
handler = TimedRotatingFileHandler(logfile, when="midnight", backupCount=10, encoding="utf-8")
handler.setLevel(logging.INFO)
handler.setFormatter(formatter)
return handler
def close_log_queue():
# 關(guān)閉隊(duì)列監(jiān)聽器
global queue_listener
if queue_listener:
queue_listener.stop()
def get_logger(name: str = "mylogger", level: int = logging.INFO):
logger = logging.getLogger(name)
logger.setLevel(level)
formatter = set_formatter()
stream_handler = set_stream_handler(formatter)
file_handler = set_timed_rotating_file_handler(formatter)
queue_handler = set_queue_handler()
logger.addHandler(queue_handler)
global queue_listener
if not queue_listener:
queue_listener = QueueListener(log_queue, stream_handler, file_handler, respect_handler_level=True)
queue_listener.start()
return logger
logger = get_logger()
if __name__ == "__main__":
logger.info("test")
close_log_queue()main.py內(nèi)容如下,主要是創(chuàng)建子進(jìn)程調(diào)用logger,觀察日志輸出是否正常。
from multiprocessing import Process
from pkg.log import logger, close_log_queue
import os
class MyProcess(Process):
def __init__(self, delay):
self.delay = delay
super().__init__()
def run(self):
for i in range(self.delay):
logger.info(f"pid: {os.getpid()}, {i}")
if __name__ == '__main__':
logger.info(f"main process pid: {os.getpid()}")
for i in range(10):
p = MyProcess(10000)
p.start()
p.join()
logger.info("main process end")
close_log_queue()執(zhí)行輸出大致如下所示:
$ tail logs/app.log
2024-01-22 23:10:17 | INFO | mylogger | main.py:12 | run | pid: 7908, 1
2024-01-22 23:10:17 | INFO | mylogger | main.py:12 | run | pid: 7908, 2
2024-01-22 23:10:17 | INFO | mylogger | main.py:12 | run | pid: 7908, 3
2024-01-22 23:10:17 | INFO | mylogger | main.py:12 | run | pid: 7908, 4
2024-01-22 23:10:17 | INFO | mylogger | main.py:12 | run | pid: 7908, 5
2024-01-22 23:10:17 | INFO | mylogger | main.py:12 | run | pid: 7908, 6
2024-01-22 23:10:17 | INFO | mylogger | main.py:12 | run | pid: 7908, 7
2024-01-22 23:10:17 | INFO | mylogger | main.py:12 | run | pid: 7908, 8
2024-01-22 23:10:17 | INFO | mylogger | main.py:12 | run | pid: 7908, 9
2024-01-22 23:10:17 | INFO | mylogger | main.py:21 | <module> | main process end
補(bǔ)充
logging還內(nèi)置很多其它handler,比如按文件大小自動(dòng)切割,日志通過HTTP請求輸出,日志輸出到syslog等,可按照自己需求進(jìn)行定制。
到此這篇關(guān)于python使用標(biāo)準(zhǔn)庫logging實(shí)現(xiàn)多進(jìn)程安全的日志模塊的文章就介紹到這了,更多相關(guān)python多進(jìn)程安全日志模塊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
到此這篇關(guān)于python線程類改變類變量的文章就介紹到這了,更多相關(guān)python線程類改變類變量內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python 實(shí)現(xiàn)手機(jī)自動(dòng)撥打電話的方法(通話壓力測試)
今天小編就為大家分享一篇python 實(shí)現(xiàn)手機(jī)自動(dòng)撥打電話的方法(通話壓力測試),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08
Tensorflow設(shè)置顯存自適應(yīng),顯存比例的操作
今天小編就為大家分享一篇Tensorflow設(shè)置顯存自適應(yīng),顯存比例的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02
python一行代碼就能實(shí)現(xiàn)數(shù)據(jù)分析的pandas-profiling庫
這篇文章主要為大家介紹了python一行代碼就能實(shí)現(xiàn)數(shù)據(jù)分析的pandas-profiling庫,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
解析Python中的eval()、exec()及其相關(guān)函數(shù)
本篇文章主要介紹了解析Python中的eval()、exec()及其相關(guān)函數(shù),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12
一文淺析Python如何構(gòu)建優(yōu)雅的異常體系
這篇文章主要介紹了Python異常處理的核心原則與最佳實(shí)踐,文內(nèi)首先指出異常處理常被低估,通過真實(shí)案例展示了不當(dāng)處理帶來的隱患,隨后解析了Python異常機(jī)制的本質(zhì)是一種控制流信號(hào),并詳細(xì)介紹了異常層級(jí)結(jié)構(gòu),有需要的小伙伴可以了解下2026-03-03
Python進(jìn)度條實(shí)時(shí)顯示處理進(jìn)度的示例代碼
本篇文章主要介紹了Python進(jìn)度條實(shí)時(shí)顯示處理進(jìn)度的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01
Swift 3.0在集合類數(shù)據(jù)結(jié)構(gòu)上的一些新變化總結(jié)
與字符串類似,Swift3在數(shù)組和字典等結(jié)構(gòu)上也有改動(dòng),這里我們就來整理Swift 3.0在集合類數(shù)據(jù)結(jié)構(gòu)上的一些新變化總結(jié):2016-07-07

