在长期运行的应用程序中使用临时线程?

时间:2015-02-17 23:49:26

标签: python

我有一个运行弹球机的Python应用程序。它需要以相当一致的循环速率运行以进行弹球式的事情,但我还需要能够在整个游戏中的各个点加载图像和声音。我没有足够的内存来预加载整个游戏所需的所有声音文件,所以我想在主游戏循环继续时使用额外的线程(或线程)在后台加载它们。

使用Python的threading模块非常简单,就像使用Queue.Queue来维护需要加载的资产列表一样。我的问题是它是否可以"确定" (因为没有更好的词)让资产加载器线程始终运行,或者我是否应该在需要时创建线程然后在我完成时让它结束。在我的情况下,弹球机和我的Python应用程序将一次运行数小时(或几天)。

我发现的所有Python线程的例子往往都是针对那些做某事然后结束的应用,而不是为长期运行的应用创建(可能)临时线程。

就我而言,我认为我有两种选择:

选项1,加载程序线程永远运行:

self.loader_queue = Queue.Queue

def loader_thread(self):
    while True:
        do_my_work(self.loader_queue.get())

选项2,当队列为空时,加载程序线程结束:

def loader_thread(self):
    while not self.loader_queue.empty():
        do_my_work(self.loader_queue.get())

显然我已经遗漏了一些东西..一些try:块和一种在选项2中创建线程的方法,但我认为这些片段解释了我的两个选项。

我真正的问题是,对于选项1,是"坏"因为那时我浪费了一半Python的执行周期,而加载程序线程只是旋转而且在99.99%的时间内队列为空时什么都不做?

或者这是我应该使用第一个选项的情况,但使用self.loader_queue.get(block=True)?我假设如果我的加载器线程在等待队列中的项目时只是阻塞,那么这是一种有效的等待类型,我不会浪费一堆周期?

谢谢! 布赖恩

1 个答案:

答案 0 :(得分:1)

Queue.get的默认设置是阻止,这就是您所需要的:

  

从队列中删除并返回一个项目。如果可选的args块为true且timeout为None(默认值),则在必要时阻止,直到某个项可用为止。如果timeout是一个正数,它会阻止最多超时秒,如果在该时间内没有可用的项,则会引发Empty异常。否则(块为假),如果一个项立即可用,则返回一个项,否则引发Empty异常(在这种情况下忽略超时)。

这样,while循环只对队列中的每个项目运行一次,并在队列为空时被阻止。

你可以通过在while循环中做一些可见的事情(比如打印一些输出)来自己测试一下。

如果您正在等待项目,则选项1是好的,因为选项2可能在您获得之前终止(如果加载程序足够快)。

线程可能没有占用足够的资源来被视为优化候选者。并且,因为当它不应该运行时,你会阻止它,选项1似乎是要走的路。