Удаленные параллельные ядра и LibraryLink - как заставить их работать вместе? - PullRequest
3 голосов
/ 04 января 2012

Кто-нибудь имеет опыт использования расширений C для Mathematica (LibraryLink или MathLink - в настоящее время я использую LibraryLink) с удаленными параллельными ядрами?

Вкратце: как я могу прозрачно использовать определенную библиотекой функцию (см. CreateLibrary и LibraryFunctionLoad ) как в параллельных, так и в непараллельных оценках, когда подчиненные ядра работают на удаленном компьютере

Я ищу некоторые шаги настройки, которые позволят мне иметь функцию libraryFun (написанную на C), которую можно вызывать либо как libraryFun[args], либо параллельно ( и of *). 1015 * и то же самое с ParallelTable[]), когда суб-ядра работают на удаленном компьютере.

Удаленное выполнение основного ядра также может быть лучше , если у меня также не было проблем с этим .


Обновление

Тем временем я добился определенного прогресса. Я опишу это здесь.

Во-первых, ParallelEvaluate оценит выражение во всех параллельных ядрах. Если исходные файлы для расширения C скопированы на удаленный компьютер, мы можем скомпилировать их там следующим образом:

ParallelNeeds["CCompilerDriver`"]
k1 = First@Kernels[]
ParallelEvaluate[SetDirectory["/path/to/source/files"]]
ParallelEvaluate[CreateLibrary["sourefile", "myLibrary"]]

Это нужно сделать только один раз. Я предполагаю, что библиотека уже скомпилирована на главном компьютере с ядром.

После этого во всех последующих сеансах мы можем использовать FindLibrary на основной и удаленной машинах для загрузки библиотеки.

LibraryFunctionLoad[myFun = FindLibrary["myLibrary"], "fun", ...]
ParallelEvaluate[myFun = LibraryFunctionLoad[FindLibrary["myLibrary"], "fun", ...]]

И тут возникает проблема. Из-за разных путей myFun будет иметь разные значения в основном и в параллельных ядрах.

Таким образом, вопрос: Как обеспечить , чтобы значение myFun не было случайно синхронизировано между основным и параллельным ядрами?

Я покажу в отдельных примерах, как это может произойти случайно:

In[1]:= LaunchKernels[2]
Out[1]= {KernelObject[1, "local"], KernelObject[2, "local"]}

Установить значение x в основном ядре:

In[2]:= x = 1
Out[2]= 1

Обратите внимание, что оно получает то же значение и в удаленных ядрах:

In[3]:= ParallelEvaluate[x]
Out[3]= {1, 1}

Установите другое значение для x в параллельных ядрах и убедитесь, что они его хранят:

In[4]:= ParallelEvaluate[x = 2]
Out[4]= {2, 2}

In[5]:= {x, ParallelEvaluate[x]}
Out[5]= {1, {2, 2}}

Теперь "невинно" используйте Parallelize на чем-то, содержащем x:

In[6]:= Parallelize[Table[x, {10}]]
Out[6]= {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}

И посмотрите, как значение x было повторно синхронизировано между основным и подчиненным ядром.

In[7]:= {x, ParallelEvaluate[x]}
Out[7]= {1, {1, 1}}

Новый вопрос: Как я могу предотвратить автоматическую синхронизацию определенного символа между основным и субядрами?

Ответы [ 2 ]

4 голосов
/ 06 января 2012

Я надеюсь, что это отвечает на ваш вопрос:

В настоящий момент я предполагаю, что основное ядро ​​и параллельные ядра имеют одинаковую архитектуру, которая для меня является Windows 7. Сначала вы скомпилируете функцию;Вы можете сделать это вне Mathematica , используя компилятор C, или непосредственно в Mathematica:

f = Compile[{x}, x^2, CompilationTarget -> "C"]

Вы можете проверить, взглянув на InputForm из f, где генерируется dllнаходится:

f // InputForm

Дает что-то вроде:

CompiledFunction[{8, 8., 5468}, {_Real}, {{3, 0, 0}, {3, 0, 1}}, {}, {0, 0, 2, 0, 0}, {{40, 
56, 3, 0, 0, 3, 0, 1}, {1}}, Function[{x}, x^2], Evaluate,
LibraryFunction["C:\\Users\\arnoudb\\AppData\\Roaming\\Mathematica\\ApplicationData\\CCompilerDriver\\BuildFolder\\arnoudb2win-5184\\compiledFunction0.dll", 
"compiledFunction0", {{Real, 0, "Constant"}}, Real]]

Вы можете скопировать этот файл в место, где его может найти параллельное (возможно, удаленное) ядро, например:

CopyFile["C:\\Users\\arnoudb\\AppData\\Roaming\\Mathematica\\ApplicationData\\CCompilerDriver\\BuildFolder\\arnoudb2win-3316\\compiledFunction1.dll",
"c:\\users\\arnoudb\\compiledFunction1.dll"]

Затем вы можете загрузить библиотеку во все параллельные ядра следующим образом:

ParallelEvaluate[
 ff = LibraryFunctionLoad["C:\\users\\arnoudb\\compiledFunction1.dll",
 "compiledFunction1", {Real}, Real]
]

И проверить, работает ли это:

ParallelEvaluate[ff[3.4]]

Что возвращает {11.56,11.56}для меня.

Если параллельное ядро ​​находится на другой архитектуре, вам нужно скомпилировать код C для этой архитектуры (или оценить Compile[..., CompilationTarget->"C"] на параллельном ядре).

1 голос
/ 06 января 2012

Кажется, я нашел решение моего вопроса в Обновление выше. Кажется, это работает, но я пока не могу подтвердить, что он не хрупкий.

Решение состоит в том, чтобы поместить символы, которые мы не хотим синхронизировать, в отдельный контекст. Использование c`x в моем примере вместо x предотвращает синхронизацию значения x, когда оно используется внутри Parallelize. Затем мы можем добавить этот контекст в $ContextPath, чтобы сделать символ легко доступным.

Наиболее удобный способ сделать это, вероятно, поместить все определения в пакет, который загружает библиотечные функции, используя LibraryFunctionLoad[FindLibrary[...], ...]. Для этого библиотека должна быть сначала скомпилирована вручную как на локальном, так и на удаленном компьютере, однако код пакета может быть одинаковым как для основного, так и для подъядерных ядер.


Мне все еще интересно, может ли кто-нибудь подтвердить, что переменные, не входящие в $Context, гарантируют , что они не будут автоматически синхронизироваться.

Обновление Подтверждено здесь .

...