多进程运行速度比单个进程慢

2024-06-16 10:54:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试使用多进程来跨多个进程运行许多模拟;但是,据我所知,我编写的代码只使用了其中一个进程。在

更新

多亏了@PaulBecotte,我让所有的进程都能正常工作(我想);然而,多处理似乎比非多处理的运行速度慢得多。在

例如,不包括函数和类声明/实现和导入,我有:

def monty_hall_sim(num_trial, player_type='AlwaysSwitchPlayer'):
    if player_type == 'NeverSwitchPlayer':
        player = NeverSwitchPlayer('Never Switch Player')
    else:
        player = AlwaysSwitchPlayer('Always Switch Player')

    return (MontyHallGame().play_game(player) for trial in xrange(num_trial))

def do_work(in_queue, out_queue):
    while True:
        try:
            f, args = in_queue.get()
            ret = f(*args)
            for result in ret:
                out_queue.put(result)
        except:
            break

def main():
    logging.getLogger().setLevel(logging.ERROR)

    always_switch_input_queue = multiprocessing.Queue()
    always_switch_output_queue = multiprocessing.Queue()

    total_sims = 20
    num_processes = 5
    process_sims = total_sims/num_processes

    with Timer(timer_name='Always Switch Timer'):
        for i in xrange(num_processes):
            always_switch_input_queue.put((monty_hall_sim, (process_sims, 'AlwaysSwitchPlayer')))

        procs = [multiprocessing.Process(target=do_work, args=(always_switch_input_queue, always_switch_output_queue)) for i in range(num_processes)]

        for proc in procs:
            proc.start()

        always_switch_res = []
        while len(always_switch_res) != total_sims:
            always_switch_res.append(always_switch_output_queue.get())

        always_switch_success = float(always_switch_res.count(True))/float(len(always_switch_res))

    print '\tLength of Always Switch Result List: {alw_sw_len}'.format(alw_sw_len=len(always_switch_res))
    print '\tThe success average of switching doors was: {alw_sw_prob}'.format(alw_sw_prob=always_switch_success)

结果是:

^{pr2}$

但是,我尝试在total_sims = 10,000,000上使用total_sims = 10,000,000,这样做比使用1个进程(3分钟内返回1个进程)花费的时间要长得多。我比较它的非多处理对应项是:

def main():
    logging.getLogger().setLevel(logging.ERROR)

    with Timer(timer_name='Always Switch Monty Hall Timer'):
        always_switch_res = [MontyHallGame().play_game(AlwaysSwitchPlayer('Monty Hall')) for x in xrange(10000000)]

        always_switch_success = float(always_switch_res.count(True))/float(len(always_switch_res))

    print '\n\tThe success average of not switching doors was: {not_switching}' \
          '\n\tThe success average of switching doors was: {switching}'.format(not_switching=never_switch_success,
                                                                               switching=always_switch_success)

Tags: inforlenqueue进程resalwaysnum
3条回答

通过将monty_hall_sim的return改为list comprehension,让do嫒u work将列表添加到输出队列中,然后使用输出队列返回的列表扩展main的结果列表,我的代码运行速度明显更快。让它在13秒内跑完。在

您可以尝试在一些if语句下导入“process”

编辑-你改变了一些东西,让我试着解释一下。在

输入队列中的每一条消息都会导致monty_hall_sim函数被调用,并向输出队列发送num_trial消息。在

所以你最初的实现是正确的——得到20条输出消息,发送5条输入消息。在

但是,您的功能有点错误。在

for trial in xrange(num_trial):
    res = MontyHallGame().play_game(player)
    yield res

这将把函数变成一个发生器,在每个下一个调用中提供一个新的值——太好了!问题就在这里

^{pr2}$

在这里,在循环的每一次传递中,都会创建一个包含新消息的新生成器。旧的被扔掉了。因此,在这里,每个输入消息只向队列中添加一个输出消息,然后将其丢弃并获取另一个输出消息。正确的写法是-

while True:
    try:
        f, args = in_queue.get(timeout=1)
        ret = f(*args)
        for result in ret:
            out_queue.put(ret.next())
    except:
        break

这样做将继续从生成器生成输出消息,直到它完成(在本例中生成4条消息之后)

相关问题 更多 >