使用多处理器模块

时间:2017-01-29 14:11:11

标签: python dictionary multiprocessing

我一直在尝试使用多处理来更新嵌套字典。

如果字典包含元素列表,我可以添加我想要的信息,但如果它是嵌套字典,我看不到任何变化。

我知道多处理模块说它是dictproxy而不是dict而且我已经尝试更改模块上的示例来实现它但我没有运气。

import socket
import csv
from pprint import pprint
from multiprocessing import Pool,Process,current_process,Manager

def dns_lookup(aggregate,ip):
    try:
        hostname=socket.gethostbyaddr(ip)[0]
        proc_name = current_process().name
        #print(str(hostname) + " extracted from ip " + str(ip) + " by process id: " + str(proc_name) )
        aggregate[ip]+=hostname
    except Exception as e:
        pass

if __name__=='__main__':
    procs=[]
    manager=Manager()
    aggregate=manager.dict()
    with open("ip_list.csv","r") as ipfile:
        csv_reader=csv.reader(ipfile)
        for index,row in enumerate(csv_reader):
            if index == 0:
                pass
            else:
                aggregate[row[0]]=row[1:]
                #ips.append((row[0]))
                proc = Process(target=dns_lookup, args=(aggregate,row[0],))
                procs.append(proc)
                proc.start()

    for proc in procs:
        proc.join()
    pprint(dict(aggregate))

以上代码有效,但如果我尝试将原始字典更改为

aggregate[row[0]]={'Other Items':row[1:]}

然后尝试将其更新为

d['hostname']=hostname
aggregate[ip]=d
#aggregate[ip]+=d

没有任何影响。

我需要为实际列表提供字典而不是元素列表。

当前文件很小但我必须将其扩展到大约10k查找,因此需要进行多处理。

非常感谢任何帮助。

谢谢, 卡兰

1 个答案:

答案 0 :(得分:2)

是的,似乎dict上的更新未传播到其他进程。即使将内部词典迁移到manager.dict()也无法解决问题。如果您从头开始创建一个新的dict并将其应用于aggregate[ip]

,那么有效
aggregate[ip] = {"hostname": hostname, "Other Items": aggregate[ip]['Other Items']}

这可能是一个错误,但我建议您对代码进行更大的更改。有两个缺点:

  1. 您使用aggregate作为"队列"仍需要查找的IP,以及进程写入的结果容器。如果将其拆分为一个队列,并且只保存结果的dict可以避免您遇到的问题:那么,您只能从队列中读取并只写入结果容器aggregate
  2. 如果您的csv文件中有1&000; 000行,则最终会有1000个进程,而您的计算机一次只能切断number-of-cores个进程。在Linux上,你浪费了大量不需要的内存。在Windows上,你可以从头开始1� 000 python程序。改为使用Pool让python计算核心数量,并在这些流程中分配您的工作。
  3. 我已将您的代码重写为:

    import socket
    import csv
    from pprint import pprint
    from multiprocessing import Pool, Queue, Process, current_process, Manager
    from time import sleep
    
    def dns_lookup(aggregate,queue):
        while not queue.empty(): # live as long there are items in the queue
            row = queue.get()
            ip = row[0]
            other_items = row[1:]
            hostname=socket.gethostbyaddr(ip)[0]
            aggregate[ip] = {
                "hostname": hostname, 
                "other items": other_items,
                "process_name": current_process().name}
    
    if __name__=='__main__':
        procs=[]
        manager=Manager()
        aggregate=manager.dict()
        queue = Queue()
        with open("ip_list.csv","r") as ipfile:
            csv_reader=csv.reader(ipfile)
            next(csv_reader) # instead of the if index == 0; pass
    
            for row in csv_reader: # fill queue before starting any processes
                queue.put(row)
    
            # start x processes, where None says to take x = the number of cpus returned by `cpu_count()`
            pool = Pool(None, dns_lookup, (aggregate, queue))
            pool.close() # signal that we won't submit any more tasks to pool
            pool.join() # wait until all processes are done
            pprint(dict(aggregate))
    

    此外:您最好使用Threads而不是multiprocessing,因为您的进程将被网络而不是CPU阻止。如果您可以将一个CPU核心占用到100%,那么多处理才有意义。