在Linux上从命令队列进行并行处理(bash、python、ruby等等)

在Linux上从命令队列进行并行处理(bash、python、ruby等等),python,ruby,bash,shell,parallel-processing,Python,Ruby,Bash,Shell,Parallel Processing,我有一个包含200条命令的列表/队列,需要在Linux服务器上的shell中运行这些命令 我只希望一次最多从队列运行10个进程。有些过程需要几秒钟才能完成,而其他过程则需要更长的时间 当一个进程完成时,我希望下一个命令从队列中弹出并执行 有人有解决这个问题的代码吗 进一步阐述: 在某种队列中,有200件工作需要完成。我想一次最多完成10件工作。当线程完成一项工作时,它应该向队列询问下一项工作。如果队列中没有更多的工作,则线程应该死亡。当所有的线程都死掉了,这意味着所有的工作都完成了 我试图解决的

我有一个包含200条命令的列表/队列,需要在Linux服务器上的shell中运行这些命令

我只希望一次最多从队列运行10个进程。有些过程需要几秒钟才能完成,而其他过程则需要更长的时间

当一个进程完成时,我希望下一个命令从队列中弹出并执行

有人有解决这个问题的代码吗

进一步阐述:

在某种队列中,有200件工作需要完成。我想一次最多完成10件工作。当线程完成一项工作时,它应该向队列询问下一项工作。如果队列中没有更多的工作,则线程应该死亡。当所有的线程都死掉了,这意味着所有的工作都完成了


我试图解决的实际问题是使用imapsync将200个邮箱从旧邮件服务器同步到新邮件服务器。一些用户的邮箱很大,需要很长时间才能同步,而另一些用户的邮箱很小,同步速度很快。

如果您打算使用Python,我建议您为此使用


具体地说

你能详细解释一下你所说的平行是什么意思吗?听起来您需要在队列中实现某种类型的锁定,这样您的条目就不会被选中两次,等等,而命令只运行一次

大多数排队系统都会作弊——他们只是写一个巨大的待办事项列表,然后选择十个项目,对它们进行操作,然后选择接下来的十个项目。没有并行化


如果您提供更多详细信息,我相信我们可以帮助您。

GNU make和其他实现可能也有-j参数,该参数控制它将同时运行多少个作业。当一项工作完成后,make将开始另一项工作。

好吧,如果它们在很大程度上相互独立,我会从以下方面考虑:

Initialize an array of jobs pending (queue, ...) - 200 entries
Initialize an array of jobs running - empty

while (jobs still pending and queue of jobs running still has space)
    take a job off the pending queue
    launch it in background
    if (queue of jobs running is full)
        wait for a job to finish
        remove from jobs running queue
while (queue of jobs is not empty)
    wait for job to finish
    remove from jobs running queue
请注意,主循环中的尾部测试意味着当while循环迭代时,如果“jobs running queue”有空间,则可以防止循环过早终止。我认为逻辑是正确的

我可以很容易地在C语言中看到如何做到这一点-在Perl中也不会那么难,因此在其他脚本语言中也不会太难-Python、Ruby、Tcl等。我根本不确定我是否想在shell中完成它-shell中的wait命令等待所有子脚本终止,xargs可以用于对并行命令处理进行排队,而不是让某些子进程终止。

在shell上。例如,始终并行进行3次睡眠,每次睡眠1秒,总共执行10次睡眠

echo {1..10} | xargs -d ' ' -n1 -P3 sh -c 'sleep 1s' _
它总共会睡4秒钟。如果您有一个名称列表,并且希望将名称传递给已执行的命令,再次并行执行3个命令,请执行以下操作:

cat names | xargs -n1 -P3 process_name

将执行命令process\u name alice、process\u name bob等等。

我想您可以使用make和make-j xx命令来执行此操作

也许像这样的makefile

all : usera userb userc....

usera:
       imapsync usera
userb:
       imapsync userb
....

在python中,make-j 10-f makefile

,您可以尝试:

import Queue, os, threading

# synchronised queue
queue = Queue.Queue(0)    # 0 means no maximum size

# do stuff to initialise queue with strings
# representing os commands
queue.put('sleep 10')
queue.put('echo Sleeping..')
# etc
# or use python to generate commands, e.g.
# for username in ['joe', 'bob', 'fred']:
#    queue.put('imapsync %s' % username)

