首页 > 解决方案 > 子线程不能更新父线程变量?

问题描述

我在aiosmtpd/244中发现了一个非常令人困惑的问题,在这里分享我的困惑,以帮助我找到如何解决问题的灵感。

情况

>>> from aiosmtpd.controller import Controller
>>> from aiosmtpd.handlers import Sink
>>> cont = Controller(Sink())
>>> cont.start()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py", line 180, in start
    raise RuntimeError("Unknown Error, failed to init SMTP server")
RuntimeError: Unknown Error, failed to init SMTP server

只有在方法结束时仍然为 Nonestart()self.smtpd时,才能生成上述 RuntimeError 。

预期流量

start()-> _run()->loop.create_server()

然后在第一次连接时:

loop.create_server()-> _factory_invoker()->factory()

该属性在以下几行smtpd中设置:_factory_invoker

        try:
            self.smtpd = self.factory()
            if self.smtpd is None:
                raise RuntimeError("factory() returned None")
            return self.smtpd
        except Exception as err:
            self._thread_exception = err
            return _FakeServer(self.loop)

self._thread_exception这些行中解释:

        if self._thread_exception is not None:
            raise self._thread_exception
        # Defensive
        if self.smtpd is None:
            raise RuntimeError("Unknown Error, failed to init SMTP server")

如您所见,如果self.smtpdNone,那么只有在 中出现错误时才会发生_factory_invoker()。如果是这样,错误应该已经被捕获并记录在self._thread_exception. 如果self._thread_exceptionNone,那么_factory_invoker()已经成功,因此self.smtpd不可能None

我在解决此问题时遇到的主要问题是,在我的所有测试系统(Windows、Ubuntu、OpenSUSE、MacOS 和 FreeBSD)上,我从未遇到过类似的错误。

所以我很难过。我将不胜感激有关解决此问题的任何想法。

标签: pythonpython-asynciopython-multithreadingaiosmtpd

解决方案


好吧,显然我被派去追逐野鹅了。

复合因素是因​​为这些行中抑制了所有异常

        try:
            self._testconn()
        except Exception:
            # We totally don't care of exceptions experienced by _testconn,
            # which _will_ happen if factory() experienced problems.
            pass

结果,一个非常有用的异常self._testconn()被吞下了。

显然self._testconn()尝试连接到 的尝试失败host:port,因此_factory_invoker() 从未被调用。

一旦将try..except块修改为吞咽socket.socket_timeout,实际问题就出现了,我们可以快速修复它。

这一切都记录在aiosmtpd/244中,因此我不会在这里重复它们 :-)

感谢所有花时间和精力尝试解决这个难题的人!


推荐阅读