- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
这发生在 Python 3.4.3
中,来自非 python 创建的线程:
https://docs.python.org/3.4/c-api/init.html#non-python-created-threads
有几个关于 SO 的问题,可以从 C/C++ 应用程序中查看类似的问题。
AssertionError (3.X only) when calling Py_Finalize with threads
Fatal error during Py_Finalize in embedded Python application
PyEval_InitThreads in Python 3: How/when to call it? (the saga continues ad nauseum)
但这些都没有专门涉及 Grand Central Dispatch。我不知道这是否重要,因为它可能只是引擎盖下的线程。
然而,尝试应用这些帖子中的知识仍然给我带来了问题。
这就是我目前所处的位置,我有一个代表我的 Python 运行时的 obj-c 类,并且我有以下相关方法:
- (void)initialize
{
Py_Initialize();
PyEval_InitThreads();
PyObject* sysPath = PySys_GetObject((char*)"path");
for(NSString * path in self.pythonPath){
PyList_Append(sysPath, objc_convert_string(path));
}
// not calling PyEval_SaveThread
// causes beginTask below to die on
// PyEval_AcquireThread
// self.threadState = PyThreadState_Get();
// release the GIL, this shouldn't need to be
// done, as I understand it,
// but as the comment above states, if I don't
// beginTask will fail at PyEval_AcquireThread
self.threadState = PyEval_SaveThread();
self.running = YES;
}
这就是我初始化 Python 的方式。然后我通过以下方式调用 python 命令:
- (void)beginTask:(nonnull void (^)(void))task completion:(nullable void (^)(void))completion
{
dispatch_async(self.pythonQueue, ^{
PyInterpreterState * mainInterpreterState = self.threadState->interp;
PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
PyEval_AcquireThread(myThreadState);
// Perform any Py_* related functions here
task();
PyEval_ReleaseThread(PyThreadState_Get());
if (completion){
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}
});
}
在进行长时间运行的操作的情况下,我有一些代码执行相当多的 Jinja 模板渲染并保存到文件系统。我想在完成后进行清理,因此我调用 Py_Finalize
然后重新初始化,使用上述方法输入我的问题:
- (void)finalize
{
PyEval_RestoreThread(self.threadState);
// Problems here
Py_Finalize();
self.running = NO;
}
这会导致 Python 中出现以下错误:
Exception ignored in: <module 'threading' from '/Users/blitz6/Library/Developer/Xcode/DerivedData/Live-cblwxzmbsdpraeebpregeuhikwzh/Build/Products/Debug/LivePython.framework/Resources/python3.4/lib/python3.4/threading.py'>
Traceback (most recent call last):
File "/Users/blitz6/Library/Developer/Xcode/DerivedData/Live-cblwxzmbsdpraeebpregeuhikwzh/Build/Products/Debug/LivePython.framework/Resources/python3.4/lib/python3.4/threading.py", line 1296, in _shutdown
_main_thread._delete()
File "/Users/blitz6/Library/Developer/Xcode/DerivedData/Live-cblwxzmbsdpraeebpregeuhikwzh/Build/Products/Debug/LivePython.framework/Resources/python3.4/lib/python3.4/threading.py", line 1019, in _delete
del _active[get_ident()]
KeyError: 140735266947840
我尝试了几种不同的方法来处理这个问题,包括在 beginTask
中使用 PyGILState_Ensure()
和 PyGILState_Release(myState);
:
- (void)beginTask:(nonnull void (^)(void))task completion:(nullable void (^)(void))completion
{
dispatch_async(self.pythonQueue, ^{
PyGILState_STATE state = PyGILState_Ensure();
task();
PyGILState_Release(state);
if (completion){
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}
});
}
但这会导致上面的finalize
方法中出现此错误:
Exception ignored in: <module 'threading' from '/Users/blitz6/Library/Developer/Xcode/DerivedData/Live-cblwxzmbsdpraeebpregeuhikwzh/Build/Products/Debug/LivePython.framework/Resources/python3.4/lib/python3.4/threading.py'>
Traceback (most recent call last):
File "/Users/blitz6/Library/Developer/Xcode/DerivedData/Live-cblwxzmbsdpraeebpregeuhikwzh/Build/Products/Debug/LivePython.framework/Resources/python3.4/lib/python3.4/threading.py", line 1289, in _shutdown
assert tlock.locked()
AssertionError:
所以我几乎陷入了困境:如何Py_Finalize
而不出现某种错误。显然我不明白一些事情。当我到达断点时,我还可以通过 xcode 确认我的 dispatch_async
block 正在从非主线程的另一个线程运行。
更新
修补了一下,我发现,这个:
PyObject* module = PyImport_ImportModule("requests");
当我在另一个线程上时,当我 Py_Finalize
Exception ignored in: <module 'threading' from '/Users/blitz6/Library/Developer/Xcode/DerivedData/Live-cblwxzmbsdpraeebpregeuhikwzh/Build/Products/Debug/LivePython.framework/Resources/python3.4/lib/python3.4/threading.py'>
Traceback (most recent call last):
File "/Users/blitz6/Library/Developer/Xcode/DerivedData/Live-cblwxzmbsdpraeebpregeuhikwzh/Build/Products/Debug/LivePython.framework/Resources/python3.4/lib/python3.4/threading.py", line 1296, in _shutdown
_main_thread._delete()
File "/Users/blitz6/Library/Developer/Xcode/DerivedData/Live-cblwxzmbsdpraeebpregeuhikwzh/Build/Products/Debug/LivePython.framework/Resources/python3.4/lib/python3.4/threading.py", line 1019, in _delete
del _active[get_ident()]
KeyError: 140735266947840
如果我导入:
PyObject* module = PyImport_ImportModule("os");
OR
PyObject* module = PyImport_ImportModule("json");
作为示例,一切都运行良好。当我开始导入自己的模块时,我遇到了问题。
在Py_Finalize
内部,wait_for_thread_shutdown();
是我遇到这个问题的地方。我猜,根据评论,这与:
/* Wait until threading._shutdown completes, provided the threading module was imported in the first place. The shutdown routine will wait until all non-daemon "threading" threads have completed. */
具体在wait_for_thread_shutdown
中:
PyThreadState *tstate = PyThreadState_GET();
PyObject *threading = PyMapping_GetItemString(tstate->interp->modules,
"threading");
if (threading == NULL) {
/* threading not imported */
PyErr_Clear();
return;
}
tstate
返回 NULL,但 threading
不是 NULL,它会跳过 PyErr_Clear()
代码路径并执行:
result = _PyObject_CallMethodId(threading, &PyId__shutdown, "");
if (result == NULL) {
PyErr_WriteUnraisable(threading);
}
else {
Py_DECREF(result);
}
Py_DECREF(threading);
如果我只是:
PyObject* module = PyImport_ImportModule("json");
然后,PyErr_WriteUnraisable(threading);
在wait_for_thread_shutdown
中执行
result = _PyObject_CallMethodId(threading, &PyId__shutdown, "");
if (result == NULL) {
PyErr_WriteUnraisable(threading);
}
最佳答案
如前所述,我正在思考我的代码,并且错误地思考了嵌入式 Python 解释器。它与 GCD 无关,而与我对嵌入式 Python 某些方面的误解有关。我可能仍然有误解,但是下面的逻辑符合我对我认为应该做的事情的期望,并且我的错误消失了。
我试图做的是运行一次性任务,而不是保留任何东西。我认为我需要在这里线程,这让我绊倒了。
我正在做的事情是获取 GIL,然后导入一些使用 threading
模块的 Python 代码。当您这样做时,解释器会注册您已引入线程模块,就像当您 Py_Finalize
时,它会跳过一些循环以确保所有可能存在或不存在的子线程都被关闭向下。我实际上是把地毯从下面拉出来,这导致了我的错误。相反,我需要完成的工作更有利于 Py_NewInterpreter
。当您调用 Py_EndInterpreter
时,它会运行与 Py_Finalize
完全相同的线程
关闭过程,但与自身隔离。
所以我最终的 GCD 一劳永逸代码如下所示:
初始化
- (void)initialize
{
Py_Initialize();
PyEval_InitThreads();
[self updateSysPath];
// Release the GIL
self.threadState = PyEval_SaveThread();
self.running = YES;
}
任务执行
- (void)beginTask:(nonnull void (^)(Runtime * __nonnull))task completion:(nullable void (^)(Runtime * __nonnull))completion
{
dispatch_async(self.pythonQueue, ^{
PyInterpreterState * mainInterpreterState = self.threadState->interp;
PyThreadState * taskState = PyThreadState_New(mainInterpreterState);
// Acquire the GIL
PyEval_AcquireThread(taskState);
PyThreadState* tstate = Py_NewInterpreter();
[self updateSysPath];
task(self);
// when Py_EndInterpreter is called, the current
// thread state is set to NULL,
// so we need to put ourselves back on
// the taskState, and release the GIL
Py_EndInterpreter(tstate);
PyThreadState_Swap(taskState);
// release the GIL
PyEval_ReleaseThread(taskState);
// cleanup
PyThreadState_Clear(taskState);
PyThreadState_Delete(taskState);
if (completion){
dispatch_async(dispatch_get_main_queue(), ^{
completion(self);
});
}
});
}
最终确定
- (void)finalize
{
// acquire the GIL
PyEval_RestoreThread(self.threadState);
Py_Finalize();
self.running = NO;
}
关于python - 嵌入 Python、在 Grand Central Dispatch 中使用非 Python 线程会导致 Py_Finalize 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30223073/
我的密码 https://gist.github.com/ButuzGOL/707d1605f63eef55e4af 因此,当我收到登录成功回调时,我想进行重定向, 重定向也可以通过调度程序进行。 我
我已经写了访问者模式如下,但我不明白什么是单次和双次分派(dispatch)。AFAIK,单分派(dispatch)是根据调用者类型调用方法,而双分派(dispatch)是根据调用者类型和参数类型调用
我有一个非 ui 线程,我需要在该线程上发送消息。 执行此操作的正常方法是在我的线程的线程过程中调用 Dispatcher.Run()。 我想修改它以使其在处理未处理的异常方面更加健壮。 我的第一个剪
我有一个具有这样功能的代码 const mapDispatchToProps = (dispatch: Dispatch) => ({ onAddProduct: ( key: str
我在使用 Window.Show 显示 WPF 窗口时遇到问题: System.InvalidOperationException was unhandled Message: An unhandle
我对何时使用 Dispatcher.Invoke 从不同线程更新 UI 上的某些内容存有疑问。 这是我的代码... public Window4() { InitializeC
我遇到了一个我无法解决的问题。我正在构建一个电子商务 react 应用程序并使用 useReducer 和 useContext 进行状态管理。客户打开产品,挑选商品数量,然后单击“添加到购物车”按钮
尽管我已经深入了解了 NEventStore 上的事务完整性,但我无法理解在连接了许多 NEventStore 实例时 NEventStore 将如何真正扩展。 总结一下我的理解,一个事件被添加到提交
我学习了 React Javascript 和 Redux,现在我遇到了这个问题。 这是一个 codesandbox 像这样尝试: 搜索书名“dep” 观察日志显示“Search url is:”,当
Dispatcher.CurrentDispatcher(在System.Windows.Threading中)和Application.Current.Dispatcher(在 >系统.Window
我得到了一些代码来处理调度程序在其构造函数中传递给 View 模型的位置。我现在想知道当我想要在 UI 线程上执行某些操作时,我是否应该使用 ObserveOn(dispatcher) 或 dispa
当我们的一个应用程序服务器内存不足时,我正在分析 Java 堆转储。我正在使用 Eclipse 内存分析器。它报告了以下内容。 One instance of "akka.dispatch.Dispa
哪一个: public static let barrier: DispatchWorkItemFlags public static let detached: DispatchWorkItem
我想使用不同于调度类型的类型提示 Action 创建者。 我已经尝试使用这两种类型对 ThunkResult 进行类型提示,但这并不理想。 // types.ts interface AppListA
我正在尝试准确地理解什么是单次分派(dispatch)和多次分派(dispatch)。 我刚刚读到这个: http://en.wikipedia.org/wiki/Multiple_dispatch
I have following api returning Flux of String我有以下返回字符串通量的接口 @GetMapping(value = "/api/getS
这是我自学前端开发一年后在Stackoverflow上的第一个问题。我已经找到了我的疑惑的答案,但由于这些问题是第三次返回,我认为是时候向 Web 提问了。 我正在尝试构建什么 我正在尝试构建一个图书
我正在使用 Kotlin 学习 Android,并且我了解到在不阻塞主线程的情况下启动协程的推荐方法是执行以下操作 MainScope().launch { withContext(Dispatc
错误本身: (alias) deleteCategory(id: number): (dispatch: Dispatch) => void import deleteCategory Argumen
我必须对抽屉进行裁剪,然后创建一个包含所有需要项的DrawerComponent,并创建一个带有NavigationActions的函数来调度我的路线,但是它不起作用。当我单击任何项目时,我都会遇
我是一名优秀的程序员,十分优秀!