def go():
  while True:
    try:
      # False here means no blocking: raise exception if queue empty
      command = queue.get(False)
      # Run command.  python also has subprocess module which is more
      # featureful but I am not very familiar with it.
      # os.system is easy :-)
      os.system(command)
    except Queue.Empty:
      return

for i in range(10):   # change this to run more/fewer threads
  threading.Thread(target=go).start()
未经测试的


当然,python本身是单线程的。不过,在等待IO方面,您仍然可以从多线程中获益。

Python似乎很适合您的问题。这是一个支持进程线程的高级包。

对于这种作业,PPSS编写了:并行处理shell脚本。用谷歌搜索这个名字,你会找到的,我不会链接垃圾邮件。

就是为了这个目的而做的

cat userlist | parallel imapsync
与其他解决方案相比,该解决方案的优点之一是它确保了输出不会混合。在工作中执行跟踪路由很好,例如:

(echo foss.org.my; echo www.debian.org; echo www.freenetproject.org) | parallel traceroute
gnu并行
pssh可能会有所帮助。

zsh中的简单函数使用/tmp中的锁文件,在不超过4个子shell中并行化作业

唯一重要的部分是第一次测试中的glob标志:

q:在测试中启用文件名全局绑定 [4] :仅返回第四个结果 N:忽略空结果上的错误 将其转换为posix应该很容易,不过会有点冗长

不要忘记用\来转义作业中的任何引号


这正是我所希望的。我编写了一些代码来生成Makefile。结果超过了1000行。谢谢我发现,如果任何命令退出时带有错误代码,make将退出,从而阻止将来作业的执行。在某些情况下,此解决方案并不理想。对此方案有何建议?@redmoskito如果您使用-k选项运行make,即使出现错误,它也会继续运行。如果您开始认为make不是任务调度器,而是并行编译工具。。我想更大的情况是“make-j”尊重依赖性,这使得这个解决方案一旦被普遍应用,就会令人振奋。1 os.system可以被新的改进的子流程模块所取代。2 CPython是否有GIL并不重要,因为您运行的是外部命令,而不是Python代码funct
如果将threading.Thread替换为multiprocessing.Process,将Queue替换为multiprocessing.Queue,那么代码将使用多个进程运行。pssh是用python编写的,我认为这看起来很理想。下次遇到类似问题时,我会检查一下。谢谢你用你的推荐更新这个帖子。太棒了!我们可以设置动态线程,例如80%的CPU/Ram允许吗?几乎正是我想要的/我又开始努力工作了,伙计,我喜欢这个工具。我知道它已经有3个小时了,我会一直使用它,直到地球上的石头都喊着让我停下来。Fedora 16将该工具包含在package Repository哇,我一直在使用xargs,从没想过它会有这个选项!对于您给出的第二个示例,如何修改该命令,使process_name可以接受多个参数?我想这样做:cat commands.txt | xargs-n1-P3 eval,commands.txt中有一组命令,每行一个,每个命令都有多个参数。问题是eval不起作用,因为它是一个内置的shellcommand@Eddy尝试使用shell作为要运行的程序;这允许您使用任意shell命令作为输入。上面的第一个答案是用sh实现的,但是也可以用bash实现。例如,如果commands.txt中有一堆看起来像echo test1的行;sleep1,您可以通过cat commands.txt | xargs-d'\n'-P3-n1/bin/bash-cyou等方式使用它,您也可以对特定的子进程使用wait命令。它可以被赋予任意数量的参数,每个参数都可以是pid或作业id。@BrianMinton:你可以用wait列出特定的pid,这是对的,但是你仍然会得到“所有pid都死了”的行为,而不是“第一个死了”的行为,这正是代码真正需要的。
#!/bin/zsh

setopt extendedglob

para() {
    lock=/tmp/para_$$_$((paracnt++))
    # sleep as long as the 4th lock file exists
    until [[ -z /tmp/para_$$_*(#q[4]N) ]] { sleep 0.1 }
    # Launch the job in a subshell
    ( touch $lock ; eval $* ; rm $lock ) &
    # Wait for subshell start and lock creation
    until [[ -f $lock ]] { sleep 0.001 }
}

para "print A0; sleep 1; print Z0"
para "print A1; sleep 2; print Z1"
para "print A2; sleep 3; print Z2"
para "print A3; sleep 4; print Z3"
para "print A4; sleep 3; print Z4"
para "print A5; sleep 2; print Z5"

# wait for all subshells to terminate
wait