Ý nghĩa của quy tắc tối ưu hóa chương trình 90/10 là gì?


67

Theo Wikipedia, quy tắc tối ưu hóa chương trình 90/10 nói rằng 90% thời gian thực hiện chương trình được dành để thực hiện 10% mã mã (xem đoạn thứ hai tại đây ).

Tôi thực sự không hiểu điều này. Chính xác điều này có nghĩa là gì? Làm thế nào 90% thời gian thực hiện có thể được dành chỉ thực hiện 10% mã? Thế còn 90% mã còn lại thì sao? Làm thế nào họ có thể được thực hiện chỉ trong 10% thời gian?


50
Một số phần của mã có thể được thực thi thường xuyên hơn các phần khác. Rốt cuộc, đó là những gì các vòng lặp dành cho. Trong thực tế, hầu như luôn luôn một số bộ phận được thực hiện cách thường xuyên hơn những người khác.
Kilian Foth

147
Đợi cho đến khi bạn nghe quy tắc 90/10 về thời gian thực hiện dự án phần mềm: 90% dự án sẽ chiếm 90% đầu tiên của thời gian quy định; 10% cuối cùng của dự án sẽ chiếm 90% còn lại của thời gian được phân bổ.
Paul D. Chờ

3
Nhầm lẫn ở đây: "thời gian được thực hiện". Hãy xem xét a++; for(i=0;i<100;i++){b++;} for(i=0;i<100;i++){print(xyz);}. Chắc chắn vòng lặp for đầu tiên chi tiêu nhiều hơn so với câu lệnh đầu tiên, nhưng vòng lặp for thứ hai dành nhiều thời gian hơn 1000 lần so với vòng lặp for đầu tiên, nhưng không thực hiện . Nó dành nó chờ đợi để in . Vì vậy, có một sự khác biệt giữa thời gian thực hiện và thời gian mà mã chịu trách nhiệm .
Mike Dunlavey

32
@ Paul_D._Waite Tôi nghĩ rằng 90% dự án chiếm 90% thời gian, 90% những gì còn lại chiếm 90% thời gian, và vì vậy, một loạt không hội tụ để kết luận rằng không có dự án nào bao giờ hoàn thành hoặc gỡ lỗi hoàn toàn trong thời gian ngắn hơn vô hạn.
nigel222

9
Đối với các ví dụ thực tế, một vài mã tôi đã làm việc (mô hình khoa học) đã sử dụng một lượng lớn mã (~ 10K dòng) để đọc và thiết lập mô hình, sau đó thực hiện một vòng lặp qua vài trăm dòng để tính toán thực tế. Nhưng vòng lặp ngắn đó là n ^ 4 (ba chiều không gian được lặp qua nhiều nghìn bước thời gian), vì vậy phải mất nhiều ngày để tính toán. Vì vậy, tỷ lệ thực tế có lẽ giống hơn 99% / 1% :-)
jamesqf

Câu trả lời:


184

Có hai nguyên tắc cơ bản khi chơi ở đây:

  • Một số mã được thực thi thường xuyên hơn nhiều so với mã khác. Ví dụ, một số mã xử lý lỗi có thể không bao giờ được sử dụng. Một số mã sẽ được thực hiện chỉ khi bạn bắt đầu chương trình của bạn. Các mã khác sẽ được thực thi lặp đi lặp lại trong khi chương trình của bạn chạy.
  • Một số mã mất nhiều thời gian để chạy hơn các mã khác. Ví dụ: một dòng duy nhất chạy truy vấn trên cơ sở dữ liệu hoặc lấy tệp từ internet có thể sẽ mất nhiều thời gian hơn hàng triệu thao tác toán học.

Quy tắc 90/10 không đúng theo nghĩa đen. Nó thay đổi theo chương trình (và tôi nghi ngờ có bất kỳ cơ sở nào cho các số cụ thể 90 và 10; có lẽ ai đó đã kéo chúng ra khỏi không khí mỏng). Nhưng vấn đề là, nếu bạn cần chương trình của mình chạy nhanh hơn, có lẽ chỉ một số lượng nhỏ dòng là có ý nghĩa để thực hiện điều đó. Xác định các phần chậm của phần mềm của bạn thường là phần lớn nhất của tối ưu hóa.

