关于字典:Python多处理DictProxy附加到列表的字典不起作用

Python Multiprocessing DictProxy append to dict of list not working

我正在编写一个使用multiprocessing.managers.DictProxy的程序。 程序遍历目录,并创建一个dict,其中username是pwd.getpwuid(os.stat(file)[4])[0]获取的密钥,密钥的相应值将是包含该用户拥有的文件的列表。 例如,假设的数据结构:

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

我写的代码就是这样做的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/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()

其中files是获得的所有文件的列表。

但是,当我打印file_stats_user这是一个multiprocessing.managers.DictProxy对象时,我得到了键,但列表值为空,如

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

file_stats_user[user].append(file)不会将文件名附加到相应的键。
我在这做错了什么?

谢谢。


如果两个进程在同一时间更新同一用户的dict,则编辑先前的解决方案具有竞争条件

您的解决方案不起作用,因为默认情况下,列表是当前进程的本地列表,并且对其进行的更新未被代理。

为了使其正常工作,您应该使用一个代理列表,以便在所有过程中进行更新

更换

1
file_stats_user[user] = []

通过

1
file_stats_user[user] = manager_attributes.list()

现在,当您附加到列表时,它在所有进程中都是相同的

但是使用共享对象是进行多进程的一种不好的方法

更好的方法是收集每个呼叫的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()