如何在 bash shell 脚本中启动两个线程?

如何在 bash shell 脚本中启动两个线程?

我正在尝试将文件复制到其中machineB,因为我正在.machineCmachineAmachineA

如果文件不存在,machineB那么它肯定应该存在,machineC所以我将尝试首先复制文件machineB,如果它不存在,machineB那么我将尝试从 复制相同的文件machineC

我正在使用 GNU 并行库并行复制文件,并且工作正常。目前我正在并行复制两个文件。

目前,我正在使用 GNU 并行复制文件夹PRIMARY_PARTITION中的文件PRIMARY,完成后,我将使用相同的 GNU 并行复制文件夹SECONDARY_PARTITION中的文件SECONDARY,因此到目前为止,它是连续的PRIMARYSECONDARY文件夹

下面是我的 shell 脚本,一切正常 -

#!/bin/bash

export PRIMARY=/test01/primary
export SECONDARY=/test02/secondary
readonly FILERS_LOCATION=(machineB machineC)
export FILERS_LOCATION_1=${FILERS_LOCATION[0]}
export FILERS_LOCATION_2=${FILERS_LOCATION[1]}
PRIMARY_PARTITION=(550 274 2 546 278) # this will have more file numbers
SECONDARY_PARTITION=(1643 1103 1372 1096 1369) # this will have more file numbers

export dir3=/testing/snapshot/20140103

# delete primary files first and then copy
find "$PRIMARY" -mindepth 1 -delete

do_CopyInPrimary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/.
}
export -f do_CopyInPrimary
parallel -j 2 do_CopyInPrimary ::: "${PRIMARY_PARTITION[@]}"

# delete secondary files first and then copy
find "$SECONDARY" -mindepth 1 -delete

do_CopyInSecondary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/.
}
export -f do_CopyInSecondary
parallel -j 2 do_CopyInSecondary ::: "${SECONDARY_PARTITION[@]}"

问题陈述:-

有什么方法可以启动两个线程,一个线程PRIMARY使用与上面相同的设置复制文件夹中的文件,这意味着它将并行复制两个文件。第二个线程SECONDARY使用与上面相同的设置复制文件夹中的文件,它还应该同时并行复制两个文件?

这意味着他们应该同时在文件夹中并行复制文件,PRIMARYSECONDARY不是在PRIMARY文件夹完成后,然后在SECONDARY文件夹中复制文件。

目前,一旦PRIMARY文件夹文件完成,那么只有我尝试复制文件SECONDARY夹中的文件。

简而言之,我只需要启动两个线程,一个线程将运行这个 -

# delete primary files first and then copy
find "$PRIMARY" -mindepth 1 -delete

do_CopyInPrimary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/.
}
export -f do_CopyInPrimary
parallel -j 2 do_CopyInPrimary ::: "${PRIMARY_PARTITION[@]}"

第二个线程将运行这个 -

# delete secondary files first and then copy
find "$SECONDARY" -mindepth 1 -delete

do_CopyInSecondary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/.
}
export -f do_CopyInSecondary
parallel -j 2 do_CopyInSecondary ::: "${SECONDARY_PARTITION[@]}"

一旦所有文件都被成功复制,它应该回显消息,所有文件都被复制。在java中,我知道如何启动两个线程,并且每个线程都执行特定任务,但不确定在bash shell脚本中这将如何工作?

PRIMARY我的主要任务是使用GNU并行在文件夹和SECONDARY文件夹中同时复制两个文件?

这可以在 bash shell 脚本中完成吗?

答案1

Bash 不支持线程,但支持后台多处理。也就是说,进程被克隆到一个新的进程空间,有自己的环境、工作目录等,所有通信都必须通过正常的 IPC 通道进行。但除此之外它看起来很像线程。

您可以通过“背景化”代码块来实现此目的。像这样:

#!/bin/bash
{
    echo "Foo"
    sleep 1
    echo "Foo: done"
}&    
echo "Bar"
sleep 1
echo "Bar: done"

输出

Bar
Foo
**[1 second delay]**
Bar: done
Foo: done

您可以通过将代码块包装在函数中并将该函数作为后台作业运行来获得相同的效果。

或者,您可以将代码块括在括号而不是大括号中。括号中的语句显式(并且始终)在单独的进程中运行;通常,大括号中的语句会被分组,但运行时不会分叉。使用后缀在后台运行代码&会强制该代码在单独的进程中运行。

答案2

显而易见的是:

parallel -j 2 do_CopyInPrimary ::: "${PRIMARY_PARTITION[@]}" &
parallel -j 2 do_CopyInSecondary ::: "${SECONDARY_PARTITION[@]}" &
wait

但这样,辅助服务器不会等待主服务器完成,也不会检查主服务器是否成功。让我们假设 $PRIMARY_PARTITION[1] 对应于 $SECONDARY_PARTITION[1] (因此,如果您无法从 $PRIMARY_PARTITION[1] 读取文件,您将从 $SECONDARY_PARTITION[1] 读取它 - 这也意味着 $PRIMARY_PARTITION 和 $SECONDARY_PARTITION具有相同数量的元素)。然后您可以在 $PRIMARY_PARTITION[1] 上调节 $SECONDARY_PARTITION[1] 的运行。

do_Copy() {
  PRIMARY_PARTITION=(550 274 2 546 278) # this will have more file numbers
  SECONDARY_PARTITION=(1643 1103 1372 1096 1369) # this will have more file numbers
  pel=${PRIMARY_PARTITION[$1]}
  sel=${SECONDARY_PARTITION[$1]}
  do_CopyInPrimary $pel || 
    do_CopyInSecondary $sel || 
    echo Could not copy neither $pel nor $sel
}
export -f do_Copy
# Number of elements in PRIMARY_PARTITION == SECONDARY_PARTITION
seq ${#PRIMARY_PARTITION[@]} | parallel -j 2 do_Copy

这将使依赖关系正确,但一次总共只能复制 2 个。由于-j4您面临同时进行 4 项初选的风险,因此我们也需要防范这种情况:

do_Copy() {
  PRIMARY_PARTITION=(550 274 2 546 278) # this will have more file numbers
  SECONDARY_PARTITION=(1643 1103 1372 1096 1369) # this will have more file numbers
  pel=${PRIMARY_PARTITION[$1]}
  sel=${SECONDARY_PARTITION[$1]}
  sem -j2 --fg --id primary do_CopyInPrimary $pel || 
    sem -j2 --fg --id secondary do_CopyInSecondary $sel || 
    echo Could not copy neither $pel nor $sel
}
export -f do_Copy
# Number of elements in PRIMARY_PARTITION == SECONDARY_PARTITION
seq ${#PRIMARY_PARTITION[@]} | parallel -j 4 do_Copy

sem将主要数量限制为 2 个,次要数量限制为 2 个。

答案3

为此,最好使用 rsync 而不是 scp。通过使用一个命令复制所有文件,而不是为每个文件运行 scp,它将节省您大量的时间和精力,并有助于确保正确复制数据。它还将跳过从 machineC 复制现有文件。像这样的东西:

#!/bin/bash

files="one two three"
machines="machineB machineC"

for machine in machines
do
    ssh $machine -c "cd source_directory || exit 1; rsync -avPz --ignore-existing $files machineA:/receive_directory/"
done

相关内容