Khi nào tối ưu hóa không sớm và do đó không xấu?


75

"Tối ưu hóa sớm là gốc rễ của mọi tội lỗi" là điều mà hầu hết tất cả chúng ta đã nghe / đọc. Điều tôi tò mò là loại tối ưu hóa nào không sớm, tức là ở mọi giai đoạn phát triển phần mềm (thiết kế cấp cao, thiết kế chi tiết, triển khai cấp cao, triển khai chi tiết, v.v.) mức độ tối ưu hóa chúng ta có thể xem xét mà không vượt qua mặt tối.



Câu trả lời:


116

Khi bạn dựa trên kinh nghiệm? Không ác. "Mỗi lần chúng tôi thực hiện X, chúng tôi phải chịu một cú đánh thành công tàn bạo. Hãy lên kế hoạch tối ưu hóa hoặc tránh X hoàn toàn vào lúc này."

Khi nó tương đối không đau? Không ác. "Việc thực hiện điều này là Foo hoặc Bar sẽ tốn rất nhiều công sức, nhưng về mặt lý thuyết, Bar sẽ hiệu quả hơn rất nhiều. Hãy dùng nó."

Khi bạn đang tránh các thuật toán tào lao sẽ mở rộng khủng khiếp? Không ác. "Lãnh đạo công nghệ của chúng tôi cho biết thuật toán lựa chọn đường dẫn được đề xuất của chúng tôi chạy trong thời gian thực tế; tôi không chắc điều đó có nghĩa là gì, nhưng cô ấy đề nghị chúng tôi cam kết seppuku thậm chí xem xét nó. Hãy xem xét điều gì khác."

Cái ác đến từ việc dành rất nhiều thời gian và năng lượng để giải quyết các vấn đề mà bạn không biết thực sự tồn tại. Khi các vấn đề chắc chắn tồn tại, hoặc khi các vấn đề ảo ảo có thể được giải quyết với giá rẻ, tà ác sẽ biến mất.


Steve314Matthieu M. nêu quan điểm trong các ý kiến ​​nên được xem xét. Về cơ bản, một số loại tối ưu hóa "không đau" chỉ đơn giản là không có giá trị bởi vì nâng cấp hiệu suất tầm thường mà chúng cung cấp không đáng để mã hóa, chúng đang nhân đôi các cải tiến mà trình biên dịch đang thực hiện hoặc cả hai. Xem các bình luận cho một số ví dụ hay về sự không cải tiến quá thông minh.


22
Thỉnh thoảng, giải quyết một vấn đề ảo dễ dàng vẫn là một điều xấu xa, vì nó có thể dẫn đến khó đọc hơn, khó duy trì mã hơn. Không khó hơn nhiều (hoặc nó sẽ không phải là một giải pháp dễ dàng), nhưng có lẽ đôi khi vẫn có liên quan. Một ví dụ có thể đang sử dụng một thủ thuật bitwise thông minh mà một số người sẽ không nhận ra và trình biên dịch có thể sẽ áp dụng bằng mọi cách nếu nó hữu ích.
Steve314

26
Tôi đồng ý với Steve ở đây, đôi khi "tối ưu hóa" đơn giản là không đáng, đặc biệt là vì trình biên dịch quá tốt. Thí dụ ? nếu ikhông dấu, i / 2có thể được thay thế bằng i >> 1. Nó nhanh hơn Nhưng nó cũng khó hiểu hơn (không phải ai cũng sẽ thấy hiệu quả, ngay cả những người làm có thể mất thời gian). Nhưng điều tồi tệ nhất của nó là trình biên dịch sẽ làm điều đó bằng mọi cách, vậy tại sao lại làm xáo trộn mã nguồn;)?
Matthieu M.

19
@Larry: Tôi đã không làm vậy, vì vậy tôi đoán đó là một ví dụ tốt.
Joris Meys

18
Theo quan điểm của tôi, tối ưu hóa, ngay cả những thứ đơn giản, cũng nên được coi là xấu xa nếu chúng tác động đến khả năng đọc / bảo trì của mã không dựa trên các phép đo hiệu suất thực tế.
Bart van Ingen Schenau

