45

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

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

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

有没有人有代码来解决这个问题?

进一步阐述:

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

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

4

12 回答 12

45

在shell 上,xargs可用于队列并行命令处理。例如,总是有 3 个并行睡眠,每个睡眠 1 秒,总共执行 10 个睡眠

echo {1..10} | xargs -d ' ' -n1 -P3 sh -c 'sleep 1s' _

它总共会睡4秒钟。如果您有一个名称列表,并且想将名称传递给执行的命令,请再次并行执行 3 个命令,执行

cat names | xargs -n1 -P3 process_name

将执行命令process_name aliceprocess_name bob依此类推。

于 2009-01-21T03:53:00.787 回答
41

我想你可以使用 make 和 make -j xx 命令来做到这一点。

也许像这样的makefile

all : usera userb userc....

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

make -j 10 -f 生成文件

于 2009-01-21T03:58:50.900 回答
28

并行正是为此目的而设计的。

cat userlist | parallel imapsync

与其他解决方案相比, Parallel的优点之一是它确保输出不会混合。并行traceroute工作很好,例如:

(echo foss.org.my; echo www.debian.org; echo www.freenetproject.org) | parallel traceroute
于 2010-01-27T17:00:56.533 回答
13

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

于 2009-03-10T00:31:35.383 回答
7

GNU make(也许还有其他实现)有 -j 参数,它控制一次将运行多少个作业。当一个工作完成后,make 会开始另一个工作。

于 2009-01-21T03:31:22.437 回答
4

好吧,如果它们在很大程度上彼此独立,我会考虑:

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 循环迭代时有空间 - 防止循环过早终止。我认为逻辑是合理的。

我可以很容易地看到如何在 C 中做到这一点——在 Perl 中也不会那么难(因此在其他脚本语言中也不是太难——Python、Ruby、Tcl 等)。我完全不确定我是否想在 shell 中执行此操作 - shell 中的wait命令等待所有子进程终止,而不是等待某个子进程终止。

于 2009-01-21T03:34:12.930 回答
3

如果你打算使用 Python,我推荐使用Twisted

特别是 Twisted Runner

于 2009-01-21T02:59:40.830 回答
3

在python中,您可以尝试:

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 方面,您仍然应该受益于多线程。)

于 2009-01-21T03:59:01.007 回答
2

https://savannah.gnu.org/projects/parallel(gnu并行)和 pssh 可能会有所帮助。

于 2011-08-29T22:30:14.210 回答
1

Python 的多处理模块似乎很适合您的问题。它是一个支持进程线程的高级包。

于 2009-01-21T04:10:43.420 回答
0

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

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

  • #q: 在测试中启用文件名通配符
  • [4]: 只返回第四个结果
  • N:忽略空结果的错误

将其转换为 posix 应该很容易,尽管它会更冗长一些。

不要忘记使用\".

#!/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
于 2017-09-13T16:36:09.040 回答
-3

您能否详细说明并行的含义?听起来您需要在队列中实现某种锁定,这样您的条目就不会被选择两次,等等,并且命令只运行一次。

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

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

于 2009-01-21T03:08:43.060 回答