并行化一个Python for循环以模拟两名玩家对抗(博弈论模拟)

1 投票
2 回答
1099 浏览
提问于 2025-04-18 02:52

我正在用Python写一个博弈论的模拟游戏。在这个模拟中,每一代会有两个玩家被配对,然后互相对战(每个玩家都是Player1Player2类的实例)。简单来说,代码大概是这样的:

pool1 = [Player1() for _ in range(50)]
pool2 = [Player2() for _ in range(50)]

assignments = range(50)
random.shuffle(assignments)

pairs = []
for i, assignment in enumerate(assignments):
    pairs.append((pool1[i], pool2[assignment]))

for player1, player2 in pairs:
    repeat = True
    while repeat:
        repeat = play_game(player1, player2)

每个玩家都有一个属性来记录他们的得分。在每一轮结束时,根据玩家的动作,游戏会决定是继续还是结束(play_game会分别返回True或False)。

我想知道如何让这段代码并行运行。也就是说,如何让多个玩家对战同时进行?我在网上查了一下,发现了Python的multiprocessing库,但我不知道怎么把它应用到这段代码上。

谢谢!

2 个回答

1

我想对你帖子里的评论说几句(我没有足够的积分来评论),你的程序可能变慢是因为创建了太多进程,这样会增加额外的负担。除非play_game这个函数需要大量的计算资源或者运行时间很长,否则你可能不需要为它创建单独的进程。线程通常启动的开销更小(在Windows上更明显,因为Unix/Linux把线程当作进程来处理),这可能更符合你的需求。

问题的一部分在于你使用的result。看起来play_game可以返回False并结束循环,但这种方式在使用线程时就不太适用了,因为线程的执行顺序不会再是线性的。如果你只是想同时运行所有的任务,可以把

for player1, player2 in pairs:
    repeat = True
    while repeat:
        repeat = play_game(player1, player2)

改成

thread_list = []
for player1, player2 in pairs:
    thread_list.append(threading.Thread(target=play_game,args=(player1,player2)))
for wait_thread in thread_list:
    wait_thread.join()

这样就可以同时为所有不同的配对启动线程。如果你想在其中一个线程没有返回True时能够终止所有正在运行的线程,你就需要考虑线程之间的通信,并且需要在主程序中设置一个监听线程来读取这些线程的输出。

1

我会创建一个叫做 Game 的类,这个类是从 threading.Thread 继承来的,所以它的行为就像一个线程一样。Game 类的构造函数需要接受两个玩家对象和一个游戏的编号 number

number 是必须的,因为它可以帮助将游戏结果通过一个共享变量 resultList 返回到主程序中(在Python中,列表是线程安全的)。resultList 是一个包含多个列表的列表,每个 Game 实例会根据自己的 number 把结果放到 resultList 的相应位置。

每个 Game() 实例的 run() 方法是在不同的线程中执行的,这样所有的游戏就可以同时进行。

import threading
numOfGames = 10
resultList = [[] for x in xrange(numOfGames)]

class Game(threading.Thread):

    def __init__(self, player1, player2, number):
        threading.Thread.__init__(self)
        self.number = number
        self.player1 = player1
        self.player2 = player2

    def run(self):

        #Your game algorithm between self.player1 and self.player2 is here

        #Put game result into shared list
        resultList[self.number] = <result>

要使用 Game 类,你需要这样做:

#Create instances of the Game() class, pass your Player() objects
#You can do the step in loop
game0 = Game(<PlayerObj>,<PlayerObj>,0)
game1 = Game(<PlayerObj>,<PlayerObj>,1)

#Start execution of Game.run() methods of all Game() objects in separate threads
#You can do the step in loop
game0.start()
game1.start()

#Wait until all Game.run() methods are executed = all threads are finished
#You can do the step in loop
game0.join()
game1.join()

#In the shared list you have corresponding return values, 
#whatever they are in your case [[result of Game 0],[result of Game 1],[]...]
print resultList

PS: 我不建议使用多进程,因为创建一个进程的开销比较大(需要分配栈等)。在你的情况下,使用多进程是可以的,因为你的应用不需要内存隔离。

撰写回答