我正在尝试使用lua来构建一些并行算法。有了这个,我的意思是用纯Lua编写代码,对它执行测试,调试它等等。然后,当我确信它有效时,我可以将它转换为真正的多线程库,甚至是另一种语言(例如OpenCL kenel) )。显然,我并不关心原型代码的性能。
我想在每一行都使用一个协同程序,用一些样板随机选择下一个“Thread”来运行。例如:
local function parallel_simulation(...)
local function_list = {...}
local coroutine_list = {}
local thread_number = #function_list
for i = 1, thread_number do
coroutine_list[i] = coroutine.create(function_list[i])
end
while 0 < thread_number do
local current = math.random(1, thread_number)
local worker = coroutine_list[current]
coroutine.resume(worker)
if 'dead' == coroutine.status(worker) then
thread_number = thread_number - 1
table.remove(coroutine_list, current)
end
end
end
----------------------------------------------------------
-- Usage example
local Y = coroutine.yield
local max = 3
local counter = 0
local retry = 99
local function increment()
Y() local c = counter
Y() while max > c do
Y() c = counter
Y() c = c + 1
Y() counter = c
Y() end
end
for i=1,retry do
counter = 0
parallel_simulation(increment, increment)
if max ~= counter then
print('Test SUCCESS ! A non-thread-safe algorithm was identified .', i, counter)
return
end
end
error('Test FAIL ! The non-thread-safe algorithm was not identified .')
这只是一个想法,任何涉及纯Lua的解决方案都是受欢迎的!让我对这个解决方案感到非常不舒服的是Y()。有什么方法可以避免它们吗? (debug.sethook不允许产生...)
编辑1 - 提供了更有意义的例子
编辑2 - 希望,我澄清了我想要完成的事情
答案 0 :(得分:0)
将Y()
放在每行前面的简单替代方法是使用gsub
和load
:
Y = coroutine.yield
max = 3
counter = 0
code = [[
function increment()
local c = counter
while max > c do
c = counter
c = c + 1
counter = c
end
end]]
code = code:gsub("\n ", "\n Y() ") -- replace two spaces in find/replace with whatever tab character(s) you use
assert(load(code))()
local retry = 99
-- rest of code here
(根据您的Lua版本,使用load
或loadstring
)
请注意,变量声明Y / max / counter必须是全局的,否则加载的函数将无法访问它们。同样,code
中的函数必须是全局的,否则increment
将不会存在于加载的代码之外。
这样的解决方案假定每行上的所有指令都是原子/线程安全的。
我建议对parallel_simulation
进行的改进是添加一些改变下一个线程选择方式的方法。例如,如果其中一个线程处于执行的早期阶段,而另一个线程几乎完成,则可能只会显示错误 - 虽然理论上可以通过足够的随机试验达到这个状态,但是有一个参数允许您调整哪些线程更多可能会被选择(使用权重)应该更有可能。