【问题标题】:Separate output from different threads分离不同线程的输出
【发布时间】:2014-12-12 05:25:12
【问题描述】:

我所有的代码都是通过 say() 将日志写入 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() 是全局的——需要在这个全局日志文件存储上放置一个信号量,或者将一个日志对象传递给每个单独的函数记录进度。

【问题讨论】:

  • @Amber,我已经有一个唯一标识,可以用它作为线程名:

标签: python multithreading python-3.x python-multithreading


【解决方案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

【讨论】:

  • muchas gracias , 先生
【解决方案2】:

你可以在你的say() 函数中调用threading.get_ident() 来决定在哪里写行。它并不完美(因为线程 ID 号允许在线程结束并创建另一个线程后重复使用),但如果您的线程长时间运行,那么它可能适合您的目的。

【讨论】:

    猜你喜欢
    • 2022-01-05
    • 2011-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多