Sử dụng tài nguyên bằng cách sử dụng đường ống và chuỗi ở đây


16

Chúng ta có thể nhận được kết quả tương tự bằng cách sử dụng hai trong bash,

echo 'foo' | cat

cat <<< 'foo'

Câu hỏi của tôi là sự khác biệt giữa hai điều này có liên quan gì đến tài nguyên được sử dụng và cái nào tốt hơn?

Tôi nghĩ rằng trong khi sử dụng đường ống, chúng tôi đang sử dụng một quy trình bổ sung echovà đường ống trong khi ở đây chuỗi chỉ có một bộ mô tả tệp đang được sử dụng cat.

Câu trả lời:


17

Ống là một tệp được mở trong một hệ thống tệp trong kernel và không thể truy cập như một tệp thông thường trên đĩa. Nó được tự động đệm chỉ đến một kích thước nhất định và cuối cùng sẽ chặn khi đầy. Không giống như các tệp có nguồn gốc trên các thiết bị khối, các đường ống hoạt động rất giống các thiết bị ký tự và do đó thường không hỗ trợ lseek()và dữ liệu đọc từ chúng không thể được đọc lại như bạn có thể làm với một tệp thông thường.

Chuỗi ở đây là một tệp thông thường được tạo trong một hệ thống tệp được gắn kết. Shell tạo tệp và giữ lại bộ mô tả của nó trong khi ngay lập tức xóa liên kết hệ thống tệp duy nhất của nó (và xóa nó) trước khi nó ghi / đọc một byte đến / từ tệp. Nhân sẽ duy trì không gian cần thiết cho tệp cho đến khi tất cả các quy trình giải phóng tất cả các mô tả cho nó. Nếu đứa trẻ đọc từ một mô tả như vậy có khả năng để làm điều đó, nó có thể được lseek()đọc lại và đọc lại.

Trong cả hai trường hợp, mã thông báo <<<|đại diện cho mô tả tệp và không nhất thiết phải là chính các tệp. Bạn có thể hiểu rõ hơn về những gì đang diễn ra bằng cách làm những việc như:

readlink /dev/fd/1 | cat

...hoặc là...