14
@Matthew: Dạy họ những gì? Thủ đoạn bẩn thỉu và không cần thiết? Tại sao? Nếu hồ sơ cho thấy rằng i/2thực sự là một điểm nóng và rằng (không thể tin được, nhưng giả sử) i>>1làm cho nó nhanh hơn, do đó, và đưa ra một nhận xét cho rằng hồ sơ này cho thấy rằng điều này nhanh hơn. Nếu điều này thực sự cần thiết ở bất cứ đâu (mà tôi nghi ngờ, vì, như Matthieu nói, trình biên dịch nên đủ thông minh để tự làm việc này), người mới sẽ học được điều gì đó, nếu không (có khả năng), tại sao bạn muốn cắm đầu của họ với văn hóa dân gian không cần thiết?
sbi

38

Mã ứng dụng chỉ nên tốt nhất có thể, nhưng mã thư viện nên càng tốt càng tốt, vì bạn không bao giờ biết thư viện của mình sẽ được sử dụng như thế nào. Vì vậy, khi bạn viết mã thư viện, nó cần phải tốt về mọi mặt, có thể là hiệu suất, sự mạnh mẽ hoặc bất kỳ danh mục nào khác.

Ngoài ra, bạn cần suy nghĩ về hiệu suất khi bạn thiết kế ứng dụng và khi bạn chọn thuật toán . Nếu nó không được thiết kế để hoạt động, thì không có mức độ tin tặc nào có thể khiến nó hoạt động sau đó và không tối ưu hóa vi mô sẽ vượt trội hơn một thuật toán ưu việt.


5
Mã thư viện nên ghi lại liệu nó đang cố gắng "tốt nhất có thể" hay mục tiêu của nó là gì. Mã không cần phải tối ưu tuyệt đối để có ích, với điều kiện người tiêu dùng chỉ sử dụng nó khi thích hợp.
supercat

1
Xin lỗi, nhưng "tốt về mọi mặt" nghe có vẻ nghi ngờ như áp đảo. Thêm vào đó, nó có thể không thực tế - cuộc sống luôn là về sự đánh đổi.
sleske

1
+1 để nhấn mạnh giai đoạn thiết kế; nếu bạn cố tình cân nhắc lợi ích của nó, thì nó không còn sớm.
Nathan Tuggy

Ngược lại, nếu bạn không bao giờ biết thư viện của mình sẽ được sử dụng như thế nào, bạn không biết liệu dành thời gian để cải thiện nó có mang lại giá trị kinh doanh nào không. Vì vậy, đó hầu như không phải là một cuộc tranh cãi.
RemcoGerlich

25

loại tối ưu hóa nào [không] không sớm

Các loại đến như là kết quả của các vấn đề được biết đến.


17

Khi nào tối ưu hóa không sớm và do đó không xấu?

Thật khó để nói điều gì là tốt và xấu. Ai có quyền đó? Nếu chúng ta nhìn vào thiên nhiên, có vẻ như chúng ta được lập trình để sinh tồn với một định nghĩa rộng về "sự sống" bao gồm việc truyền gen của chúng ta cho con cái.

Vì vậy, tôi sẽ nói, ít nhất là theo các chức năng và lập trình cơ bản của chúng tôi, rằng tối ưu hóa không phải là xấu khi nó phù hợp với mục tiêu tái tạo. Đối với các chàng trai, có những cô gái tóc vàng, ngăm đen, đầu đỏ, nhiều đáng yêu. Đối với các cô gái, có những chàng trai, và một số trong số họ dường như là ổn.

Có lẽ chúng ta nên tối ưu hóa cho mục đích đó, và ở đó nó giúp sử dụng một hồ sơ. Trình hồ sơ sẽ cho phép bạn ưu tiên tối ưu hóa và thời gian hiệu quả hơn trên đầu trang cung cấp cho bạn thông tin chi tiết về các điểm nóng và lý do chúng xảy ra. Điều này sẽ cho bạn nhiều thời gian rảnh hơn dành cho sinh sản và theo đuổi nó.


3
Thật sảng khoái khi thấy ai đó mang đến sự tươi mới cho hạt dẻ cũ này. Tất cả chỉ cần đọc toàn bộ trích dẫn của Knuth, và không chỉ một câu, eh?
Robert Harvey

1
@RobertHarvey Tôi có một chút tiểu thư thú cưng ở đó - vì rất nhiều người dường như chỉ trích dẫn một câu đó, và rất nhiều thông tin theo ngữ cảnh quan trọng cuối cùng bị mất trong quá trình. Tôi không chắc đó là một câu trả lời tuyệt vời như vậy vì tôi đã có một chút giận dữ. :-D

