Tại sao wc quá chậm?


17

Tại sao tiện ích wc quá chậm?

Khi tôi chạy nó trên một tệp lớn, sẽ mất khoảng 20 lần so với md5sum:

MyDesktop:/tmp$ dd if=/dev/zero bs=1024k count=1024 of=/tmp/bigfile
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.687094 s, 1.6 GB/s

MyDesktop:/tmp$ time wc /tmp/bigfile 
         0          0 1073741824 /tmp/bigfile

real    0m45.969s
user    0m45.424s
sys     0m0.424s

MyDesktop:/tmp$ time md5sum /tmp/bigfile 
cd573cfaace07e7949bc0c46028904ff  /tmp/bigfile

real    0m2.520s
user    0m2.196s
sys     0m0.316s

Đây không chỉ là một điều kiện cạnh kỳ lạ do tệp chứa đầy null, tôi thấy sự khác biệt tương tự về hiệu suất ngay cả khi tệp chứa đầy dữ liệu ngẫu nhiên hoặc là tệp văn bản.

(đây là trên Ubuntu 13.04, 64 bit)


Lưu ý cho những người chỉ quan tâm đến số lượng dòng: wc -l <tên tệp> nhanh hơn nhiều trên các tệp rất lớn.
EL

Câu trả lời:


27

Vì vậy, tôi đã đi đến nguồn, và có vẻ như sự chậm chạp trong việc xử lý các ký tự byte kép. Về cơ bản, đối với mỗi ký tự được đọc, nó cần gọi mbrtowc()để cố gắng chuyển đổi nó thành một ký tự rộng, sau đó ký tự rộng đó được kiểm tra để xem đó có phải là dấu tách từ, dấu tách dòng, v.v.

Thật vậy, nếu tôi thay đổi LANGbiến cục bộ của mình từ mặc định en_US.UTF-8(UTF-8 là bộ ký tự đa nhân) và đặt nó thành " C" (bộ ký tự byte đơn giản), wccó thể sử dụng tối ưu hóa một byte, giúp tăng tốc đáng kể, chỉ mất khoảng một phần tư như trước đây.

Ngoài ra, nó chỉ phải kiểm tra từng ký tự nếu nó đang đếm từ ( -w), độ dài dòng ( -L) hoặc ký tự ( -m). Nếu nó chỉ thực hiện đếm byte và / hoặc dòng, nó có thể bỏ qua việc xử lý ký tự rộng và sau đó nó chạy cực kỳ nhanh - nhanh hơn md5sum.

Tôi chạy nó thông qua gprof, và các chức năng được sử dụng để xử lý các ký tự nhiều byte ( mymbsinit(), mymbrtowc(), myiswprint(), vv) đều chiếm khoảng 30% thời gian thực hiện một mình, và mã mà bước qua bộ đệm là nhiều phức tạp bởi vì nó có tới xử lý các bước có kích thước thay đổi thông qua bộ đệm cho các ký tự có kích thước thay đổi, cũng như nhồi bất kỳ ký tự nào đã hoàn thành một phần kéo dài bộ đệm trở lại đầu bộ đệm để có thể xử lý lần sau.

Bây giờ tôi biết những gì cần tìm, tôi đã tìm thấy một vài bài viết đề cập đến sự chậm chạp của utf-8 với một số tiện ích:

/programming/13913014/grepping-a-huge-file-80gb-any-way-to-speed-it-up http://dtrace.org/bloss/enamendan/2011/12/08 / 2000x-hiệu suất-thắng /


2
Ồ, mới nhận ra bạn là OP. : p
Ivan Châu

2
Mặc dù đây là câu trả lời được đánh giá cao nhất, nhưng nó không liên quan. md5sumsẽ không bao giờ cho phép bạn đếm số từ và wcsẽ không tính băm md5 của tệp! Nó giống như hỏi tại sao xe của tôi quá chậm so với máy đánh chữ của tôi khi viết văn bản.
dùng49468

5
@ user49468: Thật hợp lý khi cho rằng cả hai đều bị ràng buộc IO, vì cả hai đều phải đọc từng byte của tệp đầu vào. Câu trả lời này chứng minh rằng wctrên thực tế là bị ràng buộc bởi CPU, khi xử lý các ký tự nhiều byte.
MSalters

2
@ user49468: wc và md5sum có thể làm những việc khác nhau, nhưng cả hai đều đọc một tệp và thực hiện một phép tính tương đối đơn giản, một tính toán tổng kiểm tra, một đếm số byte, dấu tách từ và dòng mới. Chà, tôi nghĩ nó đơn giản, nhưng không bao gồm sự phức tạp thêm của các bộ ký tự đa nhân. Nó giống như hỏi "Tại sao xe của tôi đến cửa hàng nhanh hơn 20 lần so với minivan của tôi?" Bạn sẽ mong đợi một số khác biệt giữa hai, nhưng không phải là một sự khác biệt 20X.
Johnny

