多处理比单处理运行速度慢

时间:2018-08-19 21:52:52

标签: python python-2.7 queue multiprocessing python-multiprocessing

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

已更新

由于@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)

产生:

    Time Elapsed: 1.32399988174 seconds
    Length: 20
    The success average: 0.6

但是,我试图将其用于total_sims = 10,000,000上的num_processes = 5,并且比使用1个进程花费的时间要长得多(在1分钟内返回了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)

3 个答案:

答案 0 :(得分:0)

编辑-您更改了一些内容,让我尝试更好地解释。

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

所以您最初的实现是正确的-获得20条输出消息,发送5条输入消息。

但是,您的功能略有错误。

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

这会将函数转换为生成器,该生成器将在每个next()调用中提供新值!问题在这里

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

在这里,每次循环时,您都会创建一个带有NEW消息的NEW生成器。旧的被扔掉了。因此,在这里,每条输入消息仅在队列中添加一条输出消息,然后再将其丢弃并得到另一条。正确的写法是-

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条消息之后)

答案 1 :(得分:0)

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

答案 2 :(得分:0)

通过将monty_hall_sim的返回值更改为列表理解,让do_work将列表添加到输出队列中,然后使用输出队列返回的列表扩展main的结果列表,我能够使我的代码运行得更快。使它在大约13秒内运行。