我的所有代码都是通过说()将日志写入 sys.stderr 和错误重定向。在多线程服务器中,我希望每个线程都写入一个单独的日志文件。我可以在不重写线程使用的所有代码的情况下完成此操作吗
from threading import Thread
from time import sleep
def say(*args):
print(*args, file=sys.stderr)
def worker(num):
for _ in range(5):
say("worker", num, "working")
sleep(.1)
for num in range(4):
Thread(target=worker, args=(num,)).start()
混合输出,目标是将其重定向到每个线程的不同日志文件:
worker 0 working
worker 1 working
worker 2 working
worker 3 working
worker 0 working
worker 1 working
worker 3 working
worker 2 working
. . .
我的理解是,如果我尝试将stderr重定向到线程内的文件,重定向将由所有线程共享:
def worker(num):
sys.stderr = open('worker{}.log'.format(num), 'w')
for _ in range(5):
say("worker", num, "working")
按预期结果:
$ cat worker3.log
worker 1 working
worker 1 working
worker 1 working
worker 3 working
worker 3 working
worker 3 working
worker 3 working
worker 3 working
@Amber,我已经有了一个唯一的标识符,可以将它用作线程名称:
def say(*args, end='\n'):
print(currentThread().getName(), *args, file=sys.stderr, end=end)
sys.stderr.flush()
t_worker = Thread(name=str(num), target=worker, args=(num,))
我无法为每个线程动态选择日志文件,因为 say()是全局的 - 需要在此全局日志文件存储上放置信号量,或者将日志对象传递给每个单独的函数记录进度。
答案 0 :(得分:1)
您可以使用线程本地存储(通过threading.local
类)为每个线程存储单独的文件对象。然后say
函数可以查找正确的文件:
local = threading.local()
def say(*args):
if not hasattr(local, "logfile"):
local.logfile = open("logfile{}".format(threading.get_ident()), "a")
print(*args, file=local.logfile)
我正在使用threading.get_ident
获取一个有希望的唯一值来生成日志文件名。如果有更合理的方法来命名程序中的文件,我建议您使用它。您甚至可能希望从say
函数中分离出文件的创建。例如,您可以将其作为线程启动代码的一部分:
local = threading.local()
def say(*args):
print(*args, filename=local.logfile)
def worker1():
local.logfile = open("logfile_worker1", "a")
# do stuff here, including calling `say()` as necessary
答案 1 :(得分:0)
您可以在say()
函数中调用threading.get_ident()
来决定在哪里写行。它并不完美(因为在线程结束并创建另一个线程后,允许重用线程ID号),但如果您的线程长时间运行,那么它可能适用于您的目的。