Я сейчас создал параллельное приложение, используя luaproc
.Вот некоторые заблуждения, которые помешали мне принять его раньше, и как обойти их.
После запуска параллельных потоков, насколько я могу судить нетспособ общения с родителем. Это свойство было для меня большим блоком.В конце концов я понял путь вперед: когда он завершает разветвление потоков, родитель останавливается и ждет.Задание, которое было бы выполнено родителем, вместо этого должно быть выполнено дочерним потоком, который должен быть выделен для этого задания.Не очень хорошая модель, но она работает.
Общение между родителями и детьми очень ограничено .Родитель может передавать только скалярные значения: строки, логические значения и числа.Если родитель хочет передать более сложные значения, такие как таблицы и функции, он должен кодировать их как строки.Такое кодирование может быть встроено в программу или (особенно) функции могут быть припаркованы в файловой системе и загружены в дочерний элемент с помощью require
.
Дети не наследуют ничегосреды родителей. В частности, они не наследуют package.path
или package.cpath
.Мне пришлось обойти это, написав код для детей.
Самый удобный способ общения от родителя к ребенку - это определить ребенка как функцию ипусть ребенок захватит родительскую информацию в своих свободных переменных, известных на языке Lua как "upvalues".Эти свободные переменные не могут быть глобальными переменными, и они должны быть скалярами.Тем не менее, это достойная модель.Вот пример:
local function spawner(N, workers)
return function()
local luaproc = require 'luaproc'
for i = 1, N do
luaproc.send('source', i)
end
for i = 1, workers do
luaproc.send('source', nil)
end
end
end
Этот код используется, например, как
assert(luaproc.newproc(spawner(randoms, workers)))
Этот вызов - то, как значения randoms
и workers
передаются от родителя к потомку.
Здесь важно утверждение, так как если вы забудете правила и случайно захватите таблицу или локальную функцию, luaproc.newproc
потерпит неудачу.
Как только я пойму эти свойстваluaproc
действительно работал «из коробки», когда загружено из askyrme на github .
ETA: раздражающее ограничение : в некоторых обстоятельствахвызов fread()
в одном потоке может помешать планированию других потоков.В частности, если я запускаю последовательность
local file = io.popen(command, 'r')
local result = file:read '*a'
file:close()
return result
, операция read
блокирует все остальные потоки .Я не знаю, почему это так - я предполагаю, что в glibc происходит какая-то ерундаОбходной путь, который я использовал, заключался в непосредственном вызове read(2)
, что требовало небольшого кода клея, но это правильно работает с io.popen
и file:close()
.
. Есть еще одно ограничение, на которое стоит обратить внимание:1062 *
В отличие от оригинальной концепции передачи последовательной обработки Тони Хоара и в отличие от большинства зрелых серьезных реализаций синхронной передачи сообщений,
luaproc
не позволяет приемнику блокировать несколько каналов одновременно.Это серьезное ограничение, и оно исключает многие из шаблонов проектирования, в которых хорошо работает синхронная передача сообщений, но оно все еще можно найти для многих простых моделей параллелизма, особенно для типа "parbegin", который мне нужно было решить для моей исходной задачи.