layout: post
title: Bash脚本实现批量作业并行化
categories:
在Linux下运行作业时, 经常会遇到以下情形: 有大量作业需要运行, 完成每个作业所需要的时间也不是很长. 如果我们以串行方式来运行这些作业, 可能要耗费较长的时间; 若采用并行方式运行则可以大大节约运行时间. 再者, 目前的计算机绝大部分都是多核架构, 要想充分发挥它们的计算能力也需要并行化. 总结网上看到的资料, 利用Bash脚本, 可以采用下面几种方法实现批量作业的并行化. 注意, 下面论述中将不会区分进程和线程, 也不会区分并行和并发.
1. 采用GNU的paralle程序
parallel是GNU专门用于并行化的一个程序, 对于简单的批量作业并行化非常合适. 使用parallel不需要编写脚本, 只需在原命令的基础上简单地加上parallel就可以了. 所以, 如果能用paralle并行化你的作业, 请优先使用. 有关paralle的详细说明, 请参考其官方文档.
2. 最简单的并行化方法: &+wait
利用Bash的后台运行&
和wait
函数, 可实现最简单的批量作业并行化.
如下面的代码, 串行执行大约需要10秒
<table class="highlighttable"><th colspan="2" style="text-align:left">bash</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height: 125%">1
2
3
4</pre></div></td><td class="code"><div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #AA22FF; font-weight: bold">for</span><span style="color: #666666">((</span><span style="color: #B8860B">i</span><span style="color: #666666">=</span>1; i<<span style="color: #666666">=</span>3; i++<span style="color: #666666">))</span>; <span style="color: #AA22FF; font-weight: bold">do</span> <span style="color: #666666">{</span>
sleep 3
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"DONE!"</span>
<span style="color: #666666">}</span> <span style="color: #AA22FF; font-weight: bold">done</span>
</pre></div>
</td></tr></table>
改为下面的简单并行代码理想情况下可将运行时间压缩到3秒左右
<table class="highlighttable"><th colspan="2" style="text-align:left">bash</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height: 125%">1
2
3
4
5</pre></div></td><td class="code"><div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #AA22FF; font-weight: bold">for</span><span style="color: #666666">((</span><span style="color: #B8860B">i</span><span style="color: #666666">=</span>1; i<<span style="color: #666666">=</span>3; i++<span style="color: #666666">))</span>; <span style="color: #AA22FF; font-weight: bold">do</span> <span style="color: #666666">{</span>
sleep 3
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"DONE!"</span>
<span style="color: #666666">}</span> & <span style="color: #AA22FF; font-weight: bold">done</span>
<span style="color: #AA22FF">wait</span>
</pre></div>
</td></tr></table>
### 3. 进程数可控的并行化方法(1): 模拟队列
使用Bash脚本同时运行多个进程并无困难, 主要存在的问题是如何控制同时运行的进程数目. 上面的简单并行化方法使用时进程数无法控制, 因而功能有限, 因为大多数时候我们需要运行的作业数远远超过可用处理器数, 这种情况下若大量作业同时在后台运行, 会导致运行速度变慢, 并行效率大大下降. 一种简单的解决方案就是模拟一个限定最大进程数的队列, 以进程PID做为队列元素, 每隔一定时间检查队列, 若队列中有作业完成, 则添加新的作业到队列中. 这种方法还可以避免由于不同作业耗时不同而产生的无用等待. 下面是根据网上的代码改写的一种实现. 实用性更强的代码, 请参考原文.
<table class="highlighttable"><th colspan="2" style="text-align:left">bash</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height: 125%"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41</pre></div></td><td class="code"><div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #B8860B">Njob</span><span style="color: #666666">=10</span> <span style="color: #008800; font-style: italic"># 作业数目</span>
<span style="color: #B8860B">Nproc</span><span style="color: #666666">=5</span> <span style="color: #008800; font-style: italic"># 可同时运行的最大作业数</span>
<span style="color: #AA22FF; font-weight: bold">function</span> CMD <span style="color: #666666">{</span> <span style="color: #008800; font-style: italic"># 测试命令, 随机等待几秒钟</span>
<span style="color: #B8860B">n</span><span style="color: #666666">=</span><span style="color: #AA22FF; font-weight: bold">$((</span>RANDOM <span style="color: #666666">%</span> <span style="color: #666666">5</span> <span style="color: #666666">+</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">))</span>
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"Job </span><span style="color: #B8860B">$1</span><span style="color: #BB4444"> Ijob </span><span style="color: #B8860B">$2</span><span style="color: #BB4444"> sleeping for </span>$<span style="color: #BB4444">n seconds ..."</span>
sleep $n
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"Job </span><span style="color: #B8860B">$1</span><span style="color: #BB4444"> Ijob </span><span style="color: #B8860B">$2</span><span style="color: #BB4444"> exiting ..."</span>
<span style="color: #666666">}</span>
<span style="color: #AA22FF; font-weight: bold">function</span> PushQue <span style="color: #666666">{</span> <span style="color: #008800; font-style: italic"># 将PID压入队列</span>
<span style="color: #B8860B">Que</span><span style="color: #666666">=</span><span style="color: #BB4444">"</span>$<span style="color: #BB4444">Que </span><span style="color: #B8860B">$1</span><span style="color: #BB4444">"</span>
<span style="color: #B8860B">Nrun</span><span style="color: #666666">=</span><span style="color: #AA22FF; font-weight: bold">$((</span>$Nrun+1<span style="color: #AA22FF; font-weight: bold">))</span>
<span style="color: #666666">}</span>
<span style="color: #AA22FF; font-weight: bold">function</span> GenQue <span style="color: #666666">{</span> <span style="color: #008800; font-style: italic"># 更新队列</span>
<span style="color: #B8860B">OldQue</span><span style="color: #666666">=</span>$Que
<span style="color: #B8860B">Que</span><span style="color: #666666">=</span><span style="color: #BB4444">""</span>; <span style="color: #B8860B">Nrun</span><span style="color: #666666">=</span>0
<span style="color: #AA22FF; font-weight: bold">for</span> PID in $OldQue; <span style="color: #AA22FF; font-weight: bold">do</span>
<span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #666666">[[</span> -d /proc/$PID <span style="color: #666666">]]</span>; <span style="color: #AA22FF; font-weight: bold">then</span>
PushQue $PID
<span style="color: #AA22FF; font-weight: bold">fi</span>
<span style="color: #AA22FF; font-weight: bold">done</span>
<span style="color: #666666">}</span>
<span style="color: #AA22FF; font-weight: bold">function</span> ChkQue <span style="color: #666666">{</span> <span style="color: #008800; font-style: italic"># 检查队列</span>
<span style="color: #B8860B">OldQue</span><span style="color: #666666">=</span>$Que
<span style="color: #AA22FF; font-weight: bold">for</span> PID in $OldQue; <span style="color: #AA22FF; font-weight: bold">do</span>
<span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #666666">[[</span> ! -d /proc/$PID <span style="color: #666666">]]</span> ; <span style="color: #AA22FF; font-weight: bold">then</span>
GenQue; <span style="color: #AA22FF">break</span>
<span style="color: #AA22FF; font-weight: bold">fi</span>
<span style="color: #AA22FF; font-weight: bold">done</span>
<span style="color: #666666">}</span>
<span style="color: #AA22FF; font-weight: bold">for</span><span style="color: #666666">((</span><span style="color: #B8860B">i</span><span style="color: #666666">=</span>1; i<<span style="color: #666666">=</span>$Njob; i++<span style="color: #666666">))</span>; <span style="color: #AA22FF; font-weight: bold">do</span>
CMD $i &
<span style="color: #B8860B">PID</span><span style="color: #666666">=</span><span style="color: #B8860B">$!</span>
PushQue $PID
<span style="color: #AA22FF; font-weight: bold">while</span> <span style="color: #666666">[[</span> $Nrun -ge $Nproc <span style="color: #666666">]]</span>; <span style="color: #AA22FF; font-weight: bold">do</span>
ChkQue
sleep 1
<span style="color: #AA22FF; font-weight: bold">done</span>
<span style="color: #AA22FF; font-weight: bold">done</span>
<span style="color: #AA22FF">wait</span>
</pre></div>
</td></tr></table>
一个更简洁的方法是记录PID到数组, 通过检查PID存在与否以确定作业是否运行完毕. 可实现如下
<table class="highlighttable"><th colspan="2" style="text-align:left">bash</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height: 125%"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25</pre></div></td><td class="code"><div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #B8860B">Njob</span><span style="color: #666666">=10</span> <span style="color: #008800; font-style: italic"># 作业数目</span>
<span style="color: #B8860B">Nproc</span><span style="color: #666666">=5</span> <span style="color: #008800; font-style: italic"># 可同时运行的最大作业数</span>
<span style="color: #AA22FF; font-weight: bold">function</span> CMD <span style="color: #666666">{</span> <span style="color: #008800; font-style: italic"># 测试命令, 随机等待几秒钟</span>
<span style="color: #B8860B">n</span><span style="color: #666666">=</span><span style="color: #AA22FF; font-weight: bold">$((</span>RANDOM <span style="color: #666666">%</span> <span style="color: #666666">5</span> <span style="color: #666666">+</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">))</span>
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"Job </span><span style="color: #B8860B">$1</span><span style="color: #BB4444"> Ijob </span><span style="color: #B8860B">$2</span><span style="color: #BB4444"> sleeping for </span>$<span style="color: #BB4444">n seconds ..."</span>
sleep $n
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"Job </span><span style="color: #B8860B">$1</span><span style="color: #BB4444"> Ijob </span><span style="color: #B8860B">$2</span><span style="color: #BB4444"> exiting ..."</span>
<span style="color: #666666">}</span>
<span style="color: #B8860B">PID</span><span style="color: #666666">=()</span> <span style="color: #008800; font-style: italic"># 记录PID到数组, 检查PID是否存在以确定是否运行完毕</span>
<span style="color: #AA22FF; font-weight: bold">for</span><span style="color: #666666">((</span><span style="color: #B8860B">i</span><span style="color: #666666">=</span>1; i<<span style="color: #666666">=</span>Njob; <span style="color: #666666">))</span>; <span style="color: #AA22FF; font-weight: bold">do</span>
<span style="color: #AA22FF; font-weight: bold">for</span><span style="color: #666666">((</span><span style="color: #B8860B">Ijob</span><span style="color: #666666">=</span>0; Ijob<Nproc; Ijob++<span style="color: #666666">))</span>; <span style="color: #AA22FF; font-weight: bold">do</span>
<span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #666666">[[</span> $i -gt $Njob <span style="color: #666666">]]</span>; <span style="color: #AA22FF; font-weight: bold">then</span>
break;
<span style="color: #AA22FF; font-weight: bold">fi</span>
<span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #666666">[[</span> ! <span style="color: #BB4444">"</span><span style="color: #BB6688; font-weight: bold">${</span><span style="color: #B8860B">PID</span>[Ijob]<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BB4444">"</span> <span style="color: #666666">]]</span> <span style="color: #666666">||</span> ! <span style="color: #AA22FF">kill</span> -0 <span style="color: #BB6688; font-weight: bold">${</span><span style="color: #B8860B">PID</span>[Ijob]<span style="color: #BB6688; font-weight: bold">}</span> 2> /dev/null; <span style="color: #AA22FF; font-weight: bold">then</span>
CMD $i $Ijob &
PID<span style="color: #666666">[</span>Ijob<span style="color: #666666">]=</span><span style="color: #B8860B">$!</span>
<span style="color: #B8860B">i</span><span style="color: #666666">=</span><span style="color: #AA22FF; font-weight: bold">$((</span>i+1<span style="color: #AA22FF; font-weight: bold">))</span>
<span style="color: #AA22FF; font-weight: bold">fi</span>
<span style="color: #AA22FF; font-weight: bold">done</span>
sleep 1
<span style="color: #AA22FF; font-weight: bold">done</span>
<span style="color: #AA22FF">wait</span>
</pre></div>
</td></tr></table>
### 3. 进程数可控的并行化方法(2): 命名管道
上面的并行化方法也可利用命名管道来实现, 命名管道是Linux下进程间进行通讯的一种方法, 也称为先入先出(fifo, first in first out)文件. 具体方法是创建一个fifo文件, 作为进程池, 里面存放一定数目的"令牌". 作业运行规则如下: 所有作业排队依次领取令牌; 每个作业运行前从进程池中领取一块令牌, 完成后再归还令牌; 当进程池中没有令牌时, 要运行的作业只能等待. 这样就能保证同时运行的作业数等于令牌数. 前面的模拟队列方法实际就是以PID作为令牌的实现.
据我已查看的资料, 这种方法在网络上讨论最多. 实现也很简洁, 但理解其代码需要的Linux知识较多. 下面是我改写的示例代码及其注释.
<table class="highlighttable"><th colspan="2" style="text-align:left">bash</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height: 125%"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41</pre></div></td><td class="code"><div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #B8860B">Njob</span><span style="color: #666666">=10</span> <span style="color: #008800; font-style: italic"># 作业数目</span>
<span style="color: #B8860B">Nproc</span><span style="color: #666666">=5</span> <span style="color: #008800; font-style: italic"># 可同时运行的最大作业数</span>
<span style="color: #AA22FF; font-weight: bold">function</span> CMD <span style="color: #666666">{</span> <span style="color: #008800; font-style: italic"># 测试命令, 随机等待几秒钟</span>
<span style="color: #B8860B">n</span><span style="color: #666666">=</span><span style="color: #AA22FF; font-weight: bold">$((</span>RANDOM <span style="color: #666666">%</span> <span style="color: #666666">5</span> <span style="color: #666666">+</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">))</span>
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"Job </span><span style="color: #B8860B">$1</span><span style="color: #BB4444"> Ijob </span><span style="color: #B8860B">$2</span><span style="color: #BB4444"> sleeping for </span>$<span style="color: #BB4444">n seconds ..."</span>
sleep $n
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"Job </span><span style="color: #B8860B">$1</span><span style="color: #BB4444"> Ijob </span><span style="color: #B8860B">$2</span><span style="color: #BB4444"> exiting ..."</span>
<span style="color: #666666">}</span>
<span style="color: #B8860B">Pfifo</span><span style="color: #666666">=</span><span style="color: #BB4444">"/tmp/</span><span style="color: #B8860B">$$</span><span style="color: #BB4444">.fifo"</span> <span style="color: #008800; font-style: italic"># 以PID为名, 防止创建命名管道时与已有文件重名,从而失败</span>
mkfifo $Pfifo <span style="color: #008800; font-style: italic"># 创建命名管道</span>
<span style="color: #AA22FF">exec</span> 6<>$Pfifo <span style="color: #008800; font-style: italic"># 以读写方式打开命名管道, 文件标识符fd为6</span>
<span style="color: #008800; font-style: italic"># fd可取除0, 1, 2,5外0-9中的任意数字</span>
rm -f $Pfifo <span style="color: #008800; font-style: italic"># 删除文件, 也可不删除, 不影响后面操作</span>
<span style="color: #008800; font-style: italic"># 在fd6中放置$Nproc个空行作为令牌</span>
<span style="color: #AA22FF; font-weight: bold">for</span><span style="color: #666666">((</span><span style="color: #B8860B">i</span><span style="color: #666666">=</span>1; i<<span style="color: #666666">=</span>$Nproc; i++<span style="color: #666666">))</span>; <span style="color: #AA22FF; font-weight: bold">do</span>
<span style="color: #AA22FF">echo</span>
<span style="color: #AA22FF; font-weight: bold">done</span> >&6
<span style="color: #AA22FF; font-weight: bold">for</span><span style="color: #666666">((</span><span style="color: #B8860B">i</span><span style="color: #666666">=</span>1; i<<span style="color: #666666">=</span>$Njob; i++<span style="color: #666666">))</span>; <span style="color: #AA22FF; font-weight: bold">do</span> <span style="color: #008800; font-style: italic"># 依次提交作业</span>
<span style="color: #AA22FF">read</span> -u6 <span style="color: #008800; font-style: italic"># 领取令牌, 即从fd6中读取行, 每次一行</span>
<span style="color: #008800; font-style: italic"># 对管道,读一行便少一行,每次只能读取一行</span>
<span style="color: #008800; font-style: italic"># 所有行读取完毕, 执行挂起, 直到管道再次有可读行</span>
<span style="color: #008800; font-style: italic"># 因此实现了进程数量控制</span>
<span style="color: #666666">{</span> <span style="color: #008800; font-style: italic"># 要批量执行的命令放在大括号内, 后台运行</span>
CMD $i <span style="color: #666666">&&</span> <span style="color: #666666">{</span> <span style="color: #008800; font-style: italic"># 可使用判断子进程成功与否的语句</span>
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"Job </span>$<span style="color: #BB4444">i finished"</span>
<span style="color: #666666">}</span> <span style="color: #666666">||</span> <span style="color: #666666">{</span>
<span style="color: #AA22FF">echo</span> <span style="color: #BB4444">"Job </span>$<span style="color: #BB4444">i error"</span>
<span style="color: #666666">}</span>
sleep <span style="color: #666666">1</span> <span style="color: #008800; font-style: italic"># 暂停1秒,可根据需要适当延长,</span>
<span style="color: #008800; font-style: italic"># 关键点,给系统缓冲时间,达到限制并行进程数量的作用</span>
<span style="color: #AA22FF">echo</span> >&<span style="color: #666666">6</span> <span style="color: #008800; font-style: italic"># 归还令牌, 即进程结束后,再写入一行,使挂起的循环继续执行</span>
<span style="color: #666666">}</span> &
<span style="color: #AA22FF; font-weight: bold">done</span>
<span style="color: #AA22FF">wait</span> <span style="color: #008800; font-style: italic"># 等待所有的后台子进程结束</span>
<span style="color: #AA22FF">exec</span> 6>&- <span style="color: #008800; font-style: italic"># 删除文件标识符</span>
</pre></div>
</td></tr></table>
注意:
(1) `exec 6<>$Pfifo` 这一句很重要, 若无此语句, 向`$Pfifo`写入数据时, 程序会被阻塞, 直到有read读出了文件中的数据为止. 而执行了此语句, 就可以在程序运行期间不断向文件写入数据而不会阻塞, 并且数据会被保存下来以供read读出.
(2) 当`$Pfifo`中已经没有数据时, read无法读到数据, 进程会被阻塞在read操作上, 直到有子进程运行结束, 向`$Pfifo`写入一行.
(3) 核心执行部分也可使用如下方式
<table class="highlighttable"><th colspan="2" style="text-align:left">bash</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height: 125%">1
2
3
4</pre></div></td><td class="code"><div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #AA22FF; font-weight: bold">for</span><span style="color: #666666">((</span><span style="color: #B8860B">i</span><span style="color: #666666">=</span>1; i<<span style="color: #666666">=</span>$Njob; i++<span style="color: #666666">))</span>; <span style="color: #AA22FF; font-weight: bold">do</span>
<span style="color: #AA22FF">read</span> -u6
<span style="color: #666666">(</span>CMD $i; sleep 1; <span style="color: #AA22FF">echo</span> >&6<span style="color: #666666">)</span> &
<span style="color: #AA22FF; font-weight: bold">done</span>
</pre></div>
</td></tr></table>{}和()的区别在shell是否会衍生子进程
(4) 此方法在目前的Cygwin(版本1.7.27)下无法使用, 因其不支持双向命名管道. 有人提到一个解决方案, 使用两个文件描述符来替代单个文件描述符, 但此方法我没有测试成功.
参考资料
简洁的模拟队列方法实现
shell里如何实现"多线程"?
模拟队列方法, 实用性更强的代码
A srcipt for running processes in parallel in Bash
- 命名管道方法及其解释
- Cygwin下双向命名管道的问题: bi-directional named pipe
评论
- 2015-06-16 13:30:38
waventropy
非常赞的脚本!在本地实验室的机群上必须这样写代码不然所有的资源就独占了,同时别人也无法使用这些资源。一般来说,大部分人如果只是偶尔使用服务器是不会先top查看下服务器的负载的。这样的脚本就会很有用了!
- 2015-06-16 15:06:35
waventropy
很好用的脚本,可以尽情地在服务器上玩耍了。
2015-06-16 21:32:02 Jerkwin
如果发现有什么问题或不足的话, 欢迎指出.
2015-06-19 15:57:22 waventropy
针对第三种方法,有一个疑问,我就是用的这种方法,是不是一定要保证Linux的文件描述符不同样?
比如我同时运行两个脚本job1.sh和job2.sh,那么是不是一定要保证文件标识符fd为6改变?比如job1.sh用6,job2.sh必须改为7?
Pfifo="/tmp/$$.fifo" # 以PID为名, 防止创建命名管道时与已有文件重名,从而失败
mkfifo $Pfifo # 创建命名管道
exec 6<>$Pfifo # 以读写方式打开命名管道, 文件标识符fd为6
- 2015-06-19 21:09:17
Jerkwin
你说的对, 应该使用不同的文件标识符, 否则的话会冲突, 两个脚本同时运行时会出现问题.
- 2015-06-24 10:54:48
waventropy
对,主要就是比如50个任务,一个节点15个核,我在这个节点利用15个核跑脚本。那么另外的一个节点,期望中应该也可以用同样的方法跑出结果,但是却出现了错误。我排查就是这个描述符的问题。
正在修改,但是感觉还是会有错误。
不确定具体原因。
- 2015-06-24 20:35:03
Jerkwin
如果你把文件存在运行节点上, 我觉得应该没有问题. 如果你把文件保存在当前节点, 那就会出问题.
- 2015-06-24 10:55:15
waventropy
我重新再做测试下
- 2015-06-24 20:36:22
Jerkwin
好, 如果还不能解决问题的话, 可以把脚本发给我看看: Jerkwin@gmail.com
2017-04-27 12:01:42 Terry_Zheng
每个进程打开的 FD,对于每个进程都是独立的,各自用各自的文件描述符。每个进程都会打开0、1、2 这 3 个 FD,/proc/${PID}/fd/ 目录下能看到 ${PID} 这个进程打开的文件描述符。
2015-06-24 11:00:14 waventropy
对了,举报一个抄袭不给出出处的网站。http://www.linuxidc.com/Linux/2015-01/112363.htm,内容完全一致
2015-06-24 20:38:02 Jerkwin
嗯, 那个版本是发在科学网上的: http://blog.sciencenet.cn/blog-548663-750136.html
2015-07-06 16:44:14 magicmonk
请问vasp任务的提交也可以这样做吗?应该如何修改脚本?
2015-07-06 20:02:26 Jerkwin
这是并行方法, 和运行什么任务无关. vasp的话, 你需要先设计好如何单独运行vasp, 然后将运行的代码放到并行的任务代码中即可.
2015-08-16 09:03:17 日月人依依
博主,通报一个方法吧!
安装一个PBS软件服务就行,比如我们实验室用的就是PBS: Portable Batch System,有一个非常不错的开源版本实现torque。
周五的ReadHat的工程师安装了然后就可以联合14个节点,自动分布任务。推荐使用下,看工程师安装的过程应该是比较简单的,如果安装了NIS更加方便。
昨天熬了一夜终于提交了所有的任务,可以调动各个节点的各个资源,自动分布调度,同时会把结果mail给各个用户。
- 2015-08-16 09:10:01
日月人依依
借助PBS配合自己的脚本的话,就可以批量作业,同时多出来的程序自动排队。
- 2015-08-16 14:46:44
Jerkwin
嗯, PBS系统大部分集群都使用的, 可以算作大粒度的并行, 这里说的是小粒度的并行, 两者不冲突, 要根据自己的具体情况确定来使用. 有时在PBS系统内部还会使用并行.
- 2015-08-16 14:49:00
Jerkwin
如果你要花一夜来提交任务的话, 那我建议你仔细研究下如何使用通用脚本来提交任务. 如果每个任务都要单独写一个PBS脚本来提交的话, 任务多了就很麻烦.
2015-08-19 09:30:33 日月人依依
没有,一夜是装这个服务的时间,对,最后确实是需要脚本来提交的。
2016-01-04 16:47:48 dreamaster
拜读了,但发现freebsd不支持read -u,有何替代手段呢?请赐教,谢谢!
- 2016-01-04 23:17:35
Jerkwin
我没用过freebsd, 不清楚. 不过建议你优先考虑使用parallel, 再试试模拟队列的方法.