Đây là một cái nhìn sâu sắc quan trọng và nó có nghĩa là các quyết định có vẻ trái ngược với nhà phát triển mới thường có thể đúng. Ví dụ:

  • Có rất nhiều mã không đáng để bạn dành thời gian để làm "tốt hơn" , ngay cả khi nó đang làm mọi thứ một cách ngu ngốc, đơn giản. Bạn có thể viết một thuật toán tìm kiếm hiệu quả hơn cho ứng dụng XYZ không? Có, nhưng thực sự là một so sánh đơn giản của mọi giá trị cần một lượng thời gian không đáng kể, mặc dù có hàng ngàn giá trị. Vì vậy, nó chỉ không xứng đáng. Các nhà phát triển mới có thể khó tránh khỏi việc tối ưu hóa không cần thiết, bởi vì trong chương trình cấp bằng của họ đã dành quá nhiều thời gian cho việc viết thuật toán "chính xác" (nghĩa là hiệu quả nhất). Nhưng trong thế giới thực, thuật toán chính xác là bất kỳ thuật toán nào hoạt động và chạy đủ nhanh.
  • Những thay đổi làm cho mã của bạn dài hơn và phức tạp hơn vẫn có thể là một chiến thắng hiệu suất. Ví dụ, trong ứng dụng FOO, có thể đáng để thêm hàng trăm dòng logic mới, chỉ để tránh một cuộc gọi cơ sở dữ liệu.

6
Đặc biệt lưu ý, với những thứ như sắp xếp các hàm, nó nhanh hơn (trong thời gian phát triển) và dễ dàng hơn để tạo ra một thuật toán đơn giản ngu ngốc làm điều đúng đắn trong mọi trường hợp hơn là có được một thuật toán thanh lịch đầy đủ chức năng và không có lỗi. (Tho những lý do duy nhất để viết một thuật toán sắp xếp bên ngoài học viện là nếu bạn đang xây dựng một thư viện hoặc làm việc trên một nền tảng mà không có một
tên lửa

5
Tôi nghĩ rằng bạn cần thêm liên kết đến Shouldioptizes.com :)
Ivan Kolmychek

13
Tôi nghĩ rằng 90/10 đến từ Nguyên tắc Pareto 80/20 nổi tiếng en.wikipedia.org/wiki/Pareto_principl
fernando.reyes

2
@StarWeaver Đó là lý do tại sao các ngôn ngữ giúp viết các loại siêu hiệu quả dễ dàng hoặc dễ dàng hơn một loại bong bóng xảo quyệt rất quan trọng ở đó, như C ++. Các thuật toán và mã "đóng gói sẵn" như vậy có thể thực sự được tối ưu hóa rất nhiều mà không gây ra sự phức tạp tại điểm sử dụng.
Yakk

6
@IvanKolmychek Trang web đó là sai lệch. Chắc chắn, loại phân tích chi phí là một yếu tố cần xem xét, nhưng có những yếu tố khác như trải nghiệm người dùng. Bạn có thể tiết kiệm rất nhiều tiền bằng cách không tối ưu hóa, nhưng bạn cũng có thể bỏ lỡ rất nhiều thu nhập nếu mọi người rời khỏi trang web của bạn thất vọng.
jpmc26

21

Đây không phải là một quy luật tự nhiên, mà là một quy tắc ngón tay cái được sinh ra bởi kinh nghiệm rộng rãi. Nó còn được gọi là quy tắc 80/20 và chỉ là một xấp xỉ thô.

Vòng lặp, Chi nhánh và kiểm soát dòng chảy khác.

Mỗi nơi có if, bạn sẽ có một nhánh được lấy thường xuyên hơn so với nhánh khác. Do đó, phần lớn thời gian thực hiện được dành để thực hiện phần đó của chương trình chứ không phải phần khác.

Mỗi nơi có một vòng lặp chạy nhiều lần, bạn có mã được thực thi nhiều hơn mã xung quanh. Vì vậy, nhiều thời gian hơn được dành ở đó.

