Python 线程:应用程序调用了为不同线程编组的接口

Python thread: The application called an interface that was marshalled for a different thread

以下代码可以正常运行:

 self.sim.create_pnl_results(gui_values, dfs)

这段代码给我一个错误:

thread = Thread(target=self.sim.create_pnl_results, args=(gui_values, dfs))
thread.start()

in _ApplyTypes_ self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args),
com_error: (-2147417842, 'The application called an interface that was marshalled for a different thread.', None, None)

似乎应用程序在更远的地方调用了一个 com 对象,因为我想在上面放一个 gui (QT),所以我需要让它成为一个单独的线程。我怎样才能避免上述错误信息?我读到它与 windows 问题有关。任何有关如何在 python 中解决它的建议将不胜感激。我无法控制从应用程序调用的 com 对象,我不明白如果我从新线程的主线程调用它们会有什么不同。

有关如何调用 com 对象的其他信息:

def process_ts(*args):
    ts_id, i, dfn , ts_queue = args
    pythoncom.CoInitialize()
    ts = win32com.client.Dispatch(pythoncom.CoGetInterfaceAndReleaseStream(ts_id, pythoncom.IID_IDispatch))
    ts_queue.put( tuple([i , ACRF._com_to_ts(ts, i, dfn)]) )
    pythoncom.CoUninitialize ()

许多(如果不是大多数)GUI 应用程序 运行 如果您尝试从另一个线程 update/redraw UI 进入问题。试想一下,如果您有一个线程试图将 "blue" 100x 写入文件,而另一个线程试图写入 "red" 100x,会发生什么。您会看到如下内容:

redblueredblruede...

(授予 Python 你有 GIL,所以你可能不会得到完全相同的效果,但使用多处理你可能会实现它)。

如果一个线程试图将某个区域变为蓝色,而另一个线程试图将其变为红色,那么您的图形应用程序也会发生完全相同的事情。因为这是不可取的,所以有一些保护措施可以通过抛出您遇到的异常来阻止它的发生。

你在这里发生的事情是这样的:

----(UI Thread)-,----------------->
                 \
                  `---(new thread)-----(affect the UI)-X kaboom!

想要发生的事情是这样的:

----(UI Thread)-,--------------------------------------,---(affect the UI)-->
                 \                                    /
                  `---(new thread)-----(pass result)-`

它的确切机制会因框架而异。在 .NET 中,您有一个 if (thing.InvokeRequired){ thing.BeginInvoke(data); }

在 Windows,COM 对象以相同的方式受到保护。如果你在一个线程上创建一个 COM 对象,它不会喜欢你试图在不同的线程上访问它。因此,如果您在不同的线程上创建它并且您仍然需要与其进行交互,那么您将不得不跨线程进行通信。

如果您的代码没有阻塞,或者 运行 不需要很长时间(即 < 250 毫秒),那么 运行 在主线程上调用应该没问题。通常 UI 框架允许您注册一个在 N 时间后执行的回调,然后它会在可能的时候在主线程上执行。