3

Я пишу программу, которая использует multiprocessing.managers.DictProxy. Программа перемещается по каталогу и создает dict с именем пользователя в качестве ключа, полученного с помощью pwd.getpwuid(os.stat(file)[4])[0], и соответствующее значение для ключа будет списком, который содержит файлы, принадлежащие этому пользователю. Например, для предполагаемой структуры данных:Python Multiprocessing DictProxy append to dict of list не работает

{'root': ["/boot/vmlinuz", "/boot/grub"], 'testuser': ["/home/testuser", "/home/testuser/.bashrc"]} 

Кода я написал, чтобы сделать это

#!/usr/bin/python 
import os 
import multiprocessing 
import sys 
import pwd 
import grp 
manager_attributes = multiprocessing.Manager() 
file_stats_user = manager_attributes.dict()  
def filestat(file): 
    try: 
     stat = os.stat(file) 
     user = pwd.getpwuid(stat[4])[0] 
     group = grp.getgrgid(stat[5])[0] 
     if user not in file_stats_user: 
      file_stats_user[user] = [] 
     file_stats_user[user].append(file) 
    except OSError, e: 
     print e 

try: 
    cores = (multiprocessing.cpu_count()*2) 
except: 
    cores = 8 
print "Starting parallel execution with ", cores, "concurrency" 
pool_get_attributes = multiprocessing.Pool(cores) 
pool_get_attributes.map(filestat, files) 
pool_get_attributes.close() 
pool_get_attributes.join() 

где файлы находятся список всех файлов, полученные.

Однако, когда я печати file_stats_user который является объектом multiprocessing.managers.DictProxy, я получаю ключи, но список значений являются пустыми, а

{'root': [], 'testuser': []} 

file_stats_user[user].append(file) не прилагая имя файла к соответствующему ключу. Что я здесь делаю неправильно?

спасибо.

+0

при использовании 'multiprocessing', вы должны защитить главный модуль с' если __name__ == '__main __' '. –

+0

Эта программа не называется модулем, так что это все еще необходимо @NizamMohamed? – nohup

ответ

2

EDIT предыдущее решение имеет состояние гонки, если два процесса обновления Dict для того же пользователя в то же время

Ваше решение не работает, потому что по умолчанию список является локальным для текущего процесса и сделанное обновление не проксировано.

Для изготовления работы, вы должны использовать список, который является доверенным лицом, так что может быть обновлены во всем процессе

заменить

file_stats_user[user] = [] 

по

file_stats_user[user] = manager_attributes.list() 

Теперь, когда вы добавляете к Перечислите то же самое во всех процессах

B ет, используя общий объект является плохим способом сделать несколько процессы

Лучшим способа собрать результаты каждого вызова

from collections import defaultdict 
def filestat(file): 
    try: 
     stat = os.stat(file) 
     user = pwd.getpwuid(stat[4])[0] 
     group = grp.getgrgid(stat[5])[0] 
     return user, file 
    except OSError, e: 
     print e 
     return None 
try: 
    cores = (multiprocessing.cpu_count()*2) 
except: 
    cores = 8 
print "Starting parallel execution with ", cores, "concurrency" 
pool_get_attributes = multiprocessing.Pool(cores) 
result_map = pool_get_attributes.map(filestat, files) 
result = defaultdict(list) 
for user,file in (r for r in result_map if r is not None): 
    result[user].append(file) 
pool_get_attributes.close() 
pool_get_attributes.join() 
+0

Спасибо @ Xavier. Это сработало. – nohup

+0

Не могли бы вы объяснить, что делает 'file_stats_user [user] = file_stats_user [пользователь] + [файл]', и почему приложение не работало? Я не понял, что делает 'file_stats_user [user] = file_stats_user [user] + [file]' does. – nohup

+1

Я обновил свой ответ. Какой файл 'file_stats_user [user] = file_stats_user [user] + [file]' does создает новый список с одним элементом больше и обновляет dict с ним ** Однако **, между созданием нового списка и когда произойдет обновление, другой процесс мог бы уже обновить dict, а второе обновление перезапишет первое обновление, поэтому потеря данных –