Ví dụ, xem xét:

def DoSomeWork():
    for i in range(1000000):
        DoWork(i)
    except WorkExeption:
        print("Oh No!")

Ở đây ý print("Oh No!")chí chỉ chạy tối đa một lần, và thường không bao giờ, trong khi ý DoWork(i)chí sẽ xảy ra khoảng một triệu lần.


7
Gọi nó là quy tắc 80/20 có thể gây nhầm lẫn với nguyên tắc Pareto , áp dụng rộng rãi hơn là chỉ lập trình. Có lẽ 90 và 10 chỉ là những con số thuận tiện không có ý nghĩa trùng lặp này.
trichoplax

29
Đây là một ví dụ của hiệu trưởng Pareto. Cả hai cặp số đều tùy ý như nhau
Caleth

2
Có một cơ sở toán học để phân chia 80/20 trong nguyên tắc Pareto. Họ không chỉ là một số nhân vật tưởng tượng để đại diện cho "rất nhiều" và "một chút".
Moyli

1
@Moyli - Có, "Có một cơ sở toán học cho sự phân chia 80/20 ...", nhưng trong thế giới thực, nó sẽ không bao giờ (OK, bởi sự trùng hợp, hiếm khi) chính xác là 80/20.
Kevin Fegan

2
@trichoplax nguyên tắc pareto áp dụng rất tốt ở đây. 20% nguyên nhân (các dòng mã) gây ra 80% hiệu ứng (thời gian chạy)
njzk2

16

Vòng lặp.

Tôi muốn dừng lại ở đó! :-)

Xem xét chương trình này

1. do_something

2. loop 10 times
3.    do_another_thing

4.    loop 5 times
5.        do_more_stuff

Dòng 1 được thực thi một lần trong khi dòng 3 được thực thi 10 lần. Nhìn lần lượt từng dòng

1 1   0.8%
2 10  8.3%
3 10  8.3%
4 50 41.3%
5 50 41.3%

