[설명] 셸 에서 mkfifo 를 통 해 이름 파 이 프 를 만들어 여러 프로 세 스 의 병행 을 제어 합 니 다.
작업 중 에 두 개의 타지 기관실 이 데 이 터 를 전송 해 야 하 는데 데이터 의 전체 이름 이 매우 규범 적 이 고 특정한 디 렉 터 리 에서 통 일 된 접두사 에 번 호 를 붙 여야 한다.예 를 들 어/path/from/file. {1. 100}.한편, 기계 방 의 전용 선 은 하나의 scp 프로 세 스 의 전송 속도 에 제한 이 있다. 예 를 들 어 최대 100 Mb/s 에 있 고 100 개의 scp 를 직접 시작 하면 ssh 의 병렬 연결 수 제한 을 만 날 수 있다.
따라서 동시 다발 수 를 제어 해 야 한다. 즉, ssh 의 동시 다발 제한 을 초과 하지 않 고 단일 네트워크 카드 의 대역 폭 을 포화 에 가 깝 게 하고 전송 을 빨리 완성 해 야 한다 (전선 대역 폭 이 단일 네트워크 카드 대역 폭 보다 훨씬 크다 고 가정)
이루어지다
mkfifo 를 통 해 이름 파 이 프 를 만 들 면 동시 다발 에 대한 통 제 를 실현 할 수 있다 는 것 을 알 고 있 었 습 니 다.이제 하 나 를 이 루 자.
그 전에 mkfifo 에 대해 잘 모 르 면 이 연결 을 참고 하 세 요. 작가 가 상세 하 게 쓰 면 저 는 바퀴 를 만 들 지 않 겠 습 니 다.
여기 서 코드 를 직접 제시 하고 설명 을 합 니 다.단일 프로 세 스 의 대역 폭 이 위 와 같 기 때문에 9 개의 병발 을 고려 합 니 다.코드 는 다음 과 같 습 니 다:
1 #!/bin/bash
2
3 your_func()
4 { # use your cmd or func instead of sleep here. don't end with background(&)
5 date +%s
6 echo "scp HOSTNAME:/home/USER/path/from/file.$1 REMOTE_HOST:/home/USER/path/to/"
7 sleep 2
8 }
9
10 concurrent()
11 { # from $1 to $2, (included $1,$2 itself), con-current $3 cmd
12 start=$1 && end=$2 && cur_num=$3
13
14 # ff_file which is opened by fd 4 will be really removed after script stopped
15 mkfifo ./fifo.$$ && exec 4<> ./fifo.$$ && rm -f ./fifo.$$
16
17 # initial fifo: write $cur_num line to $ff_file
18 for ((i=$start; i<$cur_num+$start; i++)); do
19 echo "init time add $i" >&4
20 done
21
22 for((i=$start; i<=$end; i++)); do
23 read -u 4 # read from mkfifo file
24 { # REPLY is var for read
25 echo -e "-- current loop: [cmd id: $i ; fifo id: $REPLY ]"
26
27 your_func $i
28 echo "real time add $(($i+$cur_num))" 1>&4 # write to $ff_file
29 } & # & to backgroud each process in {}
30 done
31 wait # wait all con-current cmd in { } been running over
32 }
33
34 concurrent 0 8 3
위 에 서 는 다음 과 같은 실행 결 과 를 표시 하기 위해 3 을 병발 수로 0 번 에서 8 번 까지 총 9 번 을 집행 한다.
1 bash concurrent.sh
2 -- current loop: [cmd id: 0 ; fifo id: init time add 0 ]
3 -- current loop: [cmd id: 1 ; fifo id: init time add 1 ]
4 -- current loop: [cmd id: 2 ; fifo id: init time add 2 ]
5 1453518400
6 1453518400
7 scp HOSTNAME:/home/USER/path/from/file.0 REMOTE_HOST:/home/USER/path/to/
8 scp HOSTNAME:/home/USER/path/from/file.2 REMOTE_HOST:/home/USER/path/to/
9 1453518400
10 scp HOSTNAME:/home/USER/path/from/file.1 REMOTE_HOST:/home/USER/path/to/
11 -- current loop: [cmd id: 3 ; fifo id: real time add 3 ]
12 -- current loop: [cmd id: 4 ; fifo id: real time add 5 ]
13 -- current loop: [cmd id: 5 ; fifo id: real time add 4 ]
14 1453518402
15 scp HOSTNAME:/home/USER/path/from/file.3 REMOTE_HOST:/home/USER/path/to/
16 1453518402
17 1453518402
18 scp HOSTNAME:/home/USER/path/from/file.5 REMOTE_HOST:/home/USER/path/to/
19 scp HOSTNAME:/home/USER/path/from/file.4 REMOTE_HOST:/home/USER/path/to/
20 -- current loop: [cmd id: 6 ; fifo id: real time add 6 ]
21 -- current loop: [cmd id: 7 ; fifo id: real time add 7 ]
22 -- current loop: [cmd id: 8 ; fifo id: real time add 8 ]
23 1453518404
24 scp HOSTNAME:/home/USER/path/from/file.6 REMOTE_HOST:/home/USER/path/to/
25 1453518404
26 1453518404
27 scp HOSTNAME:/home/USER/path/from/file.7 REMOTE_HOST:/home/USER/path/to/
28 scp HOSTNAME:/home/USER/path/from/file.8 REMOTE_HOST:/home/USER/path/to/
date 출력 시간 에서 볼 수 있 듯 이 2 초 마다 3 개의 병발 이 실 행 됩 니 다.
설명 하 다.
전체 과정
N 의 값 을 병발 수로 설정 합 니 다.fifo 에서 N 줄 내용 초기 화 (빈 값 일 수 있 음) 를 통 해 fifo 의 특성 을 이용 하여 fifo 에서 한 줄 을 읽 을 때마다 your 를 시작 합 니 다.func 호출, fifo 가 N 번 을 읽 었 을 때 fifo 가 비어 있 습 니 다.다시 읽 으 면 막힌다.이렇게 실행 을 시작 할 때 N 개 병발 (1 - N) 입 니 다.
동시 실행 프로 세 스 yourfunc, 임의의 작업 이 완료 되 었 을 때 다음 단 계 는 다음 과 같은 문 구 를 접대 합 니 다.
echo "real time add $(($i+$cur_num))" 1>&4
이렇게 해서 fifo 에 한 줄 을 새로 썼 습 니 다. 앞 에 막 힌 N + 1 번 이 실 행 될 프로 세 스 read 에 성공 하여 {} 구문 블록 에 들 어가 서 실 행 했 습 니 다.이렇게 read fifo 의 차단 기능 을 통 해 병발 수의 통 제 를 실현 하 였 다.
주의해 야 할 것 은 병발 수가 많 을 때 여러 개의 병발 프로 세 스 가 sleep 같은 초 수 시 뮬 레이 션 을 사용 하 더 라 도 프로 세 스 스케줄 링 순서 문제 가 존재 하기 때문에 시작 순서에 따라 끝 나 는 것 이 아니 라 나중에 시작 할 수 있 는 프로 세 스 가 먼저 끝 날 수 있 습 니 다.
따라서 다음 문장 에서 보 여 주 는 출력 에서 두 숫자 가 반드시 같 지 않다.병발 수가 클 수록 이런 차이성 은 크다.
-- current loop: [cmd id: 8 ; fifo id: real time add 9 ]
사용자 정의 함수
사용자 정의 함수 수정 yourfunc, 이 함 수 는 실제 한 줄 만 있 으 면 완 성 됩 니 다.
your_func()
{ # use your cmd or func instead of sleep here. don't end with background(&)
date +%s
scp HOSTNAME:/home/USER/path/from/file.$1 REMOTE_HOST:/home/USER/path/to/
}
주의해 야 할 것 은 scp 명령 은 마지막 으로 배경 을 누 르 는 & 기 호 를 추가 할 필요 가 없다 는 것 이다.상급 에 서 는 이미 백 스테이지 가 동시 다발 되 었 기 때문이다.
concurrent 함수 의 14 번 째 줄 을 설명 합 니 다.
exec digit<> filename
이것 은 평소에 거의 사용 되 지 않 는 명령 이다.특히 '< >' 라 는 부 호 는.모 르 겠 으 면 시스템 도움말 좀 알 아 보 자.
man bash
# search 'exec '
Opening File Descriptors for Reading and Writing
The redirection operator
[n]<>word
causes the file whose name is the expansion of word to be opened for both reading and writing on file
descriptor n, or on file descriptor 0 if n is not specified. If the file does not exist, it is created.
man bash 를 통 해 exec 에 빈 칸 을 검색 하면 exec 에 대한 설명 을 찾 을 수 있 습 니 다.man exec 를 직접 사용 하면 Liux programer 's manual 을 검색 할 수 있 습 니 다. execl, execlp, execv, execvp, execvpe - execute a file 이라는 시스템 함수 에 대한 호출 설명 입 니 다.
그리고 주의해 야 합 니 다. 4 < > 이 몇 글 자 는 빈 칸 을 넣 지 말고 반드시 연결 되 어 쓸 것 입 니 다.워드 전에 빈 칸 을 추가 할 수 있 습 니 다.
rm file
mkfifo 는 먼저 파이프 파일 을 만 든 다음 exec 를 통 해 이 파일 을 파일 설명자 4 에 연결 합 니 다.아마도 당신 은 뒤의 rm 조작 을 의심 하고 있 을 것 입 니 다.사실 이 파일 이 파일 설명자 에 연결 되 었 을 때 커 널 은 open 시스템 호출 을 통 해 이 파일 을 열 었 습 니 다. 이때 rm 작업 을 실 행 했 습 니 다. 파일 의 Inode 를 삭 제 했 지만 concurrent 함 수 는 파일 의 block 블록 에 연결 되 었 습 니 다.
만약 당신 이 이러한 상황 을 만난 적 이 있다 면, 당신 은 알 게 될 것 입 니 다. 만약 온라인 의 nginx 로그 가 구분 되 지 않 았 다 면, access. log 는 점점 커 질 것 입 니 다. 이때 당신 은 직접 rm 입 니 다. access. log 파일 이후 파일 이 보이 지 않 았 지만 df 보기 시스템 은 디스크 공간 을 방출 하지 않 았 습 니 다.이것 은 rm 이 inode 만 삭 제 했 기 때 문 입 니 다. 그러나 그 전에 nginx 는 open 을 통 해 이 파일 을 열 었 습 니 다. nginx 프로 세 스 제어 블록 에 있 는 파일 설명 부적 표 에 대응 하 는 fd 는 해당 하 는 파일 포인터 가 메모리 에 있 는 파일 시트 와 메모리 에 있 는 v 노드 표를 가리 키 고 최종 적 으로 파일 의 실제 저장 블록 을 가리 키 고 있 습 니 다.따라서 nginx 는 로 그 를 계속 쓸 수 있 고 디스크 는 기록 되 어 있 습 니 다.프로 세 스 가 설정 을 다시 읽 고 해당 파일 을 다시 열 때 만 이 파일 이 존재 하지 않 는 것 을 발견 하고 새 파일 을 만 들 수 있 습 니 다.이 때 Inode 노드 가 방출 되 었 기 때문에 df 로 볼 때 사용 가능 한 공간 이 커지 는 것 을 볼 수 있 습 니 다.
모 르 겠 습 니 다. APUE 의 그림 3.1 과 생각 설명 을 참고 하 세 요.
따라서 14 줄 의 rm 은 스 크 립 트 가 끝 날 때 까지 후속 스 크 립 트 실행 에 영향 을 주지 않 습 니 다. 시스템 은 모든 파일 설명 자 를 회수 합 니 다.
초기 화
18 - 20 줄 에서 파 이 프 를 초기 화 하 는 작업 을 하고 있 습 니 다.읽 기 파 이 프 는 두 가지 쓰기 가 있 습 니 다.
1 # style 1
2 for ((i=$start; i<$cur_num+$start; i++)); do
3 echo "init time add $i" >&4
4 done
5
6 # style 2
7 for ((i=$start; i<$cur_num+$start; i++)); do
8 echo "init time add $i"
9 done >&4
차 이 는 바로 '> & 4' 라 는 몇 개의 문 자 를 echo 문장 뒤에 두 느 냐, 아니면 done 뒤에 두 느 냐 하 는 것 이다. 전 자 는 echo 문장 을 대상 으로 하고 후 자 는 전체 for 순환 을 대상 으로 한다.
마찬가지 로 다음 for 순환 에서 read 명령 도 두 가지 방식 이 있 습 니 다.
# style 1
for((i=$start; i<=$end; i++)); do
read -u 4
{
your_func $i
echo "real time add $(($i+$cur_num))" 1>&4 # write to $ff_file
} &
done
# style 2
for((i=$start; i<=$end; i++)); do
read
{
your_func $i
echo "real time add $(($i+$cur_num))" 1>&4 # write to $ff_file
} &
done <&4
REPLY 에 대해 서.
REPLY 변 수 를 다시 설명해 주세요.이것 은 상기 순환 에서 read 명령 이 fifo 에서 읽 은 내용 을 저장 하 는 데 사 용 됩 니 다.사실 전체 스 크 립 트 에 서 는 이 점 에 관심 을 가 질 필요 가 없다.근 데 여기 도 설명 좀 해 주세요.
fifo 의 끊 임 없 는 읽 기와 쓰 기 를 통 해 echo 다음 과 같은 문 구 를 실현 할 수 있 습 니 다.
-- current loop: [cmd id: 7 ; fifo id: real time add 7 ]
리 플 리 를 어떻게 알 아 요?우리 또 맨 해 야 겠 다.read 의 인 자 를 찾기 위해 서먼저 man read 가 잘못 되 었 습 니 다.read 는 bash 자체 건설 명령 이기 때문에 다음 과 같이 찾 습 니 다.
1 man bash
2 # search 'Shell Variables'
3
4 REPLY Set to the line of input read by the read builtin command when no arguments are supplied.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.