我有一个依赖 LuaLaTeX 的项目,其中主文档首先生成一个或多个中间.tex
文件,然后循环调用lualatex
以生成最终的 PDF 结果。这可以一次生成多达 10-15 个文档。以后可能会扩展到(Web)服务器并为大量作品生成这 10-15 个文档(具体来说:音乐总谱加上任意数量的乐器部分),因此我们最终可能会得到三位数的lualatex
调用次数(理论上,当项目完成并且全部分数应该立即(重新)生成,甚至可能达到四位数。
为了提高效率和进行研究,我想为该过程的第二阶段实现一个多线程作业队列,其中所有要生成的文档都添加到队列中并由给定数量的工作线程进行处理(每个工作线程都会启动一个外部进程并等待其完成)。我基本上知道它是如何工作的,但从我在网上找到的信息来看,我怀疑 Lua 没有提供必要的多线程支持来实现这一点。
所以问题是:Lua(特别是在 LuaLaTeX 上下文中)是否提供了可靠地实现此类作业队列的机制?如果是,我会很高兴有指针。或者,我会将第二阶段分解为对 Python 脚本的一次调用,我肯定会找到自己的方法 - 但我实际上更喜欢留在主 Lua.tex
文档的范围内。
答案1
下面您可以找到一个穷人的任务池。它利用了io.popen
不阻塞的事实。要等待作业,您可以:close()
在其文件句柄上使用。下面是一个简单的示例,其中每个作业只休眠五秒钟,然后创建一个新的空文件。
local scheduled = {}
local running = {}
local jobs = {
new = function(cmd)
local fn = function()
local handle = io.popen(cmd)
table.insert(running, handle)
end
table.insert(scheduled, fn)
end,
run = function(nprogs)
while true do
if #scheduled == 0 then -- no more jobs?
-- close remaining jobs and exit
for _,job in ipairs(running) do
job:close()
end
break
end
if #running == nprogs then -- maximum number of jobs running?
-- block and wait for the first one
running[1]:close()
table.remove(running,1)
end
-- start new job
scheduled[1]()
table.remove(scheduled,1)
end
end
}
jobs.new("sleep 5; touch out1")
jobs.new("sleep 5; touch out2")
jobs.new("sleep 5; touch out3")
jobs.new("sleep 5; touch out4")
jobs.new("sleep 5; touch out5")
jobs.new("sleep 5; touch out6")
jobs.new("sleep 5; touch out7")
jobs.new("sleep 5; touch out8")
jobs.new("sleep 5; touch out9")
jobs.run(4)
如果这些作业是按顺序执行的,则需要 45 秒。我只是等待堆栈顶部的作业完成,而不是任何堆栈上的作业。因此,只有当所有作业花费的时间大致相同(或者您将较快的作业安排在较慢的作业之前)时,这才会给您带来很好的加速。
$ time lua test.lua
real 0m15.015s
user 0m0.028s
sys 0m0.011s