여러 pv ​​명령을 병렬로 실행하는 방법은 무엇입니까?

여러 pv ​​명령을 병렬로 실행하는 방법은 무엇입니까?

pv각 파이프라인에서 일련의 명령 파이프라인을 실행하고 싶습니다. 예는 다음과 같습니다.

for p in 1 2 3
do
  cat /dev/zero | pv -N $p | dd of=/dev/null &
done

파이프라인의 실제 명령은 중요하지 않습니다( cat/ dd는 단지 예일 뿐입니다)...

목표는 동시에 실행되는 4개의 파이프라인이며 각각 자체 pv출력이 있습니다. 그러나 백그라운드에서 이와 같은 명령을 입력하려고 하면 pv명령이 중지되고 4개의 중지된 작업만 표시됩니다. 나는 그것을 시도했지만 {...|pv|...}&동일한 bash -c "...|pv|..." &결과를 얻었습니다.

pv여러 명령 파이프라인을 동시에 실행하는 방법은 무엇입니까 ?

답변1

xargs다음 옵션을 사용하여 -P이 작업을 수행 할 수 있다는 것을 알았습니다 .

josh@subdivisions:/# seq 1 10 | xargs -P 4 -I {} bash -c "dd if=/dev/zero bs=1024 count=10000000 | pv -c -N {} | dd of=/dev/null"
        3: 7.35GiB 0:00:29 [ 280MiB/s] [                                                                                         <=>                                                                 ]
        1: 7.88GiB 0:00:29 [ 312MiB/s] [                                                                                         <=>                                                                 ]
        4: 7.83GiB 0:00:29 [ 258MiB/s] [                                                                                         <=>                                                                 ]
        2: 6.55GiB 0:00:29 [ 238MiB/s] [                                                                                         <=>                                                                 ]

반복할 배열의 출력을 다음으로 보냅니다 xargs. 모든 명령을 동시에 실행하려면 다음을 사용하십시오.-P 0

답변2

pv백그라운드에서 시작할 수 없습니다.

src/main/main.c소스 코드 파일에서 볼 수 있듯이 pv터미널(구조체)에 플래그를 설정합니다. 이는 포그라운드에 있지 않을 때 터미널에 쓰려고 할 때 이를 수신하고 신호 처리기로 포착한 다음 터미널을 "혼란"시키지 않도록 출력을 리디렉션하기 위한 것입니다.TOSTOPtcsetattr()c.c_lflagtermiosSIGTTOU/dev/null

/*
 * Set terminal option TOSTOP so we get signal SIGTTOU if we try to
 * write to the terminal while backgrounded.
 *
 * Also, save the current terminal attributes for later restoration.
 */
memset(&t, 0, sizeof(t));
tcgetattr(STDERR_FILENO, &t);
t_save = t;
t.c_lflag |= TOSTOP;
tcsetattr(STDERR_FILENO, TCSANOW, &t);

물론 이것은 역겨운 일입니다. 그 자체에 대해 플래그를 설정하는 것이 아니라 터미널을 사용하는 모든 프로그램에 대해 설정하기 때문입니다.

하지만 그게 전부는 아닙니다. glibc에서 설명했듯이수동:

함수: int tcsetattr(int filedes, int when, const struct termios *termios-p)

이 함수가 제어 터미널의 백그라운드 프로세스에서 호출되면 일반적으로 프로세스가 터미널에 쓰려고 시도하는 것처럼 SIGTTOU 신호가 프로세스 그룹의 모든 프로세스로 전송됩니다. 예외는 호출 프로세스 자체가 SIGTTOU 신호를 무시하거나 차단하는 경우입니다. 이 경우 작업은 수행되지만 신호는 전송되지 않습니다. 작업 제어를 참조하세요.

그들은 차단하거나 무시하지 않으며 SIGTTOU확인하지도 않습니다 tcsetattr()(-1을 반환하고 errno다음으로 설정됩니다).EINTR 만약에이전에 이미 신호 처리기를 설정 했습니다 SIGTTOU.

따라서 프로세스가 중지됩니다. ( 명령 SIGCONT에서 ) 하나를 받으면 시도하기 전에 완료됩니다 .bgtcsetattr()

그래서 나는 그것을 기능으로 고려해야한다고 생각합니다 ;-)

관련 정보