Python线程执行两次函数

时间:2015-07-04 20:24:48

标签: python multithreading

Atm我正在使用tkinter进行游戏。我正致力于通过游戏地图移动敌人的算法。

我将仅发布相关的行,因为代码很难读取。

我正在使用从线程导入的类Timer。 2相关功能是:

def add_enemies(self):
  enemy = self.enemies.pop(0)
  if enemy in '.':
     Timer(1, self.add_enemies).start()
  else:
     self.move_enemy(enemy,set())
     if not self.game_ended and self.enemies:
        Timer(1, self.add_enemies).start()

def move_enemy(self, enemy, visited):
  if type(enemy) == str:
     if enemy in 'm':
        enemy = Mongol(self.canvas, *self.start)
  visited.add((enemy.x,enemy.y))
  for move in (-1,0),(0,1),(1,0),(0,-1):
      pos = (enemy.x + move[0], enemy.y+move[1])
      if pos in self.way and pos not in visited:
          print(pos)
          enemy.move(*move)
          enemy.take_shot(6)
          visited.add(pos)
          Timer(0.5, lambda: self.move_enemy(enemy, visited)).start()

此函数应移动敌人,等待0.5秒,然后创建一个线程,在该线程中递归调用自身并再次移动敌人。

它可能不是在线程中创建另一个线程的最佳解决方案,但所有其他解决方案使我的GUI在执行函数时冻结。

问题是,Timer执行两次函数move_enemy。代码中的任何其他内容都不会导致此问题。

敌人位置的简单打印测试显示:

它只是移动敌人两次,并增加其位置两次,如图所示。

3 个答案:

答案 0 :(得分:0)

这是一个疯狂的猜测,但是将enemy对象替换为具有修改位置的新enemy对象 Timer(0.5, lambda: self.move_enemy(enemy, visited)).start()可能会得到中间坐标((3,1),(5,1)和其他坐标)。 (如果使用相同的输入执行相同的操作两次,则会得到两个相同的值。)

从输出中我推断:visited.add(pos)不会向visited添加位置,因此if pos in self.way and pos not in visited:子句不会过滤掉已测试的值(因此(2,1)( 2,1)打印输出)。如果.append()效果更好,请尝试。

我尽我所能:D gl hf

答案 1 :(得分:0)

从输出结果来看,看起来实际发生的是你期望按此顺序执行的事情

print
move
print
move
print
move
print
move
....

但是您没有包含足够的同步,而是按此顺序发生:

print
print
move
move
print
print
move
move
....

它没有做任何额外的:它只是按照你希望的顺序做事。

答案 2 :(得分:0)

问题是,tkinter不是线程安全的,因此它不具有确定性。 我使用Queue解决了这个问题。我的主要线程,即tkinter运行,定期检查它是否有东西可以绘制。