Tại sao tiếng vang tiếng vang lại nhanh hơn nhiều so với tiếng vang cảm ứng


116

Tôi đang cố cập nhật dấu thời gian đến thời điểm hiện tại trên tất cả các tệp xml trong thư mục của mình (theo cách đệ quy). Tôi đang sử dụng Mac OSX 10.8.5.

Trên khoảng 300.000 tệp, echolệnh sau mất 10 giây :

for file in `find . -name "*.xml"`; do echo >> $file; done

Tuy nhiên, touchlệnh sau mất 10 phút ! :

for file in `find . -name "*.xml"`; do touch $file; done

Tại sao tiếng vang nhanh hơn nhiều so với chạm ở đây?


20
Chỉ là một nhận xét phụ: Bạn biết rằng hai lệnh đó không tương đương nhau không? Ít nhất là đối với Unix / Linux, echo >> $filesẽ nối thêm một dòng mới $filevà do đó sửa đổi nó. Tôi giả sử nó sẽ giống với OS / X. Nếu bạn không muốn điều đó, hãy sử dụng echo -n >> $file.
Dubu

2
Cũng sẽ không touch `find . -name "*.xml"` nhanh hơn cả hai điều trên?
elmo

4
Hoặc chỉ xem xét>>$file
gerrit

8
Không phải là một câu trả lời cho câu hỏi rõ ràng, nhưng tại sao lại gọi touchrất nhiều lần? find . -name '*.xml' -print0 | xargs -0 touchgọi touchít hơn nhiều lần (có thể chỉ một lần). Hoạt động trên Linux, nên hoạt động trên OS X.
Mike Renfro

3
Danh sách đối số @elmo quá dài (dễ dàng, với 300.000 tệp ...)
Rmano

Câu trả lời:


161

Trong bash, touchlà một nhị phân bên ngoài, nhưng echolà một phần tử dựng sẵn :

$ type echo
echo is a shell builtin
$ type touch
touch is /usr/bin/touch

touchlà một nhị phân bên ngoài và bạn gọi touchmột lần cho mỗi tệp, trình bao phải tạo 300.000 trường hợp touch, việc này mất nhiều thời gian.

echotuy nhiên, là một nội dung được tích hợp sẵn và việc thực hiện các nội dung trong trình bao không hoàn toàn không cần thiết. Thay vào đó, shell hiện tại thực hiện tất cả các hoạt động và không có quy trình bên ngoài nào được tạo ra; đây là lý do tại sao nó nhanh hơn nhiều

Đây là hai hồ sơ hoạt động của shell. Bạn có thể thấy rằng rất nhiều thời gian được dành để nhân bản các quy trình mới khi sử dụng touch. Sử dụng /bin/echothay cho vỏ dựng sẵn sẽ hiển thị một kết quả tương đương hơn nhiều.


Sử dụng cảm ứng

$ strace -c -- bash -c 'for file in a{1..10000}; do touch "$file"; done'
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 56.20    0.030925           2     20000     10000 wait4
 38.12    0.020972           2     10000           clone
  4.67    0.002569           0     80006           rt_sigprocmask
  0.71    0.000388           0     20008           rt_sigaction
  0.27    0.000150           0     10000           rt_sigreturn
[...]

Sử dụng tiếng vang

$ strace -c -- bash -c 'for file in b{1..10000}; do echo >> "$file"; done'
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 34.32    0.000685           0     50000           fcntl
 22.14    0.000442           0     10000           write
 19.59    0.000391           0     10011           open
 14.58    0.000291           0     20000           dup2
  8.37    0.000167           0     20013           close
[...]

1
Bạn đã biên dịch strace trên OS X hoặc chạy thử nghiệm trên một HĐH khác chưa?
bmike

1
@bmike Thử nghiệm của tôi là trên Linux, nhưng nguyên tắc là giống hệt nhau.
Chris Xuống

Tôi hoàn toàn đồng ý - hãy xem nhận xét của tôi về câu hỏi chính về cách / bin / echo chậm như / bin / touch để lý do là âm thanh. Tôi chỉ muốn tái tạo thời gian của strace và thất bại khi sử dụng dtruss / dtrace và cú pháp bash -c không hoạt động như mong đợi trên OS X.
bmike

