2014-12-11 2 views
3

Весь мой код записывает журнал через say() to 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 
. . . 

Я понимаю, что если я пытаюсь перенаправить поток ошибок в файл внутренней резьбы в перенаправление будет совместно всеми потоками:

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,)) 

Я не могу динамически выбирать логи для каждого потока, потому что говорят() является глобальным - необходимо будет либо семафором в этом глобальном хранилище файлов журнала, либо передать объект ведения журнала для каждой отдельной функции, которая регистрирует прогресс.

+0

@Amber, у меня уже есть уникальная идентифицированный и может использовать его в качестве имени потока: – Muposat

ответ

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 
+0

Muchas Грасьяс, сеньор – Muposat

0

Вы можете позвонить threading.get_ident() в свою say() функцию, чтобы решить, где написать строку. Это не идеально (поскольку номера идентификаторов потоков разрешены для повторного использования после окончания потока, а другой создается), но если ваши потоки работают долго, это может сработать для ваших целей.

Смежные вопросы