【问题标题】:How to run the same method concurrently without waiting for loop to end?如何在不等待循环结束的情况下同时运行相同的方法?
【发布时间】:2019-02-26 15:29:45
【问题描述】:

如下面的代码所示,当用户点击窗口时,我有一个函数会产生一个圆圈的动画。我的问题是,要让另一个圆圈出现并在一个圆圈已经生成后移动,我必须等待前一个圆圈完成其移动循环。在降雪函数结束时一个圆圈完成其“i in range”循环后,我可以单击并生成另一个圆圈。我希望能够随时单击并让尽可能多的圆圈同时移动(我知道我在函数下的代码中将其限制为 10 次)。看来我需要同时多次运行同一个方法。

from graphics import*
from random import*


win = GraphWin("Graphics Practice", 500, 500)

colours = ["blue", "red", "orange", "purple", "green", "black", "brown", "yellow", "pink"]

def snowfall(randColour):
    point = win.getMouse()
    circle = Circle(point, 40)
    circle.draw(win)
    circle.setFill(colours[randColour])
    for i in range(1000):
        circle.move(0, 1)
        time.sleep(0.002)

randColour = randint(0, 8)
for i in range (10):
    repeatColour = randColour
    snowfall(randColour)
    randColour = randint(0, 8)
    while randColour == repeatColour:
        randColour = randint(0, 8)

win.getMouse()
win.close()

我在多线程方面的一次失败尝试:

from graphics import*
from random import*


win = GraphWin("Graphics Practice", 500, 500)

colours = ["blue", "red", "orange", "purple", "green", "black", "brown", "yellow", "pink"]

def snowfall(randColour):
    point = win.getMouse()
    circle = Circle(point, 40)
    circle.draw(win)
    circle.setFill(colours[randColour])
    for i in range(1000):
        circle.move(0, 1)
        time.sleep(0.002)

randColour = randint(0, 8)
t1 = threading.Thread(target = snowfall, args = randColour)
for i in range (10):
    repeatColour = randColour
    t1.start()
    t1.join()
    randColour = randint(0, 8)
    while randColour == repeatColour:
        randColour = randint(0, 8)

win.getMouse()
win.close()

最新代码:

from graphics import*
from random import*


win = GraphWin("Graphics Practice", 500, 500)

colours = ["blue", "red", "orange", "purple", "green", "black", "brown", "yellow", "pink"]

class Snowflake(object):
    def __init__(self, randColour):
        self.circle = Circle(point, 40)
        self.circle.draw(win)
        self.circle.setFill(colours[randColour])

    def next_frame(self):
        self.circle.move(0, 1)

randColour = randint(0, 8)
sprites = []    
for i in range (100):
    repeatColour = randColour
    point = win.getMouse()
    sprites.append(Snowflake(randColour))
    randColour = randint(0, 8)
    while randColour == repeatColour:
        randColour = randint(0, 8)
    for s in sprites:
        while True:
            s.next_frame()
            time.sleep(0.02)
    win.getMouse()
    randColour = randint(0, 8)
    sprites.append(Snowflake(randColour, point))

win.getMouse()
win.close()

【问题讨论】:

  • 尝试在编程中使用多线程希望您的问题会得到解决。

标签: python function loops methods concurrency


【解决方案1】:

一个问题是您在启动后立即尝试join 线程t1join 一个线程是等待它完成,所以不是启动十个线程,而是启动然后等待一个线程十次。

但是,线程在这里是错误的方法。大多数图形包不允许多个线程绘制到相同的图形上下文,这是出于性能和流动性的充分考虑。这意味着您需要将绘图线程“从里到外”,将每个动画对象的状态放在一个“精灵”中,以便每个动画对象的状态都在它自己的实例中。然后,不是为每个精灵使用单独的线程,而是遍历所有精灵并在一个循环中更新它们,如下所示。

(请注意,我介绍了win.checkMouse(),它对鼠标事件进行非阻塞检查,因此允许您每次点击添加一个精灵,我相信这是您的意图。)

from graphics import *
from random import *

win = GraphWin("Graphics Practice", 500, 500)

colours = ["blue", "red", "orange", "purple", "green", "black", "brown", "yellow", "pink"]

class Snowflake(object):
    def __init__(self, randColour, point):
        self.circle = Circle(point, 40)
        self.circle.draw(win)
        self.circle.setFill(colours[randColour])

    def next_frame(self):
        self.circle.move(0, 1)

randColour = randint(0, 8)
sprites = []
for i in range(100):
    point = win.checkMouse()
    if point:
        randColour = randint(0, 8)
        sprites.append(Snowflake(randColour, point))
    for s in sprites:
        s.next_frame()
    time.sleep(0.1)
win.close()

【讨论】:

  • 我理解您使用多个对象(每个对象都是一个精灵)的概念,但是在尝试实现您的代码时,圆圈现在不再动画(移动)。当我单击它们时它们会出现,但会卡在原地。
  • 我编辑了我的答案以显示一个完整的从上到下的解决方案,因此您可以准确地看到精灵循环与主循环的关系,并演示了如何使用win.getMouse()。 (我也有一个错误,我使用this 代替self,我已修复。)
  • 请看我最近的代码(更新)。我必须添加一个while循环,否则圆圈不会连续动画。现在我回到了我开始的地方,但使用不同的代码,一次移动一个圆圈。我认为这是因为while循环一直在进行,程序永远不会到达下一个checkMouse,但是需要while循环进行连续移动,导致动画。我怎样才能从上面留下的代码中产生更多的圆圈和动画?谢谢。
  • 你最近的代码有几个问题。在 sprite 循环中包含 while True: 意味着它永远不会停止为列表中的第一个 sprite 设置动画。接下来,time.sleep 调用不应在 sprite 循环内;在 all 精灵更新后,每帧只应执行一次。最后,每次都会创建新的Snowflake 实例(每个循环两个),而不是响应新的鼠标事件。仔细查看我的答案中的代码结构。尝试运行它,并添加打印语句或修改它以理解它。
  • 部分按预期工作,谢谢。我还设法使它不能连续重复相同的颜色,就像我之前在我的代码版本中所做的那样。您的代码的一个问题是,在范围部分,当第一个精灵达到该范围时程序结束。假设第一个圆圈移动了 400 次(对于 i 在 400 范围内),一旦它进行了第 400 次移动,整个程序就结束了。其他圆圈在点击时确实会出现并移动,但在第一个圆圈达到 400 时全部停止。
猜你喜欢
  • 1970-01-01
  • 2021-03-12
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 2021-03-02
  • 1970-01-01
  • 2012-01-12
相关资源
最近更新 更多