Hai dòng chiếm 83% thời gian thực hiện (giả sử tất cả các dòng mất khoảng thời gian giống nhau để chạy. Vì vậy, 40% chương trình mất> 80%.

Với các ví dụ thực tế lớn hơn, điều này tăng lên, do đó chỉ một lượng nhỏ các dòng chiếm phần lớn thời gian chạy.

Quy tắc 90/10 (hoặc đôi khi đặt 80/20) là "quy tắc ngón tay cái" - chỉ gần đúng.

Xem thêm Nguyên tắc Pareto


2
Thay vì nói nó chỉ gần đúng, tôi đã nói rằng trong nhiều trường hợp, ít nhất 90% thời gian sẽ được sử dụng để thực thi một phần rất nhỏ của mã - nhiều nhất là 10%. Rõ ràng là có thể có các chương trình trong đó tất cả các phần dành cho cùng một khoảng thời gian thực hiện, nhưng điều đó rất hiếm.
supercat

+1 để tham khảo Nguyên tắc Pareto. Giải thích sâu hơn có thể được nhìn thấy trong video Vsauce tuyệt vời này .
Radu Murzea

5

Khi bạn hỏi về thời gian thực hiện, ví dụ này có thể hữu ích:

int main() {
    sleep(90); // approximately 10% of the program.
    // other 90% of the program:
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    sleep(1);
    return 0;
}

Nếu nghiêm trọng hơn một chút, điều đó có nghĩa là trong mã thực tế, bạn hầu như luôn gọi một hàm nặng trong một vòng lặp (thay vì sleep(90);), trong khi 10% còn lại bạn thực hiện một số tính toán một lần.

Một ví dụ khác là xử lý lỗi trong một số dịch vụ HA. Bất kỳ dịch vụ khả dụng cao nào cũng được thiết kế để làm việc với lượng thời gian vô hạn trong điều kiện bình thường. Nó hoạt động bình thường 99% thời gian, nhưng đôi khi, trong trường hợp có lỗi, nó chạy một số xử lý và phục hồi lỗi, thậm chí có thể phức tạp hơn về mặt logic so với chính dịch vụ.


Thật tuyệt, tôi đã hy vọng ai đó sẽ đăng ví dụ cực đoan này, điều đó cho thấy sự khác biệt rõ ràng.
djechlin

3

Lý do 90/10 có nghĩa là một phần nhỏ mã của bạn sẽ được lặp lại hoặc sử dụng nhiều hơn các mã khác. Điều này thường được sử dụng để đề xuất rằng bạn nên tập trung 90% nỗ lực phát triển / tối ưu hóa của mình trong 10% mã này.

Hãy nghĩ về một bộ xử lý văn bản bình thường, như Microsoft Word hoặc OpenOffice :

  • Hộp thoại ưu tiên, không được sử dụng nhiều;
  • Các chương trình con vẽ ký tự được sử dụng mọi lúc.

Câu nói này cũng được sử dụng trong khoa học quản lý ... Đây là một bài học cho chính cuộc sống ... Ý nghĩa: tập trung hầu hết các nỗ lực của bạn, nơi mang lại cho bạn nhiều kết quả hơn.


6
Nếu Microsoft Word đơn giản, ví dụ về một phức tạp là gì?
Peter Mortensen

@PeterMortensen mà không có ý nghĩa.
Vịt lớn

@PeterMortensen Emacs, rõ ràng.
muru

2

Hãy tưởng tượng một chương trình như thế này:

print "H"
print "e"
print "l"
print "l"
print "o"
for i=0 to 1,000,000
    print "How long now?"
next
print "B"
print "y"
print "e"

Lưu ý làm thế nào có 11 dòng ở đây trong đó 3 trong số 11 là vòng lặp for, trong đó dành bao nhiêu thời gian cho đoạn mã khá nhỏ này? Một chút trong khi 8 dòng còn lại chỉ in một ký tự. Vì vậy, hãy cẩn thận rằng trong khi một số mã có thể ngắn, điều đó không cho bạn biết tần suất thực thi và thời gian thực hiện.


0

Ngoài việc lặp, như được đề cập bởi các câu trả lời tuyệt vời khác, cũng có các nguyên tắc DRY để xem xét. Được viết tốt, mã hướng đối tượng có rất nhiều phần có thể tái sử dụng. Theo định nghĩa, những phần được sử dụng lại sẽ được sử dụng ít nhất hai lần so với những phần chỉ được thực hiện một lần. Nếu bạn có nhiều mã OO, bạn có thể có khả năng sử dụng lại một vài lớp và phương thức nhiều lần và một vài đoạn mã khác chỉ một lần.

Như đã đề cập trong các câu trả lời khác, có lẽ tốt hơn là dành nỗ lực làm cho mã được sử dụng thường xuyên hơn tốt hơn là cải thiện mã chỉ được sử dụng một lần duy nhất.


2
Bạn có thể sử dụng lại rất nhiều mã, nhưng tất cả mã đó có thể được thực thi không thường xuyên (trong khi vẫn rất quan trọng).
Peter Mortensen

@PeterMortensen "quan trọng nhưng không thường xuyên" không giống như "được sử dụng lại gần như mỗi giây và cần phải nhanh nhất có thể"
Vịt lớn

@TheGreatDuck và tôi không nghĩ đó là ý anh ấy. Bởi vì bạn có thể có mã được thực thi không thường xuyên nhưng bạn muốn nó xảy ra nhanh nhất có thể. Ví dụ: chúng ta hãy phục hồi lỗi - tùy thuộc vào ứng dụng, có thể mất một chút thời gian (5 phút, một giờ, có thể nhiều hơn) để hệ thống hoạt động trở lại. Tuy nhiên, nếu, giả sử, một hệ thống chuyến bay gặp lỗi, bạn thực sự muốn nó lên nhanh nhất có thể. Bởi vì nếu không, nó sẽ "đi xuống" và "sụp đổ" theo nghĩa đen.
VLAZ

Điều này dường như ngụ ý rằng DRY yêu cầu OO, điều này tất nhiên không đúng. Tái sử dụng được hỗ trợ như nhau bởi các chức năng miễn phí, v.v.
underscore_d

@vlaz đó là sự thật, nhưng điều đáng nói là trong một chiếc máy bay .... MỌI THỨ cần phải chạy nhanh.
Vịt lớn

0

Đó không phải là một quy tắc, đó chỉ là một số anh chàng đã chỉnh sửa Wikipedia với một vài con số thoát ra khỏi không khí mỏng và gọi đó là quy tắc. So sánh với Nguyên tắc Pareto, được thiết lập vững chắc hơn trong các bối cảnh khác. Tôi muốn xem nghiên cứu nào đã được thực hiện (nếu có) về tính chính xác của "quy tắc" này.

Nhưng về cơ bản, câu trả lời cho câu hỏi của bạn là, một số mã được thực thi thường xuyên hơn nhiều so với mã khác. Vòng lặp thường là lý do cho việc này. Các lý do khác là các cuộc gọi tốn thời gian, ví dụ như các tài nguyên bên ngoài như dịch vụ web hoặc phương tiện lưu trữ.


Đó là một điều hợp pháp mà mọi người sử dụng như một quy tắc của ngón tay cái.
Vịt lớn

Nếu bạn đang đề xuất việc này được sử dụng rộng rãi như một quy tắc chung, tôi cũng muốn thấy bằng chứng cho điều đó! Hay đó chỉ là một ý kiến ​​khác rút ra từ không khí mỏng nhưng ngụ ý là thực tế?
Brad Thomas

Nếu bạn thực sự đọc bài viết trên wikipedia bạn sẽ thấy rằng trích dẫn mà người hỏi đề cập có trích dẫn này: amazon.com/Every-Computer-Performance-Book-Computers/dp/ điều tôi chưa bao giờ thấy cá nhân sử dụng, nhưng ý kiến ​​của bạn xuất hiện là thô lỗ và bác bỏ theo ý kiến ​​của tôi nên tôi đã trả lời. Rõ ràng 10% là một con số ai đó tạo nên. Tôi có thể làm cho nó bất cứ số nào tôi muốn bằng cách làm cho chương trình của tôi không hiệu quả. Tuy nhiên, có hay không đó là một thuật ngữ được sử dụng trong công nghệ phần mềm rõ ràng là không thể tranh cãi khi thấy có bao nhiêu người ở đây đồng ý với sự tồn tại của nó.
Vịt lớn

Chà, tôi sẽ không đi mua cuốn sách chỉ để xem nghiên cứu mà nó được cho là đề cập đến ... bạn có thể đăng một trích dẫn từ nó cho thấy bằng chứng không? Hoặc trong thực tế bạn đã nhìn thấy không?
Brad Thomas

1
@BradThomas: Bằng chứng chống lại lý thuyết rằng quy tắc 90-10 được phát minh bởi một người đang chỉnh sửa Wikipedia là nó đã được trích dẫn rộng rãi, với các số 90 và 10, nhiều năm trước khi Wikipedia tồn tại; nguyên tắc thực tế không phải là chính xác 10% mã chiếm 90% thời gian chạy, mà là trong hầu hết các chương trình, một phần nhỏ của mã - 10% hoặc ít hơn , chiếm một phần lớn thời gian chạy như vậy- -90% trở lên , thậm chí cải thiện 10% hiệu năng của phần nhỏ của mã đó sẽ giảm thời gian thực hiện tổng thể hơn cải thiện 1000 lần trong mọi thứ khác.
supercat

0

Đó là sự diễn giải lại "nguyên tắc Pareto", trong đó nêu rõ "đối với nhiều sự kiện, khoảng 80% hiệu ứng đến từ 20% nguyên nhân.", Còn được gọi là quy tắc 80/20. Quy tắc này chủ yếu được áp dụng cho kinh tế, vì vậy nó có ý nghĩa rằng nó sẽ được tái định hướng cho lập trình.

Nó chỉ là một mô hình đã được quan sát trong một thời gian dài.

Đây là một video rất hay về các mẫu như thế này và nó cũng giải thích Nguyên tắc Pareto.

https://www.youtube.com/watch?v=fCn8zs912OE&ab_channel=Vsauce

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.