14

Báo giá đầy đủ xác định khi tối ưu hóa không còn sớm:

Một lập trình viên giỏi sẽ không bị ru ngủ bởi sự tự mãn bởi lý do như vậy, anh ta sẽ khôn ngoan khi xem xét kỹ các mã quan trọng; nhưng chỉ sau khi mã đó đã được xác định . [nhấn mạnh của tôi]

Bạn có thể xác định mã quan trọng theo nhiều cách: cấu trúc dữ liệu hoặc thuật toán quan trọng (ví dụ: được sử dụng nhiều hoặc "lõi" của dự án) có thể đưa ra các tối ưu hóa lớn, nhiều tối ưu hóa nhỏ được xác định thông qua các trình biên dịch, v.v.


6
Vâng ... Sẽ rất tốt và tốt khi bạn giảm 90% thời gian cho một cuộc gọi chức năng ngẫu nhiên, nhưng có thể bạn sẽ có tác động lớn hơn bằng cách xem mã nơi ứng dụng của bạn thực sự dành 80% thời gian và tắt đi vài phần trăm ở đó

11

Bạn nên luôn luôn chọn một giải pháp "đủ tốt" trong mọi trường hợp dựa trên kinh nghiệm của bạn.

Câu nói tối ưu hóa đề cập đến việc viết "mã phức tạp hơn" đủ tốt "để làm cho nó nhanh hơn" trước khi thực sự biết rằng nó là cần thiết, do đó làm cho mã phức tạp hơn mức cần thiết. Sự phức tạp là điều làm cho mọi thứ trở nên khó khăn, vì vậy đó không phải là một điều tốt.

Điều này có nghĩa là bạn không nên chọn một thói quen sắp xếp siêu phức tạp "có thể sắp xếp 100 Gb bằng cách hoán đổi trong suốt đĩa" khi sắp xếp đơn giản sẽ làm, nhưng bạn cũng nên đưa ra lựa chọn tốt cho cách sắp xếp đơn giản ngay từ đầu. Mù quáng chọn Bubble Sort hoặc "chọn tất cả các mục ngẫu nhiên và xem chúng có theo thứ tự không. Lặp lại." hiếm khi tốt


3

Nguyên tắc chung của tôi: nếu bạn không chắc chắn bạn sẽ cần tối ưu hóa, giả sử bạn không. Nhưng hãy ghi nhớ khi bạn cần tối ưu hóa. Có một số vấn đề mà bạn có thể biết về phía trước mặc dù. Điều này thường liên quan đến việc lựa chọn các thuật toán tốt và cấu trúc dữ liệu. Ví dụ, nếu bạn cần kiểm tra tư cách thành viên trong một bộ sưu tập, bạn có thể khá chắc chắn rằng bạn sẽ cần một số loại cấu trúc dữ liệu được đặt.


3

Theo kinh nghiệm của tôi, ở giai đoạn thực hiện chi tiết, câu trả lời nằm ở việc lược tả mã. Điều quan trọng là phải biết những gì cần phải nhanh hơn và những gì được chấp nhận nhanh.

Điều quan trọng nữa là phải biết chính xác nút thắt hiệu suất ở đâu - tối ưu hóa một phần của mã chỉ mất 5% tổng thời gian để chạy sẽ không làm gì tốt.

Bước 2 và 3 mô tả tối ưu hóa không sớm:

  1. Lam cho no hoạt động
  2. Kiểm tra. Không đủ nhanh? Hồ sơ nó .
  3. Sử dụng dữ liệu từ bước 2, tối ưu hóa các phần chậm nhất của mã.

Bạn đã quên bước 0, đó là: kiến ​​trúc sư ứng dụng đúng cách để bạn có thể mong đợi hiệu suất hợp lý ngay từ đầu.
Robert Harvey

Tôi chỉ nói về giai đoạn thực hiện chi tiết.
Gorgi Kosev

1
Tôi đặt câu hỏi cho bước số 3 - rất thường xuyên câu trả lời tốt nhất là tìm ra một cách tiếp cận khác để bạn không thực hiện đoạn mã chậm ở vị trí đầu tiên.
Loren Pechtel

