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
时间后执行的回调,然后它会在可能的时候在主线程上执行。
以下代码可以正常运行:
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
时间后执行的回调,然后它会在可能的时候在主线程上执行。