Расширение Python C не Threadsafe?
-
10-10-2019 - |
Вопрос
Я сделал расширение AC из сценария Python, который был довольно трудоемким. Сам код хорошо протестирован и простой. Расширение C вызывается с несколькими большими списками, а затем выполняет некоторую умную арифметику и возвращает несколько новых списков. Расширение C на 100% самодостаточное, он не использует никакие другие функции C и не использует какие -либо из методов объектов Python (он использует эти стандартные методы Python, однако: Pyfloat_asdouble, pylist_getitem, pylist_size, pylist_new, py_buildvalue, pylist_append, pylist_new, py_buildvalu ) До сих пор я использовал его только в не-мультичковой среде.
Сегодня я начал использовать его в многопоточной среде GUI, и весь ад сломался. У меня есть несколько тестовых примеров, которые я использую для отладки, и достаточно странно, что меньшие проходят через OK, в то время как более крупные приводят к ошибкам шины и ошибки сегментации (полностью сбоя графического интерфейса и поднимая «отчет о проблеме для окна Python» в OS X) Анкет Проблема, что мое расширение C не Threadsafe? Если так, как я могу сделать это Threadsafe? Я попробовал поиск предмета, но я не нашел никакой хорошей информации, которую я могу понять. Я проверил это а также это Пейги, но я не очень понимаю, что они говорят. Какой тип кода понадобится GIL, а какой нет?
За то, что здесь стоит свалка:
Date/Time: 2010-10-23 03:48:02.714 +0800
OS Version: Mac OS X 10.6.4 (10F569)
Report Version: 6
Interval Since Last Report: 323080 sec
Crashes Since Last Report: 60
Per-App Interval Since Last Report: 110157 sec
Per-App Crashes Since Last Report: 59
Anonymous UUID: 5BD8D75B-9B21-4267-98A4-BAA31E56CB5C
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000000b009286c
Crashed Thread: 2
Thread 0: Dispatch queue: com.apple.main-thread
0 ...ple.CoreServices.CarbonCore 0x90b024c8 ConvertFromUnicodeToTextImplementation + 1976
1 com.apple.HIToolbox 0x951c99e5 CEncodingTranslator::TranslateFromUnicode(char*, unsigned long, unsigned long*, unsigned long*, unsigned long*, unsigned long, short, short) + 549
2 com.apple.HIToolbox 0x951c9d01 CEncodingTranslator::Translate(char*, unsigned long, unsigned long*, unsigned long*, unsigned long*, unsigned long, unsigned long, short, short, short*, unsigned long) + 101
3 com.apple.HIToolbox 0x951a9e51 TXNGetDataEncoded + 278
4 libwx_macd-2.8.0.dylib 0x0188c7ee wxMacMLTEControl::GetLastPosition() const + 52
5 libwx_macd-2.8.0.dylib 0x0188bf73 wxTextCtrl::SetInsertionPointEnd() + 21
6 libwx_macd-2.8.0.dylib 0x0188bfc9 wxTextCtrl::AppendText(wxString const&) + 25
7 _controls_.so 0x1397e357 _wrap_TextCtrl_AppendText + 247 (wxPython.h:48)
8 org.python.python 0x000ca58b PyEval_EvalFrameEx + 21147
9 org.python.python 0x000cc4ba PyEval_EvalCodeEx + 2042
10 org.python.python 0x00041ca2 function_call + 162
11 org.python.python 0x0000f375 PyObject_Call + 85
12 org.python.python 0x000c7d5b PyEval_EvalFrameEx + 10859
13 org.python.python 0x000cc4ba PyEval_EvalCodeEx + 2042
14 org.python.python 0x00041ca2 function_call + 162
15 org.python.python 0x0000f375 PyObject_Call + 85
16 org.python.python 0x000c435e PyEval_CallObjectWithKeywords + 78
17 _core_.so 0x011859f0 wxPyCallback::EventThunker(wxEvent&) + 234 (helpers.cpp:1759)
18 libwx_macd-2.8.0.dylib 0x0180e360 wxEvtHandler::ProcessEventIfMatches(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) + 108
19 libwx_macd-2.8.0.dylib 0x0180e406 wxEvtHandler::SearchDynamicEventTable(wxEvent&) + 80
20 libwx_macd-2.8.0.dylib 0x0180f205 wxEvtHandler::ProcessEvent(wxEvent&) + 225
21 libwx_macd-2.8.0.dylib 0x0180ef4a wxEvtHandler::ProcessPendingEvents() + 86
22 libwx_macd-2.8.0.dylib 0x0176cd02 wxAppConsole::ProcessPendingEvents() + 102
23 libwx_macd-2.8.0.dylib 0x01806873 wxMacProcessNotifierAndPendingEvents + 33
24 libwx_macd-2.8.0.dylib 0x0183107e wxApp::MacHandleOneEvent(void*) + 90
25 libwx_macd-2.8.0.dylib 0x0183110e wxApp::MacDoOneEvent() + 120
26 libwx_macd-2.8.0.dylib 0x0184b570 wxEventLoop::Dispatch() + 32
27 libwx_macd-2.8.0.dylib 0x01906e71 wxEventLoopManual::Run() + 97
28 libwx_macd-2.8.0.dylib 0x018dd364 wxAppBase::MainLoop() + 76
29 _core_.so 0x0117c75c wxPyApp::MainLoop() + 52 (helpers.cpp:215)
30 _core_.so 0x011c9e66 _wrap_PyApp_MainLoop + 82 (_core_wrap.cpp:31686)
31 org.python.python 0x000ca58b PyEval_EvalFrameEx + 21147
32 org.python.python 0x000cc4ba PyEval_EvalCodeEx + 2042
33 org.python.python 0x00041ca2 function_call + 162
34 org.python.python 0x0000f375 PyObject_Call + 85
35 org.python.python 0x00021c66 instancemethod_call + 422
36 org.python.python 0x0000f375 PyObject_Call + 85
37 org.python.python 0x000c8ad6 PyEval_EvalFrameEx + 14310
38 org.python.python 0x000cbc88 PyEval_EvalFrameEx + 27032
39 org.python.python 0x000cc4ba PyEval_EvalCodeEx + 2042
40 org.python.python 0x000cc647 PyEval_EvalCode + 87
41 org.python.python 0x000f0ae8 PyRun_FileExFlags + 168
42 org.python.python 0x000f1a23 PyRun_SimpleFileExFlags + 867
43 org.python.python 0x0010a42b Py_Main + 3163
44 org.python.python 0x00001f82 0x1000 + 3970
45 org.python.python 0x00001ea9 0x1000 + 3753
Thread 1: Dispatch queue: com.apple.libdispatch-manager
0 libSystem.B.dylib 0x96068942 kevent + 10
1 libSystem.B.dylib 0x9606905c _dispatch_mgr_invoke + 215
2 libSystem.B.dylib 0x96068519 _dispatch_queue_invoke + 163
3 libSystem.B.dylib 0x960682be _dispatch_worker_thread2 + 240
4 libSystem.B.dylib 0x96067d41 _pthread_wqthread + 390
5 libSystem.B.dylib 0x96067b86 start_wqthread + 30
Thread 2 Crashed:
0 ccookies.so 0x0060a949 my_calc + 249 (ccookies.c:23)
1 org.python.python 0x000ca3e0 PyEval_EvalFrameEx + 20720
2 org.python.python 0x000cbc88 PyEval_EvalFrameEx + 27032
3 org.python.python 0x000cbc88 PyEval_EvalFrameEx + 27032
4 org.python.python 0x000cbc88 PyEval_EvalFrameEx + 27032
5 org.python.python 0x000cc4ba PyEval_EvalCodeEx + 2042
6 org.python.python 0x00041ca2 function_call + 162
7 org.python.python 0x0000f375 PyObject_Call + 85
8 org.python.python 0x00021c66 instancemethod_call + 422
9 org.python.python 0x0000f375 PyObject_Call + 85
10 org.python.python 0x000c435e PyEval_CallObjectWithKeywords + 78
11 org.python.python 0x0010c79c t_bootstrap + 76
12 libSystem.B.dylib 0x9606f81d _pthread_start + 345
13 libSystem.B.dylib 0x9606f6a2 thread_start + 34
Thread 2 crashed with X86 Thread State (32-bit):
eax: 0x0007d090 ebx: 0x0060a85d ecx: 0x000ef236 edx: 0xb010f920
edi: 0x02315180 esi: 0xb0092890 ebp: 0xb018d378 esp: 0xb0092870
ss: 0x0000001f efl: 0x00010282 eip: 0x0060a949 cs: 0x00000017
ds: 0x0000001f es: 0x0000001f fs: 0x0000001f gs: 0x00000037
cr2: 0xb009286c
Решение
Наконец -то мне удалось избавиться от проблемы, но довольно длинным путем. Вот оно.
Я потратил очень очень много времени, пытаясь понять документацию для расширения C и их водораздела. На одной из многочисленных траекторий Google в ту ночь я наткнулся на это Страница, описывающая, как использовать массивы Numpy в расширениях C. Поскольку мои проблемы, казалось, были связаны с производительностью (исходное расширение C работало для небольших наборов данных), я подозревал, что моя реализация зацикливания через списки Python и использование Pylist_getItem для получения данных в их аналоги C не подходил к царапинам. (Я вышел из следующих фактических чисел в расширении C, поскольку он был очень общим C без каких -либо особых вещей.)
Поэтому я решил провести полное переписывание расширения C и моего сценария Python для использования массивов Numpy вместо списков. Это заняло два дня, включая всю отладь. Но теперь это работает как очарование. Все наборы данных обрабатываются ОК, нет никаких признаков ошибок автобусов или недостатков сегментации.
TLDR: используйте массивы Numpy вместо списков Python при работе с большими наборами данных и расширениями Python C, чтобы избежать ошибок шины и ошибок сегментации.
Другие советы
CPYTHON не безопасен по тему. Это цель GIL, которая должна использоваться при доступе или изменении состояния интерпретатора.
Если вам нужны потоки и Python, вам нужно будет использовать реализацию, отличную от CPYTHON (стандартный), такой как Ironpython или Jython, оба из которых совершенно устойчивы в случае резьбы. Есть несколько модифицированных CPYTHON, таких как без стека Python, который также может работать лучше.