并行化一个Python for循环以模拟两名玩家对抗(博弈论模拟)
我正在用Python写一个博弈论的模拟游戏。在这个模拟中,每一代会有两个玩家被配对,然后互相对战(每个玩家都是Player1
或Player2
类的实例)。简单来说,代码大概是这样的:
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 个回答
我想对你帖子里的评论说几句(我没有足够的积分来评论),你的程序可能变慢是因为创建了太多进程,这样会增加额外的负担。除非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时能够终止所有正在运行的线程,你就需要考虑线程之间的通信,并且需要在主程序中设置一个监听线程来读取这些线程的输出。
我会创建一个叫做 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: 我不建议使用多进程,因为创建一个进程的开销比较大(需要分配栈等)。在你的情况下,使用多进程是可以的,因为你的应用不需要内存隔离。