使用多处理来查找网络路径

时间:2012-12-21 16:25:41

标签: python multiprocessing threadpool networkx

我目前正在使用networkx函数* all_simple_paths *来查找网络G中的所有路径,用于给定的一组源节点和目标节点。

在更大/更密集的网络上,这个过程非常密集。

我想知道是否可以想象多处理可以用在这个问题上,如果有人对如何实现这个问题有任何想法,可以通过创建一个Pool等。

import networkx as nx

G = nx.complete_graph(8)
sources = [1,2]
targets = [5,6,7]

for target in targets:
    for source in sources:
        for path in nx.all_simple_paths(G, source=source, target=target, cutoff=None):
            print(path)

非常感谢您提出任何建议!

2 个答案:

答案 0 :(得分:2)

对于最简单的情况,您的路径似乎彼此之间没有关系,除了属于同一个图形,因此不存在任何锁定问题。

我要做的是您可以使用multiprocessing模块使用targetsPool方法在map上的每个循环上启动新流程。< / p>

def create_graph_from_target( target )
    for source in sources:
        for path in nx.all_simple_paths(G, source=source, target=target, cutoff=None):
            print(path)

from multiprocessing import Pool
p = Pool( processes=4 )

p.map( create_graph_from_target, targets )
p.close()
p.join()

答案 1 :(得分:2)

这是一个使用工作进程集合的版本。每个工作人员从队列中获取source, target对,并收集列表中的路径。找到所有路径后,结果将放入输出队列中,并由主进程进行整理。

import networkx as nx
import multiprocessing as mp
import random
import sys
import itertools as IT
import logging
logger = mp.log_to_stderr(logging.DEBUG)


def worker(inqueue, output):
    result = []
    count = 0
    for pair in iter(inqueue.get, sentinel):
        source, target = pair
        for path in nx.all_simple_paths(G, source = source, target = target,
                                        cutoff = None):
            result.append(path)
            count += 1
            if count % 10 == 0:
                logger.info('{c}'.format(c = count))
    output.put(result)

def test_workers():
    result = []
    inqueue = mp.Queue()
    for source, target in IT.product(sources, targets):
        inqueue.put((source, target))
    procs = [mp.Process(target = worker, args = (inqueue, output))
             for i in range(mp.cpu_count())]
    for proc in procs:
        proc.daemon = True
        proc.start()
    for proc in procs:    
        inqueue.put(sentinel)
    for proc in procs:
        result.extend(output.get())
    for proc in procs:
        proc.join()
    return result

def test_single_worker():
    result = []
    count = 0
    for source, target in IT.product(sources, targets):
        for path in nx.all_simple_paths(G, source = source, target = target,
                                        cutoff = None):
            result.append(path)
            count += 1
            if count % 10 == 0:
                logger.info('{c}'.format(c = count))

    return result

sentinel = None

seed = 1
m = 1
N = 1340//m
G = nx.gnm_random_graph(N, int(1.7*N), seed)
random.seed(seed)
sources = [random.randrange(N) for i in range(340//m)]
targets = [random.randrange(N) for i in range(1000//m)]
output = mp.Queue()

if __name__ == '__main__':
    test_workers()
    # test_single_worker()
    # assert set(map(tuple, test_workers())) == set(map(tuple, test_single_worker()))

test_workers使用多处理,test_single_worker使用单个进程。

运行test.py不会引发AssertionError,因此看起来两个函数都返回相同的结果(至少对于我运行的有限测试)。

以下是时间结果:

% python -mtimeit -s'import test as t' 't.test_workers()'
10 loops, best of 3: 6.71 sec per loop

% python -mtimeit -s'import test as t' 't.test_single_worker()'
10 loops, best of 3: 12.2 sec per loop

因此,在这种情况下,test_workers在2核系统上能够比test_single_worker实现1.8倍的加速。希望代码能够很好地适应您的真实问题。我很想知道结果。


有些兴趣点:

  • 在短期函数上调用pool.apply_async非常慢, 因为过多的时间花在传递参数上,结果出来了 通过队列而不是使用CPU来进行有用的计算。
  • 最好在列表中收集结果并将完整结果放入 output队列而不是将结果放在output中 时间。放入队列中的每个对象都被腌制,并且更快 腌制一个大的清单,而不是许多小清单。
  • 我认为从一个流程打印更安全,所以打印 语句不会相互衔接(导致输出错位)。