1
Chọn cấu trúc dữ liệu phù hợp.
jasonk

3

Đó không phải là tối ưu hóa khi chọn những thứ khó thay đổi, ví dụ: nền tảng phần cứng.

Chọn cấu trúc dữ liệu là một ví dụ tốt - quan trọng để đáp ứng các yêu cầu cả chức năng và phi chức năng (hiệu suất). Không dễ dàng thay đổi và nó sẽ lái mọi thứ khác trong ứng dụng của bạn. Cấu trúc dữ liệu của bạn thay đổi những thuật toán có sẵn, v.v.


3

Tôi chỉ biết một cách để trả lời câu hỏi này, và đó là để có kinh nghiệm trong việc điều chỉnh hiệu suất. Điều đó có nghĩa là - viết chương trình, và sau khi chúng được viết, tìm tốc độ trong đó và thực hiện lặp lại. Đây là một ví dụ.

Đây là lỗi mà hầu hết mọi người mắc phải: Họ cố gắng tối ưu hóa chương trình trước khi thực sự chạy nó. Nếu họ đã tham gia một khóa học về lập trình (từ một giáo sư không thực sự có nhiều kinh nghiệm thực tế), họ sẽ có cặp kính màu chữ O lớn, và họ sẽ nghĩ đó là tất cả những gì về nó . Tất cả đều giống nhau, tối ưu hóa trước. **

Ai đó nói: Đầu tiên hãy làm cho đúng, sau đó làm cho nhanh. Họ đã đúng.

Nhưng bây giờ đối với kicker: Nếu bạn đã làm điều này một vài lần, bạn sẽ nhận ra những điều ngớ ngẩn mà bạn đã làm trước đó gây ra vấn đề tốc độ, vì vậy bạn theo bản năng tránh chúng. (Những thứ như làm cho cấu trúc lớp của bạn quá nặng, bị ngập trong các thông báo, kích thước của các lệnh gọi khó hiểu với chi phí thời gian của chúng, danh sách cứ lặp đi lặp lại ...) Bạn theo bản năng tránh những thứ này, nhưng hãy đoán xem nó trông như thế nào có kinh nghiệm: tối ưu hóa sớm!

Vì vậy, những cuộc tranh luận ngớ ngẩn cứ lặp đi lặp lại :)

** Một điều họ nói là bạn không phải lo lắng về điều đó nữa, bởi vì trình biên dịch rất tốt và máy móc ngày nay rất nhanh. (KIWI - Kill It With Iron.) Không có sự tăng tốc phần cứng hoặc hệ thống theo cấp số nhân (được thực hiện bởi các kỹ sư làm việc rất thông minh) có thể bù đắp cho sự chậm chạp của phần mềm (được thực hiện bởi các lập trình viên nghĩ theo cách này).


2

Khi các yêu cầu hoặc thị trường đặc biệt yêu cầu nó.

Ví dụ, hiệu suất là một yêu cầu trong hầu hết các ứng dụng tài chính vì độ trễ thấp là rất quan trọng. Tùy thuộc vào bản chất của công cụ được giao dịch, tối ưu hóa có thể chuyển từ sử dụng thuật toán không khóa trong ngôn ngữ cấp cao sang sử dụng ngôn ngữ cấp thấp và thậm chí cực đoan - thực hiện các thuật toán khớp lệnh trong chính phần cứng (ví dụ sử dụng FPGA ).

Ví dụ khác sẽ là một số loại thiết bị nhúng. Lấy ví dụ như phanh ABS; Thứ nhất là an toàn, khi bạn đâm vào xe thì nên giảm tốc độ. Nhưng đó cũng là hiệu suất, bạn sẽ không muốn bất kỳ sự chậm trễ nào khi bạn nghỉ giải lao.


0

Hầu hết mọi người sẽ gọi tối ưu hóa sớm, nếu bạn tối ưu hóa một cái gì đó không dẫn đến "lỗi mềm" (nó hoạt động nhưng nó vẫn vô dụng) của hệ thống do hiệu suất.

