线程 Thread-1 中的 Python 异常(很可能在解释器关闭期间引发)?

2022-01-21 00:00:00 python numpy pygame multithreading queue

问题描述

我和我的朋友一直在从事一个大型项目,以学习 Python 和 PyGame 并从中获得乐趣.基本上它是一个小村庄的人工智能模拟.我们想要一个昼夜循环,所以我找到了一种巧妙的方法来使用 numpy 改变整个表面的颜色(特别是交叉淡入淡出教程) - http://www.pygame.org/docs/tut/surfarray/SurfarrayIntro.html

My friend and I have been working on a large project to learn and for fun in python and PyGame. Basically it is an AI simulation of a small village. we wanted a day/night cycle so I found a neat way to change the color of an entire surface using numpy (specifically the cross-fade tutorial) - http://www.pygame.org/docs/tut/surfarray/SurfarrayIntro.html

我在代码中实现了它,它可以工作,但是非常慢,比如 <1 帧慢.所以我研究了线程(因为我最终想添加它)并在队列上找到了这个页面 - 了解python中的Queue模块(如何运行)

I implemented it into the code and it WORKS, but is extremely slow, like < 1 fps slow. so I look into threading (because I wanted to add it eventually) and found this page on Queues - Learning about Queue module in python (how to run it)

我花了大约 15 分钟来制作一个基本系统,但一旦我运行它,窗口就会关闭并显示

I spend about 15 minutes making a basic system but as soon as I run it, the window closes and it says

Exception in thread Thread-1 (most likely raised during interpreter shutdown):

这就是它所说的全部内容,没有 Traceback 错误

This is literally all it says, no Traceback error

我不知道我做错了什么,但我想我错过了一些简单的东西.我在下面添加了代码的必要部分.

I don't know what I am doing wrong, but I assume I am missing something simple. I added the necessary parts of the code below.

q_in = Queue.Queue(maxsize=0)

q_out = Queue.Queue(maxsize=0)

def run():    #Here is where the main stuff happens
    #There is more here I am just showing the essential parts
    while True:
        a = abs(abs(world.degree-180)-180)/400.

        #Process world
        world.process(time_passed_seconds)

        blank_surface = pygame.Surface(SCREEN_SIZE)
        world.render(blank_surface)    #The world class renders everything onto a blank surface
        q_in.put((blank_surface, a))
        screen.blit(q_out.get(), (0,0))

def DayNight():
    while True:
        blank_surface, a = q_in.get()
        imgarray = surfarray.array3d(blank_surface)  # Here is where the new numpy       stuff starts (AKA Day/Night cycle)
        src = N.array(imgarray)
        dest = N.zeros(imgarray.shape)
        dest[:] = 20, 30, 120
        diff = (dest - src) * a
        xfade = src + diff.astype(N.int)

        surfarray.blit_array(blank_surface, xfade)
        q_out.put(blank_surface)
        q_in.task_done()

def main():
    MainT = threading.Thread(target=run)
    MainT.daemon = True
    MainT.start()

    DN = threading.Thread(target=DayNight)
    DN.daemon = True
    DN.start()

    q_in.join()
    q_out.join()

如果有人可以提供帮助,将不胜感激.谢谢.

If anyone could help it would be greatly appreciated. Thank you.


解决方案

这在使用守护线程时很常见.你为什么要在你的线程上设置 .daemon = True ?想想看.虽然守护线程有合法用途,但大多数程序员这样做是因为他们感到困惑,例如我不知道如何干净地关闭我的线程,程序将冻结不退出就退出,所以我知道!我会说它们是守护线程.然后解释器在退出时不会等待它们终止.问题解决了."

This is pretty common when using daemon threads. Why are you setting .daemon = True on your threads? Think about it. While there are legitimate uses for daemon threads, most times a programmer does it because they're confused, as in "I don't know how to shut my threads down cleanly, and the program will freeze on exit if I don't, so I know! I'll say they're daemon threads. Then the interpreter won't wait for them to terminate when it exits. Problem solved."

但这并没有解决——它通常只会产生其他问题.特别是,守护线程继续运行,而解释器正在退出 - 销毁自身.模块被销毁,stdin 和 stdout 以及 stderr 被销毁等等.然后,守护线程中的各种事情都可能出错,因为它们试图访问的东西被消灭了.

But it isn't solved - it usually just creates other problems. In particular, the daemon threads keep on running while the interpreter is - on exit - destroying itself. Modules are destroyed, stdin and stdout and stderr are destroyed, etc etc. All sorts of things can go wrong in daemon threads then, as the stuff they try to access is annihilated.

您看到的特定消息是在某个线程中引发异常时产生的,但是解释器破坏已经到了甚至 sys 模块不再包含任何可用的东西.线程实现在内部保留了对 sys.stderr 的引用,以便它可以告诉你 something (具体来说,你看到的确切消息),但是太多的解释器已被销毁,以便告诉您有关问题的任何其他信息.

The specific message you're seeing is produced when an exception is raised in some thread, but interpreter destruction has gotten so far that even the sys module no longer contains anything usable. The threading implementation retains a reference to sys.stderr internally so that it can tell you something then (specifically, the exact message you're seeing), but too much of the interpreter has been destroyed to tell you anything else about what went wrong.

所以找到一种方法来干净地关闭你的线程(并删除 .daemon = True).对您的问题了解得不够多,无法提出具体的方法,但您会想到一些事情 ;-)

So find a way to shut down your threads cleanly instead (and remove .daemon = True). Don't know enough about your problem to suggest a specific way, but you'll think of something ;-)

顺便说一句,我建议删除 Queue() 构造函数上的 maxsize=0 参数.默认是无界",人人都知道",而很少有人知道maxsize=0也意味着无界".这变得更糟,因为其他数据类型将 maxsize=0 表示最大大小确实为 0"(最好的例子是 collections.deque);但是没有参数意味着无限"仍然普遍正确.

BTW, I'd suggest removing the maxsize=0 arguments on your Queue() constructors. The default is "unbounded", and "everyone knows that", while few people know that maxsize=0 also means "unbounded". That's gotten worse as other datatypes have taken maxsize=0 to mean "maximum size really is 0" (the best example of that is collections.deque); but "no argument means unbounded" is still universally true.

相关文章