ls -l <<<'' /dev/fd/*

Sự khác biệt đáng kể nhất giữa hai tệp là chuỗi-doc ở đây gần như là một vấn đề tất cả cùng một lúc - trình bao ghi tất cả dữ liệu vào đó trước khi đưa ra mô tả đọc cho trẻ. Mặt khác, vỏ mở đường ống trên các mô tả thích hợp và tách trẻ em ra để quản lý chúng cho đường ống - và do đó, nó được viết / đọc đồng thời ở cả hai đầu.

Những sự phân biệt này, mặc dù, chỉ nói chung là đúng. Theo như tôi biết (điều này thực sự không xa lắm) thì điều này đúng với hầu hết mọi vỏ xử lý <<<chuỗi ngắn <<ở đây để chuyển hướng tài liệu ở đây với ngoại lệ duy nhất yash. yash, busybox, dash, Và các ashbiến thể có xu hướng trở lại đây-tài liệu với đường ống, tuy nhiên, và vì vậy trong những vỏ có thực sự là rất ít sự khác biệt giữa hai sau khi tất cả.

Ok - hai ngoại lệ. Bây giờ tôi đang nghĩ về nó, ksh93thực tế không phải là một ống cho tất cả |, mà là xử lý toàn bộ w / socket của doanh nghiệp - mặc dù nó làm một tệp tmp bị xóa <<<*như hầu hết những người khác làm. Hơn nữa, nó chỉ đặt các phần riêng biệt của một đường ống trong môi trường lớp dưới , đó là một loại uyển ngữ POSIX cho ít nhất là nó hoạt động như một lớp con , và do đó thậm chí không thực hiện các nhánh.

Thực tế là kết quả điểm chuẩn của @ PSkocik (rất hữu ích) ở đây có thể rất khác nhau vì nhiều lý do và hầu hết trong số này phụ thuộc vào việc thực hiện. Đối với thiết lập tài liệu ở đây, các yếu tố lớn nhất sẽ là ${TMPDIR}loại hệ thống tệp mục tiêu và cấu hình / tính khả dụng của bộ đệm hiện tại và vẫn còn lưu lượng dữ liệu được ghi. Đối với đường ống, nó sẽ là kích thước của quá trình vỏ, bởi vì các bản sao được tạo ra cho các dĩa yêu cầu. Theo cách bashnày là khủng khiếp khi thiết lập đường ống (bao gồm cả thay thế $(lệnh )) - bởi vì nó lớn và rất chậm, nhưng với ksh93nó hầu như không có sự khác biệt nào cả.

Đây là một đoạn vỏ nhỏ khác để giải thích cách một vỏ tách ra khỏi các lớp con cho một đường ống:

pipe_who(){ echo "$$"; sh -c 'echo "$PPID"'; }
pipe_who
pipe_who | { pipe_who | cat /dev/fd/3 -; } 3<&0

32059  #bash's pid
32059  #sh's ppid
32059  #1st subshell's $$
32111  #1st subshell sh's ppid
32059  #2cd subshell's $$
32114  #2cd subshell sh's ppid

Sự khác biệt giữa những gì một pipe_who()báo cáo cuộc gọi theo đường ống và báo cáo về một lần chạy trong lớp vỏ hiện tại là do hành vi được chỉ định (của một lớp con )trong việc yêu cầu pid của vỏ cha mẹ $$khi nó được mở rộng. Mặc dù các bashlớp con chắc chắn là các quá trình riêng biệt, $$tham số shell đặc biệt không phải là nguồn đáng tin cậy của thông tin này. Tuy nhiên, lớp vỏ con của shlớp con không từ chối báo cáo chính xác $PPID.


Rất hữu ích. Hệ thống tập tin trong kernel, có tên cho nó không? nó có nghĩa là nó tồn tại trong không gian kernel?
utlamn

2
@utlamn - thực sự, vâng - chỉ đơn giản là pipefs . Đó là tất cả trong kernel - nhưng (ngoài những thứ như FUSE) thì tất cả đềutập tin i / o .
mikeerv

10

Không có sự thay thế cho điểm chuẩn:

pskocik@ProBook:~ 
$ time (for((i=0;i<1000;i++)); do cat<<< foo >/dev/null; done  )

real    0m2.080s
user    0m0.738s
sys 0m1.439s
pskocik@ProBook:~ 
$ time (for((i=0;i<1000;i++)); do echo foo |cat >/dev/null; done  )

real    0m4.432s
user    0m2.095s
sys 0m3.927s
$ time (for((i=0;i<1000;i++)); do cat <(echo foo) >/dev/null; done  )
real    0m3.380s
user    0m1.121s
sys 0m3.423s

Và đối với một lượng dữ liệu lớn hơn:

TENMEG=$(ruby -e 'puts "A"*(10*1024*1024)')
pskocik@ProBook:~ 
$ time (for((i=0;i<100;i++)); do echo "$TENMEG" |cat >/dev/null; done  )

real    0m42.327s
user    0m38.591s
sys 0m4.226s
pskocik@ProBook:~ 
$ time (for((i=0;i<100;i++)); do cat<<< "$TENMEG" >/dev/null; done  )

real    1m26.946s
user    1m23.116s
sys 0m3.681s
pskocik@ProBook:~ 

$ time (for((i=0;i<100;i++)); do cat <(echo "$TENMEG") >/dev/null; done  )

real    0m43.910s
user    0m40.178s
sys 0m4.119s

Nó sẽ xuất hiện phiên bản ống có chi phí thiết lập lớn hơn nhưng cuối cùng hiệu quả hơn.


@mikeerv Đúng vậy. Tôi đã thêm một điểm chuẩn với một lượng dữ liệu lớn hơn.
PSkocik

2
echo foo >/dev/shm/1;cat /dev/shm/1 >/dev/nulldường như là nhanh chóng trong cả hai trường hợp ...
user23013

@ user23013 Điều đó có ý nghĩa. Tôi không thấy lý do tại sao echo "$longstring"hoặc <<<"$longstring"sẽ được điều chỉnh cho hiệu quả và với các chuỗi ngắn, dù sao thì hiệu quả cũng không thành vấn đề.
PSkocik

Điều thú vị là trong trường hợp của tôi (trên Ubuntu 14.04, Intel quad core i7) cat <(echo foo) >/dev/nullnhanh hơn echo foo | cat >/dev/null.
pabouk

1
@Prem Vâng, đó sẽ là một cách tiếp cận tốt hơn, nhưng một cách tốt hơn nữa sẽ không phải lo lắng về điều này và sử dụng công cụ phù hợp cho công việc. Không có lý do để nghĩ rằng heredocs sẽ được điều chỉnh hiệu suất.
PSkocik
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.