Ví dụ thế giới thực.

  • Nếu loại bong bóng của tôi mất 20ms để chạy, tối ưu hóa nó thành quicksort 1ms sẽ không tăng cường tiện ích tổng thể theo bất kỳ cách có ý nghĩa nào mặc dù hiệu suất tăng 2000%.

  • Nếu một trang web mất 20 giây để tải và chúng tôi giảm xuống còn 1 giây, điều này có thể tăng tiện ích của trang web từ 0 đến gần vô cùng. Về cơ bản một cái gì đó đã bị hỏng vì quá chậm, bây giờ là hữu ích.


Điều quan trọng cần lưu ý là nếu loại của bạn được gọi 1000 lần trong suốt chương trình của bạn, thì tối ưu hóa từ 20ms đến 1ms là một vấn đề lớn.
Beefster

0

Những loại tối ưu hóa không phải là sớm?

Tối ưu hóa khắc phục sự cố hiệu suất đã biết với ứng dụng của bạn hoặc tối ưu hóa cho phép ứng dụng của bạn đáp ứng các tiêu chí chấp nhận được xác định rõ.

Đã được xác định, cần có thời gian để thiết lập sửa chữa và nên đo lường lợi ích hiệu suất.

(tức là không phải - "Tôi nghĩ rằng đoạn mã này có vẻ như có thể chậm, tôi sẽ thay đổi X để sử dụng Y thay vào đó và điều đó sẽ nhanh hơn").

Tôi đã gặp rất nhiều "tối ưu hóa" sớm mà cuối cùng đã làm cho mã chậm hơn - trong trường hợp này, tôi đang dùng quá sớm để có nghĩa là "không suy nghĩ thấu đáo". Hiệu suất nên được điểm chuẩn trước và sau khi tối ưu hóa và chỉ mã thực sự cải thiện hiệu suất được giữ.


0

"Tối ưu hóa sớm là gốc rễ của mọi tội lỗi" là điều mà hầu hết tất cả chúng ta đã nghe / đọc

Thật. Thật không may, nó cũng là một trong những trích dẫn lập trình bị lạm dụng (độc hại) nhất mọi thời đại. Vì Donald Knuth đã tạo ra các meme nên thêm một số bối cảnh ban đầu từ trích dẫn:

Chúng ta nên quên đi những hiệu quả nhỏ, nói về 97% thời gian: tối ưu hóa sớm là gốc rễ của mọi tội lỗi. Tuy nhiên, chúng ta không nên bỏ qua cơ hội của mình trong 3% quan trọng đó. ... Một lập trình viên giỏi ... sẽ là khôn ngoan khi xem xét kỹ mã quan trọng; nhưng chỉ sau khi mã đó đã được xác định. ... kinh nghiệm phổ quát của các lập trình viên đã và đang sử dụng các công cụ đo lường là những dự đoán trực quan của họ thất bại

Lưu ý rằng Knuth đã nói cụ thể về tốc độ thực hiện trong thời gian chạy .

.. Các lập trình viên lãng phí một lượng lớn thời gian để suy nghĩ hoặc lo lắng về tốc độ của các phần không văn bản trong các chương trình của họ ..

Ngoài ra, ông đã viết bài báo vào năm 1974 khi bất kỳ tài nguyên máy móc nào có tương quan tiêu cực và tiêu cực giữa tốc độ thực hiện và khả năng duy trì của chương trình (tốc độ cao hơn - ít bảo trì hơn) có lẽ mạnh hơn bây giờ.

OK, để trả lời câu hỏi của bạn, theo Donald Knuth, tối ưu hóa là KHÔNG sớm nếu nó khắc phục một tắc nghẽn hiệu suất nghiêm trọng đã được xác định (lý tưởng được đo lường và xác định chính xác trong quá trình định hình).

Như tôi đã nói trước đây, "tối ưu hóa sớm" là một trong những memes bị lạm dụng độc hại nhất, vì vậy câu trả lời sẽ không đầy đủ nếu không có một số ví dụ về những điều không tối ưu hóa sớm mà đôi khi bị loại bỏ như vậy:

  • nút cổ chai có thể nhìn thấy bằng mắt thường và có thể tránh được trước khi đưa vào, chẳng hạn như số lượng vòng tròn O (N ^ 2) vào cơ sở dữ liệu với N lớn thay thế tồn tại O (1)

Hơn nữa thậm chí không liên quan đến tốc độ thực hiện thời gian chạy:

  • thiết kế trả trước chu đáo

  • gõ tĩnh (!)

  • vv / bất kỳ hình thức nỗ lực tinh thần

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.