1
@Johnny bạn so sánh xe hơi / minivan thiếu khía cạnh mà cả hai được thiết kế để vận chuyển bạn đến cửa hàng. Vì vậy, một so sánh tốc độ được đưa ra. So sánh chiếc xe của bạn với chiếc xe sơn sọc là phù hợp hơn. Chỉ vì cả hai sử dụng đường phố, tốc độ của họ không liên quan vì họa sĩ sọc không phù hợp để đi mua sắm và ngược lại.
dùng49468

1

Chỉ là một phỏng đoán nhưng bạn là loại so sánh táo với cam với sự tôn trọng với những gì wcđang làm so với những gì md5sumđang làm.

nhiệm vụ của md5sum

Khi md5sumxử lý một tệp, nó chỉ cần mở tệp dưới dạng luồng và sau đó bắt đầu chạy luồng thông qua chức năng kiểm tra MD5 cần rất ít bộ nhớ. Nó chủ yếu là CPU & đĩa I / O bị ràng buộc.

nhiệm vụ của wc

Khi wcchạy nó đang làm nhiều hơn sau đó chỉ phân tích tệp một ký tự một lần. Nó phải thực sự phân tích cấu trúc của tệp, các dòng tại một thời điểm đưa ra quyết định về việc ranh giới giữa các ký tự và liệu đó có phải là ranh giới từ hay không.

Thí dụ

Hãy nghĩ về các chuỗi sau đây và làm thế nào mỗi thuật toán sẽ phải di chuyển qua chúng khi chúng phân tích chúng:

“Hello! Greg”
“Hello!Greg”
“Hello\nGreg”
“A.D.D.”
“Wow, how great!”
“wow     \n\n\n    great”
“it was a man-eating shark.”

Đối với MD5, nó di chuyển một cách tầm thường qua các chuỗi này một ký tự tại một thời điểm. Vì wcnó phải quyết định ranh giới từ & dòng là gì và theo dõi số lần xuất hiện mà nó nhìn thấy.

Thảo luận thêm về wc

Tôi đã tìm thấy thử thách mã hóa này từ năm 2006 để thảo luận về việc triển khai wctrong .NET. Những khó khăn là khá rõ ràng khi bạn xem xét một số mã giả, vì vậy điều này có thể giúp bắt đầu làm sáng tỏ lý do tại sao wcdường như chậm hơn nhiều so với các hoạt động khác.


1
Bạn đang mô tả một cái gì đó khác với lệnh wc Unix tiêu chuẩn (ít nhất, không phải là lệnh đi kèm với Ubuntu). Mà wc không đếm những từ duy nhất , chỉ là những từ, vì vậy "xin chào thế giới xin chào" là 3 từ chứ không phải 2.
Johnny

Dựa trên lý thuyết này, nó có vẻ như là một nhiệm vụ đơn giản hơn, như đếm các dòng, sẽ đi nhanh hơn. Việc thay đổi 'wc' để chỉ định số lượng dòng có làm thay đổi đáng kể kết quả không? 'wc -l'
Joshua Miller

@ John - Tôi chưa bao giờ nói nó đếm những từ duy nhất bạn nói thế. wcđếm nhiều thứ khi nó phân tích tệp. Nó đếm số lượng từ, dòng và byte khi phân tích tệp. Đọc trang người đàn ông!
slm

@JoshuaMiller - Không rõ việc bảo wcchỉ đếm các dòng giới hạn phân tích cú pháp nội bộ sao cho nó chỉ đếm những điều này hoặc chỉ báo cáo kết quả của dòng, mặc dù nó vẫn đếm mọi thứ.
slm

@slm Bạn đã nói nó đếm những từ độc đáo, ví dụ của bạn nói là Xin chào! Kết quả của Greg Tiết trong Hello 1, Greg 1 , tức là tính cho mỗi từ. Và dự án .Net mà bạn liên kết để nói "Một trong những nhiệm vụ chính của nó là trải qua một tập hợp dữ liệu và đếm số lần lặp lại của một từ đã cho. Ví dụ, đã đưa ra câu Xin chào, vâng xin chào từ Hello được sử dụng hai lần và từ có được sử dụng một lần. " Trong khi thực tế, kết quả của tiếng vang "Xin chào, vâng xin chào" | wc --words , là "3", không phải "Xin chào: 2, Có: 1"
Johnny
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.