В настоящее время я пытаюсь ускорить свой код, используя возможности многопроцессорной обработки. Однако я сталкиваюсь с некоторыми проблемами, когда дело доходит до вызова скомпилированного кода из python, так как кажется, что скомпилированный файл исчезает из представления кода, когда он включает любую форму многопроцессорности.
Например, со следующим тестовым кодом:
#include <omp.h>
int main() {
int thread_id;
#pragma omp parallel
{
thread_id = omp_get_thread_num();
}
return 0;
}
Здесь я компилирую программу, затем превращаю ее в файл .so с помощью команды
gcc -fopenmp -o theories/test.so -shared -fPIC -O2 test.c
Затем я пытаюсь запустить указанный код из test.py:
from ctypes import CDLL
import os
absolute_path = os.path.dirname(os.path.abspath(__file__))
# imports the c libraries
test_lib_path = absolute_path + '/theories/test.so'
test = CDLL(test_lib_path)
test.main()
print('complete')
Я получаю следующую ошибку:
FileNotFoundError: Could not find module 'C:\[my path]\theories\test.so' (or one of its dependencies). Try using the full path with constructor syntax.
Однако, когда я комментирую элемент многопроцессорности, чтобы получить следующий код:
#include <omp.h>
int main() {
int thread_id;
/*
#pragma omp parallel
{
thread_id = omp_get_thread_num();
}
*/
return 0;
}
Затем у меня есть идеальное выполнение с программой python, распечатывающей «завершено» в конце.
Мне интересно, как это произошло, и как код, казалось бы, может быть скомпилирован нормально, но затем создавать проблемы только после того, как он вызывается из python (также я проверил, и файл фактически создан).
ОБНОВЛЕНИЯ:
@ JérômeRichard Я думал, что мой gcc был установлен правильно, но, учитывая эту ошибку, я начинаю думать, что это может быть не так. Кроме того, моя система действительно Windows, у меня просто появилась дурная привычка использовать файлы .so, потому что я видел это в случайном учебнике в Интернете, и, похоже, в целом он работает нормально. Не уверены, что это может быть еще одним источником проблем?
В Windows должна быть найдена DLL GOMP, иначе загрузка не будет выполнена. Вам нужно настроить переменную среды PATH, чтобы DLL GOMP можно было найти и загрузить при загрузке вашей динамической библиотеки. Кроме того, я посоветовал вам использовать стандартное расширение (файлы .dll в Windows), чтобы избежать странных проблем, хотя здесь это может не иметь значения.
@ JérômeRichard нужно ли устанавливать GOMP независимо от GCC?
AFAIK, как правило, нет, но это зависит от того, как был установлен GCC (он может быть скомпилирован без поддержки GOMP, хотя это необычно). GOMP — это отдельная библиотека, обычно расположенная с другими DLL. В моей Windows GCC был установлен с MSys, он добавлен в переменную среды PATH и находится в C:\msys64\mingw64\bin
(libgomp-1.dll
). У вас есть такой файл DLL?
@ JérômeRichard Я только что посмотрел, и у меня действительно есть такой файл.
Обратите внимание, что PATH не обновляется для всех приложений динамически. Вы должны проверить, что он был изменен. Самое простое решение для обеспечения изменения PATH в Windows — перезагрузить машину.
@JérômeRichard Я изменил путь вручную и перезагрузил визуальную студию ... Я уже проверил, что это обновило используемый путь, изменив путь на несуществующий. Поскольку это дало ожидаемую ошибку, а скомпилированные версии моего кода работают на 40% быстрее с 64-битной версией, я предполагаю, что новый gcc используется правильно.
Обратите внимание, где в сообщении об ошибке говорится «или одна из его зависимостей».
Попробуйте запустить ldd
в файле test.so
, чтобы убедиться, что он полностью связан.
РЕДАКТИРОВАТЬ1:
Как правило, gcc
требует binutils
.
(Думаю, в ms-windows их можно комбинировать.) Это означает, что у вас должен быть objdump
.
Если вы запустите objdump -x test.so|more
, вы должны увидеть несколько строк, начинающихся с «НУЖНО» в «Динамическом разделе».
Это общие библиотеки, необходимые для этого.
насколько я понимаю, ldd - это команда только для Linux. Я знаю, что использую файлы .so, но в настоящее время я работаю на компьютере с Windows, поэтому у меня возникают проблемы с этим.
objdump работал нормально, но не распечатывал динамический раздел, и я не видел "НЕОБХОДИМО", о котором вы говорили. Однако был раздел под названием «Импорт таблиц», в котором говорилось, что он импортировал файлы «KERNEL32.dll», «msvcrt.dll» и «libgomp-1.dll». Заглянув в свой диспетчер установки MINGW, я увидел, что у меня установлен пакет mingw32-libgomp-dll, который, как мне сказали, должен дать мне файл libgomp-1.dll. Пакет имеет версию 9.2.0-2, и в версиях он имеет флаг «FIXME: таблица данных недоступна; компилятор для этой категории данных еще не реализован».
Я думаю, что это единственное, что казалось неправильным.
Я думаю, что это имеет ту же основную причину, что и [SO]: не удается импортировать модуль dll в Python (@ответ CristiFati) (также проверьте [SO]: PyWin32 и Python 3.8.0 (@ответ CristiFati) ).
.dll (.so) загружается только тогда, когда его зависимости успешно загружены (рекурсивно).
[SO]: Python Ctypes - загрузка dll выдает OSError: [WinError 193] %1 не является допустимым приложением Win32 (@ответ CristiFati) фокусируется на другой ошибке, но охватывает эту тему.
При комментировании вызова omp_get_thread_num компоновщик больше не связывает test.so с libgomp*.dll (поскольку от него ничего не нужно), и код работает нормально (находятся все необходимые .dll).
Чтобы решить эту проблему, вы должны добавить в os.add_dll_directory (перед попыткой загрузить .so):
Каталог libgomp*.dll
Каталог bin MinGW
Любой другой каталог, который может содержать необходимые библиотеки .dll (зависимые)
Чтобы увидеть зависимости .dll, проверьте [SO]: Обнаружение отсутствующего модуля с помощью командной строки («ошибка загрузки DLL») (@ответ CristiFati).
Примечания:
main как экспортируемая функция, поэтому может ввести в заблуждение
Хотя здесь это не требуется (по крайней мере, для текущего кода), проверьте [SO]: функция C, вызванная из Python через ctypes, возвращает неправильное значение (@ответ CristiFati)
Спасибо, хотя я, вероятно, должен добавить, что наиболее удобным ответом на самом деле является ответ Mad Physicist в вашей первой ссылке, где упоминается, что на самом деле вам просто нужно установить winmode = 0 в вызове CDLL.
Так вы говорите, что только изменение test = CDLL(test_lib_path, winmode=0)
решает проблему?
Да, насколько я понимаю, по умолчанию используется winmode = None, что, согласно этому ответу, «похоже, не реагирует на изменения в os.environ ['PATH'], sys.path или os.add_dll_directory».
Эта часть (ответа) не совсем верна (также проверьте комментарии). Я предполагаю, что у вас есть каталог libgomp*.dll в вашем PATH. Я отредактирую свой (другой) ответ, чтобы добавить дополнительную информацию (и, возможно, тестовый код).
Ага, да, я вижу, я думаю, что у меня действительно есть каталог для gomp dll на моем пути, поэтому я предполагаю, что это исправило это.
Я добавил дополнительную информацию, которая, я надеюсь, прольет свет на тему.
Я не могу воспроизвести проблему при повторе с этим bash-кодом. То же самое на другой машине. Вы уверены, что каталог существует? Правильно ли настроена среда и правильно ли установлены GCC/GOMP? Является ли библиотека so правильной? Кроме того, судя по пути к файлу, похоже, что ваша ОС — это Windows, но файлы SO являются общей библиотекой в основном для Linux, а не для Windows. Вы используете WSL? Можете ли вы указать свою целевую ОС?