我遇到过一些类似的情况,我可以将单核绑定任务分解为多个部分,并将每个部分作为单独的作业在 bash 中运行以将其并行化,但我很难将返回的数据整理回单个数据溪流。到目前为止,我的天真的方法必须创建一个临时文件夹,跟踪 PID,让每个线程使用其 pid 写入文件,然后在所有作业完成后读取所有 pid 并将它们按 PID 生成的顺序合并到一个文件中。有没有更好的方法来使用 bash/shell 工具来处理这种多入一出的情况?
我有一个makefile,想确保所有的规则都是按顺序执行的,也就是说,没有并行执行。
我相信我有三种方法可以实现这一目标:
- 有
.NOTPARALLEL
目标, - 通过调用
make
usingmake -j 1
, - 通过直接在 makefile 中设置标志,例如,
MAKEFLAGS := -j 1
这三者之间是否存在“最佳实践”,哪一个更强大?
例如,这样做是不是有点矫枉过正?
MAKEFLAGS := --jobs=1
.NOTPARALLEL:
all:foo bar
.NOTPARALLEL:
foo:bar
.NOTPARALLEL:
bar:
@echo "test"
?
在 Linux Mint 20.2 Cinnamon 上,我想创建包含 Windows 10 的辅助磁盘驱动器 (SATA) 的磁盘映像,现在并不重要,直接gzip
使用Parallel gzip
=pigz
编辑到 NTFS 格式的外部 HDD 上(即时压缩)。
我的问题是在生成的压缩文件中,内容的大小有些扭曲(错误),我希望您看看:
1TB 驱动器未压缩磁盘仅显示 3.8GB,而其压缩大小为 193 GB。
$ gzip --list sata-disk--windows10--2021-Sep-24.img.gz
compressed uncompressed ratio uncompressed_name
206222131640 3772473344 -5366.5% sata-disk--windows10--2021-Sep-24.img
-rwxrwxrwx 1 vlastimil vlastimil 193G 2021-Sep-24 sata-disk--windows10--2021-Sep-24.img.gz
我刚刚运行的以下 shell 片段的注释
序列号被删减,当然 (
ABCDEFGHIJKLMNO
)我试图用
--size
ofpv
命令强制大小整个磁盘的确切字节大小来自
smartctl -i /dev/sdX
我刚刚运行的 shell 片段如下
dev=/dev/disk/by-id/ata-Samsung_SSD_870_QVO_1TB_ABCDEFGHIJKLMNO; \
file=/media/vlastimil/4TB_Seagate_NTFS/Backups/sata-disk--windows10--"$(date +%Y-%b-%d)".img.gz; \
pv --size 1000204886016 < "$dev" | pigz -9 > "$file"
我很确定问题出在我如何使用管道或pv
就此而言,但我无法证明这一点。使用常规文件 (~2GB) 的测试场景可以正常工作并且符合预期。这可能是一个错误gzip
...?
请问我在这里做错了什么?先感谢您。
也许最后要介绍的是pv
and的版本pigz
:
我使用的是打包版本
pv
:1.6.6-1我正在使用的编译版本
pigz
:2.6
我出于无聊创建了这个脚本,其唯一目的是使用/测试 GNU 并行,所以我知道它不是特别有用或优化,但我有一个脚本可以计算所有质数,直到 n:
#!/usr/bin/env bash
isprime () {
local n=$1
((n==1)) && return 1
for ((i=2;i<n;i++)); do
if ((n%i==0)); then
return 1
fi
done
printf '%d\n' "$n"
}
for ((f=1;f<=$1;f++)); do
isprime "$f"
done
使用循环运行时:
$ time ./script.sh 5000 >/dev/null
real 0m28.875s
user 0m38.818s
sys 0m29.628s
我希望用 GNU 并行替换 for 循环会使它运行得更快,但这不是我的经验。平均而言,它只快了大约 1 秒:
#!/usr/bin/env bash
isprime () {
local n=$1
((n==1)) && return 1
for ((i=2;i<n;i++)); do
if ((n%i==0)); then
return 1
fi
done
printf '%d\n' "$n"
}
export -f isprime
seq 1 $1 | parallel -j 20 -N 1 isprime {}
并行运行:
$ time ./script.sh 5000 >/dev/null
real 0m27.655s
user 0m38.145s
sys 0m28.774s
我对优化isprime()
函数并不感兴趣,我只是想知道是否可以做些什么来优化 GNU 并行?
在我的测试seq
中实际上运行得比运行时更快,for ((i=1...))
所以我认为这与运行时没有太大关系
有趣的是,如果我将 for 循环修改为:
for ((f=1;f<=$1;f++)); do
isprime "$f" &
done | sort -n
它运行得更快:
$ time ./script.sh 5000 >/dev/null
real 0m5.995s
user 0m33.229s
sys 0m6.382s
我想以下列方式运行任务 a_1、a_2、b_1、b_2、c_1、c_2:a_i、b_j、c_k(其中 i、j、k 为 0 或 1)可以并行运行。但是 a_2 应该在 a_1 完成后立即运行(它们使用相同的资源,因此 a_2 应该等待 a_1 释放资源)。与 b、c 相同。
我怎样才能在 bash 中做到这一点?
我试图通过一个简单的示例来了解 shell 脚本中的并行处理以及在输出中确定性地(无随机顺序)顺序附加值。下面是代码片段:
x=""
appendnum() {
num=$1; x=`echo $x$num`
}
for no in {0..10}
do
appendnum $no &
done
wait $(jobs -rp)
echo $x
预期的输出是 012345678910,但它会产生一个空值。我什至尝试迭代 PID 以等待它完成,但没有成功。我希望主线程等到每个并行进程完成。附加数字只是一个例子。
我的问题陈述如下所示:考虑到我有 3 个任务,我想要响应列表,例如[responseof(task1),responseof(task2),responseof(task3)]
. 任务数最多可达到 50 个。无论任务数如何,我的响应时间都应该相同。这样做的最有效和正确的方法是什么?
我想运行一个任务,在其中我指定两个命令,这些命令将以不同的参数交替运行。例如:
1. exec --foo $inputfile1 $inputfile.outfile1
2. exec --bar $inputfile2 $inputfile.outfile2
3. exec --foo $inputfile3 $inputfile.outfile3
4. exec --bar $inputfile4 $inputfile.outfile4
我可能可以通过指定两个并行命令或指定两个输入来摆脱困境,但我需要更通用的东西。将使用流水线“查找”命令指定文件。
编辑:我的一项操作命令如下所示:
find . -name 'somefiles*' -print0 | parallel -0 -j10 --verbose 'exec --foo {} {.}.outfile'
我只是不知道如何在两个命令之间以交替方式执行此操作
所以基本上我需要并行 -j10 做的是在一组文件上运行 5 个带有 foo 参数的命令和 5 个带有 bar 参数的命令。我可能会侥幸避免它不交替,但我希望平行处理它正好是 5/5 分割,所以我不会以更多的 foos 或更多的小节结束
我正在运行cat
以单独file_X
与大量文件组合file_1
,例如file_100000000000
.
由于数量众多,我将作业分配到一个有 64 个 CPU 的节点上,以便在每个 CPU 上并行运行。每个作业都在一个子文件夹中运行,因此有 64 个子文件夹。
令我惊讶的是,整体速度比预期的要慢得多。
由于我使用的shell脚本只是将每个作业指向file_X
位于64个子文件夹的父目录中的同一个文件,我想知道如果多个CPU同时读取同一个文件,会减慢每个CPU的读取速度吗?
我想在下面的 bash 脚本中并行化 for 循环。
我有两个 Matlab 脚本
1) 主.m
clear
rng default
P=2;
grid=randn(2,3);
jobs=1;
2) 调频
sgetasknum_grid=grid(jobs*(str2double(getenv('SGE_TASK_ID'))-1)+1: str2double(getenv('SGE_TASK_ID'))*jobs,:); %jobsx3
result=sgetasknum_grid+1;
filename = sprintf('result.%d.mat', ID);
save(filename, 'result')
exit
我想做的事:
我想运行 main.m;
然后,我想并行运行两次 fm
一切都应该在节点A上执行
这是我没有并行化的版本
1)我将 main.m 和 fm 保存到名为 My_folder 的文件夹中
2)我如下创建 bash 文件 td.sh 并将其保存到文件夹 My_folder
#$ -S /bin/bash
#$ -l h_vmem=5G
#$ -l tmem=5G
#$ -l h_rt=480:0:0
#$ -cwd
#$ -j y
#$ -N try
date
hostname
export SGE_TASK_ID
for SGE_TASK_ID in {1..2}
do
#Output the Task ID
echo "Task ID is $SGE_TASK_ID"
/share/.../matlab -nodisplay -nodesktop -nojvm -nosplash -r "main; ID=$SGE_TASK_ID; f; exit"
done
3)我进入终端并输入ssh username@A
, 然后cd /.../My_folder
, 然后bash td.sh
为了并行化,本论坛中的许多答案建议使用parallel
. 我猜 bash 文件看起来像下面这样
#$ -S /bin/bash
#$ -l h_vmem=5G
#$ -l tmem=5G
#$ -l h_rt=480:0:0
#$ -cwd
#$ -j y
#$ -N try
date
hostname
export SGE_TASK_ID
SGE_TASK_ID={1..2}
echo "$SGE_TASK_ID" | parallel -P 2 /share/.../matlab -nodisplay -nodesktop -nojvm -nosplash -r "main; ID=$SGE_TASK_ID; f; exit"
但是,这是我在终端上遇到的错误
A.local
td.sh: line 16: parallel: command not found
我了解可能是parallel
机器中缺少“软件”。我可以安装它吗?如果可以,如何安装?还是应该由系统管理员安装?或者,您有其他建议parallel
吗?
更新:尝试实现下面第二个答案的脚本
#!/bin/bash -l
#$ -S /bin/bash
#$ -l h_vmem=5G
#$ -l tmem=5G
#$ -l h_rt=480:0:0
#$ -cwd
#$ -j y
#$ -N try
date
hostname
export SGE_TASK_ID
SGE_TASK_ID={1..2}
echo -e SGE_TASK_ID | xargs -I {} -P 4 /share/.../matlab -nodisplay -nodesktop -nojvm -nosplash -r "main; ID={}; f; exit"
这是我得到的错误信息
Undefined function or variable 'SGE_TASK_ID'.