71

Như những người khác đã trả lời, sử dụng echosẽ nhanh hơn touchnhư echolà một lệnh mà là thường (mặc dù không bắt buộc phải) tích hợp vào vỏ. Sử dụng nó phân phối với chi phí hạt nhân liên quan đến việc chạy bắt đầu một quy trình mới cho mỗi tệp mà bạn nhận được touch.

Tuy nhiên, lưu ý rằng cách nhanh nhất để đạt được hiệu ứng này vẫn là sử dụng touch, nhưng thay vì chạy chương trình một lần cho mỗi tệp, có thể sử dụng -exectùy chọn findđể đảm bảo chỉ chạy một vài lần. Cách tiếp cận này thường sẽ nhanh hơn vì nó tránh được chi phí liên kết với vòng lặp shell:

find . -name "*.xml" -exec touch {} +

Sử dụng +(trái ngược với \;) chỉ find ... -execchạy lệnh một lần nếu có thể với mỗi tệp làm đối số. Nếu danh sách đối số rất dài (như trường hợp có 300.000 tệp), nhiều lần chạy sẽ được thực hiện với danh sách đối số có độ dài gần với giới hạn ( ARG_MAXtrên hầu hết các hệ thống).

Một ưu điểm khác của phương pháp này là nó hoạt động mạnh mẽ với tên tệp chứa tất cả các ký tự khoảng trắng không phải là trường hợp với vòng lặp ban đầu.


17
+1để chỉ ra +đối số tìm . Tôi nghĩ nhiều người không biết điều này (tôi đã không).
gerrit

7
Không phải tất cả các phiên bản find+đối số. Bạn có thể có được một hiệu ứng tương tự bằng cách đường ống đến xargs.
Barmar

5
@Barmar, +phần được POSIX yêu cầu, vì vậy nên có thể mang theo được. -print0không phải.
Graeme

1
Tôi vẫn thỉnh thoảng chạy vào các triển khai không có nó. YMMV.
Barmar

1
@ChrisDown, Một cái gì đó tôi đã phát hiện ra là Busybox findcó sẵn tùy chọn nhưng chỉ xử lý nó như ;bên dưới bề mặt.
Graeme

29

echolà một vỏ dựng sẵn. Mặt khác, touchlà một nhị phân bên ngoài.

$ type echo
echo is a shell builtin
$ type touch
touch is hashed (/usr/bin/touch)

Shell dựng nhanh hơn nhiều vì không có chi phí liên quan đến việc tải chương trình, tức là không có fork/ execliên quan. Như vậy, bạn sẽ quan sát thấy sự khác biệt đáng kể về thời gian khi thực hiện lệnh dựng sẵn so với lệnh bên ngoài một số lượng lớn thời gian.

Đây là lý do mà các tiện ích như timecó sẵn như builtins vỏ.

Bạn có thể nhận được danh sách đầy đủ các nội dung shell bằng cách nói:

enable -p

Như đã đề cập ở trên, việc sử dụng tiện ích trái ngược với nội dung dựng sẵn dẫn đến suy giảm hiệu suất đáng kể. Sau đây là số liệu thống kê về thời gian thực hiện để tạo ~ 9000 tệp bằng cách sử dụng nội dung echotiện ích echo :

# Using builtin
$ time bash -c 'for i in {1000..9999}; do echo > $i; done'

real    0m0.283s
user    0m0.100s
sys 0m0.184s

# Using utility /bin/echo
$ time bash -c 'for i in {1000..9999}; do /bin/echo > $i; done'

real    0m8.683s
user    0m0.360s
sys 0m1.428s

Và tôi nghĩ rằng có một echohệ số nhị phân trên hầu hết các hệ thống (đối với tôi là vậy /bin/echo), vì vậy bạn có thể thử lại các bài kiểm tra thời gian bằng cách sử dụng thay vì tích hợp
Michael Mrozek

@MichaelMrozek Đã thêm kiểm tra thời gian cho nội dung và nhị phân.
devnull
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.