Là tối ưu hóa sớm thực sự là gốc rễ của tất cả các ác?


215

Một đồng nghiệp của tôi hôm nay đã cam kết một lớp được gọi ThreadLocalFormat, về cơ bản đã chuyển các thể hiện của các lớp Định dạng Java thành một luồng cục bộ, vì chúng không phải là luồng an toàn và "tương đối đắt" để tạo. Tôi đã viết một bài kiểm tra nhanh và tính toán rằng tôi có thể tạo ra 200.000 trường hợp một giây, hỏi anh ta có phải anh ta đã tạo ra rất nhiều, mà anh ta đã trả lời "không ở đâu gần đó". Anh ấy là một lập trình viên tuyệt vời và mọi người trong nhóm đều có tay nghề cao nên chúng tôi không có vấn đề gì trong việc hiểu mã kết quả, nhưng rõ ràng đó là một trường hợp tối ưu hóa khi không có nhu cầu thực sự. Anh ta ủng hộ mã ra theo yêu cầu của tôi. Bạn nghĩ sao? Đây có phải là một trường hợp "tối ưu hóa sớm" và nó thực sự tệ đến mức nào?


23
Tôi nghĩ bạn cần phân biệt giữa tối ưu hóa sớm và tối ưu hóa không cần thiết. Đối với tôi, đề xuất sớm 'quá sớm trong vòng đời', những gợi ý không cần thiết 'không thêm giá trị quan trọng'. IMO, yêu cầu tối ưu hóa muộn ngụ ý thiết kế kém chất lượng.

110
Đúng, nhưng cái ác là một đa thức và có nhiều gốc rễ, một số trong số chúng là phức tạp.
dan_waterworth

7
Bạn nên xem xét, rằng Knuth đã viết vào năm 1974. Trong những năm bảy mươi, không dễ để viết các chương trình chậm như ngày nay. Ông đã viết với Pascal trong tâm trí chứ không phải với Java hay PHP.
ceving

4
Không. Căn nguyên của mọi tội lỗi là lòng tham.
Tulains Córdova

12
@ceving Trong 70, thật dễ dàng như ngày nay để viết các chương trình chậm. Nếu bạn chọn sai thuật toán hoặc cấu trúc dữ liệu sai thì BAM! Hiệu suất kém khắp nơi. Người ta có thể tranh luận theo cách khác. Ngày nay, có rất nhiều công cụ và không thể sử dụng được mà một lập trình viên vẫn viết phần mềm phải chịu các hoạt động lưu cơ bản nhất. Song song gần như trở thành một hàng hóa và chúng ta vẫn phải chịu đựng. Hiệu suất chậm không thể đổ lỗi cho ngôn ngữ hoặc công cụ hoặc CPU hoặc bộ nhớ. Đó là một sự cân bằng tinh tế của rất nhiều thứ, đó là lý do tại sao gần như không thể tối ưu hóa sớm.
Alex

Câu trả lời:


322

Điều quan trọng cần ghi nhớ là trích dẫn đầy đủ:

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 đó.

Điều này có nghĩa là, trong trường hợp không có vấn đề về hiệu suất được đo, bạn không nên tối ưu hóa vì bạn nghĩ bạn sẽ đạt được hiệu suất. Có những tối ưu hóa rõ ràng (như không thực hiện nối chuỗi trong một vòng lặp chặt chẽ) nhưng bất cứ điều gì không phải là tối ưu hóa rõ ràng tầm thường nên được tránh cho đến khi có thể đo được.

Các vấn đề lớn nhất với "tối ưu hóa sớm" là nó có thể gây ra các lỗi không mong muốn và có thể là một công cụ xử lý thời gian khổng lồ.


7
Đến từ Donald Knuth, tôi sẽ không bị khuất phục nếu anh ta có một số bằng chứng để sao lưu nó. BTW, Src: Lập trình có cấu trúc với các Báo cáo, Khảo sát tính toán của Tạp chí ACM, Tập 6, Số 4, Tháng 12 năm 1974. tr.268. citeseerx.ist.psu.edu/viewdoc/ Từ
mctylr

28
... 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 (phần còn lại của trích dẫn đầy đủ hơn)
mctylr

21
Tôi đã có một người dùng đại diện 20k hôm nay nói với tôi rằng sử dụng HashSetthay vì Listtối ưu hóa sớm. Trường hợp sử dụng trong câu hỏi là một bộ sưu tập khởi tạo tĩnh mà mục đích duy nhất là để phục vụ như một bảng tra cứu. Tôi không nghĩ rằng tôi đã sai khi nói rằng có một sự khác biệt trong việc lựa chọn công cụ phù hợp cho công việc so với tối ưu hóa sớm. Tôi nghĩ rằng bài đăng của bạn xác nhận triết lý này: There are obvious optimizations...anything that isn't trivially clear optimization should be avoided until it can be measured.Việc tối ưu hóa Hashset đã được đo lường và ghi lại kỹ lưỡng.
nghiền nát

9
@crush: có: Setcũng đúng về mặt ngữ nghĩa và nhiều thông tin hơn List, vì vậy có nhiều hơn khía cạnh tối ưu hóa cho nó.
Erik Allik

7
Tôi muốn thêm rằng tối ưu hóa sớm không nên nhầm lẫn với việc thiết kế toàn bộ kiến ​​trúc ứng dụng của bạn để chạy nhanh nói chung, quy mô và có thể dễ dàng tối ưu hóa.
Erik Allik

111

Tối ưu hóa vi mô sớm là gốc rễ của mọi tội lỗi, bởi vì tối ưu hóa vi mô rời khỏi bối cảnh. Họ gần như không bao giờ cư xử theo cách họ mong đợi.

Một số tối ưu hóa tốt ban đầu theo thứ tự quan trọng là gì:

  • Tối ưu hóa kiến ​​trúc (cấu trúc ứng dụng, cách thức thành phần hóa và lớp)
  • Tối ưu hóa luồng dữ liệu (bên trong và bên ngoài ứng dụng)

Một số tối ưu hóa chu kỳ phát triển giữa:

  • Cấu trúc dữ liệu, giới thiệu cấu trúc dữ liệu mới có hiệu suất tốt hơn hoặc chi phí thấp hơn nếu cần thiết
  • Các thuật toán (bây giờ là thời điểm tốt để bắt đầu quyết định giữa quicksort3 và heapsort ;-))

Một số tối ưu hóa chu kỳ phát triển kết thúc

  • Tìm điểm nóng mã (vòng lặp chặt chẽ, cần được tối ưu hóa)
  • Cấu hình tối ưu hóa dựa trên các phần tính toán của mã
  • Tối ưu hóa vi mô có thể được thực hiện ngay bây giờ vì chúng được thực hiện trong bối cảnh của ứng dụng và tác động của chúng có thể được đo lường chính xác.

Không phải tất cả các tối ưu hóa ban đầu đều là xấu, tối ưu hóa vi mô là xấu nếu thực hiện không đúng thời điểm trong vòng đời phát triển , vì chúng có thể ảnh hưởng tiêu cực đến kiến ​​trúc, có thể ảnh hưởng tiêu cực đến năng suất ban đầu, có thể là hiệu suất không liên quan hoặc thậm chí có tác động bất lợi ở cuối của sự phát triển do điều kiện môi trường khác nhau.

Nếu hiệu suất là mối quan tâm (và luôn luôn nên) luôn luôn nghĩ lớn . Hiệu suất là một bức tranh lớn hơn và không phải là về những thứ như: tôi nên sử dụng int hay lâu ? Đi lên trên xuống khi làm việc với hiệu suất thay vì từ dưới lên .


"Tối ưu hóa: Kẻ thù tồi tệ nhất của bạn", bởi Joseph M. Người mới: flounder.com/optimization.htmlm
Ron Ruble

53

tối ưu hóa mà không cần đo lường đầu tiên là gần như luôn luôn sớm.

Tôi tin rằng điều đó đúng trong trường hợp này và cũng đúng trong trường hợp chung.


Ở đây ở đây! Tối ưu hóa vô thức làm cho mã không thể duy trì và thường là nguyên nhân của các vấn đề hiệu suất. ví dụ: Bạn đa luồng một chương trình vì bạn tưởng tượng nó có thể giúp thực hiện, nhưng, giải pháp thực sự sẽ là nhiều quy trình hiện quá phức tạp để thực hiện.
James Anderson

trừ khi nó được ghi nhận.
nawfal

Đúng. hoàn toàn đồng ý. Nó đầu tiên phải được đo. Không có cách nào bạn biết nút thắt ở đâu cho đến khi bạn kiểm tra một cái gì đó từ đầu đến cuối và đo từng bước.
Oliver Watkins

Các phép đo có thể nói dối. Tôi đã thấy các chuyên gia dày dạn dành hàng tuần để đọc các dấu vết và chạy hồ sơ để đánh vào một bức tường nơi họ nghĩ rằng không còn gì để đạt được. Sau đó, tôi đọc toàn bộ mã và trong vài giờ đã thực hiện một vài thay đổi toàn diện để đạt được sự cải thiện gấp 10 lần. Các hồ sơ cho thấy không có đường dẫn nóng vì toàn bộ mã được thiết kế kém. Tôi cũng đã thấy các hồ sơ yêu cầu các đường dẫn nóng, nơi không nên có bất kỳ. Một người "đo lường" sẽ tối ưu hóa hotpath, nhưng họ nên nhận ra rằng hotpath là một triệu chứng của mã kém khác.
Bengie

42

Tối ưu hóa là "xấu xa" nếu nó gây ra:

  • mã ít rõ ràng hơn
  • nhiều mã hơn
  • mã kém an toàn
  • lãng phí thời gian lập trình viên

Trong trường hợp của bạn, có vẻ như một ít thời gian lập trình viên đã được sử dụng, mã không quá phức tạp (một phỏng đoán từ nhận xét của bạn mà mọi người trong nhóm sẽ có thể hiểu được) và mã là bằng chứng trong tương lai hơn một chút chủ đề an toàn bây giờ, nếu tôi hiểu mô tả của bạn). Âm thanh như chỉ có một chút xấu xa. :)


4
Chỉ khi chi phí, nó tính theo điểm đạn của bạn, lớn hơn giá trị khấu hao được giao. Thông thường sự phức tạp giới thiệu giá trị, và trong những trường hợp này, người ta có thể gói gọn nó để nó vượt qua các tiêu chí của bạn. Nó cũng được tái sử dụng và tiếp tục cung cấp nhiều giá trị hơn.

1
Hai điểm đầu tiên là những điểm chính đối với tôi, với điểm thứ tư là hậu quả tiêu cực của việc tối ưu hóa sớm. Đặc biệt, đó là một lá cờ đỏ bất cứ khi nào tôi thấy ai đó thực hiện lại các tính năng từ một thư viện tiêu chuẩn. Giống như, tôi đã từng thấy ai đó thực hiện các thói quen tùy chỉnh cho thao tác chuỗi vì anh ta lo ngại rằng các lệnh tích hợp quá chậm.
jhocking

8
Làm cho chủ đề mã an toàn không phải là tối ưu hóa.
mattnz

38

Tôi ngạc nhiên khi câu hỏi này đã 5 tuổi, nhưng chưa ai đăng nhiều hơn những gì Knuth đã nói hơn một vài câu. Một vài đoạn xung quanh câu nói nổi tiếng giải thích nó khá tốt. Bài báo đang được trích dẫn có tên là " Lập trình có cấu trúc đi đến Tuyên bố ", và trong khi nó đã gần 40 tuổi, nói về một cuộc tranh cãi và một phong trào phần mềm không còn tồn tại, và có những ví dụ trong ngôn ngữ lập trình mà nhiều người chưa bao giờ nghe nói, một lượng lớn đáng ngạc nhiên của những gì nó nói vẫn được áp dụng.

Đây là một trích dẫn lớn hơn (từ trang 8 của pdf, trang 268 trong bản gốc):

Sự cải thiện về tốc độ từ Ví dụ 2 đến Ví dụ 2a chỉ khoảng 12% và nhiều người sẽ phát âm không đáng kể. Sự khôn ngoan thông thường được chia sẻ bởi nhiều kỹ sư phần mềm ngày nay kêu gọi bỏ qua hiệu quả trong nhỏ; nhưng tôi tin rằng đây đơn giản là một phản ứng thái quá đối với các hành vi lạm dụng mà họ thấy được thực hiện bởi các lập trình viên ngu ngốc và khôn ngoan, những người không thể gỡ lỗi hoặc duy trì các chương trình "tối ưu hóa" của họ. Trong các ngành kỹ thuật được thành lập, cải thiện 12%, dễ dàng đạt được, không bao giờ được coi là cận biên; và tôi tin rằng quan điểm tương tự sẽ chiếm ưu thế trong công nghệ phần mềm. Tất nhiên tôi sẽ không bận tâm đến việc tối ưu hóa như vậy trong công việc một lần, nhưng khi đó là câu hỏi về việc chuẩn bị các chương trình chất lượng, tôi không muốn giới hạn bản thân mình cho các công cụ từ chối tôi hiệu quả như vậy.

Không có nghi ngờ rằng chén hiệu quả dẫn đến lạm dụng. 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 chương trình của họ và những nỗ lực này có hiệu quả thực sự có tác động tiêu cực mạnh khi gỡ lỗi và bảo trì. 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ẽ 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. Nó thường là một sai lầm khi đưa ra đánh giá tiên nghiệm về những phần nào của chương trình thực sự quan trọng, vì kinh nghiệm phổ quát của các lập trình viên đã sử dụng các công cụ đo lường là dự đoán trực quan của họ thất bại.

Một chút tốt từ trang trước:

Phong cách lập trình của riêng tôi tất nhiên đã thay đổi trong thập kỷ qua, theo xu hướng của thời đại (ví dụ, tôi không còn quá khó khăn nữa và tôi sử dụng ít đi hơn), nhưng sự thay đổi lớn trong phong cách của tôi là do đến hiện tượng vòng lặp bên trong này. Bây giờ tôi nhìn bằng con mắt cực kỳ nguy hiểm ở mọi hoạt động trong một vòng lặp quan trọng bên trong, tìm cách sửa đổi chương trình và cấu trúc dữ liệu của tôi (như thay đổi từ Ví dụ 1 sang Ví dụ 2) để có thể loại bỏ một số thao tác. Lý do cho cách tiếp cận này là: a) nó không mất nhiều thời gian, vì vòng lặp bên trong ngắn; b) tiền chi trả là có thật; và c) Sau đó tôi có thể đủ khả năng để hoạt động kém hiệu quả hơn trong các phần khác của chương trình của mình, do đó dễ đọc hơn và dễ dàng viết và gỡ lỗi hơn.


20

Tôi thường thấy trích dẫn này được sử dụng để biện minh cho mã hoặc mã rõ ràng là xấu, trong khi hiệu suất của nó chưa được đo lường, có thể được thực hiện nhanh hơn khá dễ dàng, mà không làm tăng kích thước mã hoặc ảnh hưởng đến khả năng đọc của nó.

Nói chung, tôi nghĩ rằng tối ưu hóa vi mô sớm có thể là một ý tưởng tồi. Tuy nhiên, tối ưu hóa vĩ mô (những thứ như chọn thuật toán O (log N) thay vì O (N ^ 2)) thường đáng giá và nên được thực hiện sớm, vì có thể lãng phí khi viết thuật toán O (N ^ 2) và sau đó ném nó đi hoàn toàn theo hướng tiếp cận O (log N).

Lưu ý các từ có thể là : nếu thuật toán O (N ^ 2) đơn giản và dễ viết, bạn có thể vứt nó đi sau mà không cảm thấy tội lỗi nếu nó trở nên quá chậm. Nhưng nếu cả hai thuật toán đều phức tạp tương tự nhau hoặc nếu khối lượng công việc dự kiến ​​quá lớn mà bạn đã biết bạn sẽ cần nhanh hơn, thì tối ưu hóa sớm là một quyết định kỹ thuật âm thanh sẽ giảm tổng khối lượng công việc của bạn trong thời gian dài.

Vì vậy, nói chung, tôi nghĩ cách tiếp cận phù hợp là tìm hiểu các tùy chọn của bạn là gì trước khi bạn bắt đầu viết mã và có ý thức chọn thuật toán tốt nhất cho tình huống của bạn. Quan trọng nhất, cụm từ "tối ưu hóa sớm là gốc rễ của mọi tội lỗi" không phải là lý do cho sự thiếu hiểu biết. Các nhà phát triển nghề nghiệp nên có một ý tưởng chung về chi phí cho các hoạt động phổ biến; họ nên biết, ví dụ,

  • chuỗi đó có giá cao hơn số
  • các ngôn ngữ động chậm hơn nhiều so với các ngôn ngữ gõ tĩnh
  • những lợi thế của danh sách mảng / vector so với danh sách được liên kết và ngược lại
  • khi nào sử dụng hashtable, khi nào sử dụng bản đồ được sắp xếp và khi nào sử dụng heap
  • rằng (nếu chúng hoạt động với thiết bị di động) "double" và "int" có hiệu suất tương tự trên máy tính để bàn (FP thậm chí có thể nhanh hơn) nhưng "double" có thể chậm hơn hàng trăm lần trên các thiết bị di động cấp thấp không có FPU;
  • việc truyền dữ liệu qua internet chậm hơn so với truy cập ổ cứng, ổ cứng chậm hơn RAM rất nhiều, RAM chậm hơn nhiều so với bộ nhớ cache và đăng ký L1 và các hoạt động internet có thể chặn vô thời hạn (và thất bại bất cứ lúc nào).

Và các nhà phát triển nên làm quen với một hộp công cụ cấu trúc dữ liệu và thuật toán để họ có thể dễ dàng sử dụng các công cụ phù hợp cho công việc.

Có nhiều kiến ​​thức và hộp công cụ cá nhân cho phép bạn tối ưu hóa gần như dễ dàng. Đặt nhiều nỗ lực vào một tối ưu hóa có thể không cần thiết xấu xa (và tôi thừa nhận đã rơi vào cái bẫy đó hơn một lần). Nhưng khi tối ưu hóa dễ dàng như chọn một tập hợp / hàm băm thay vì một mảng hoặc lưu trữ một danh sách các số thành hai [] thay vì chuỗi [], thì tại sao không? Tôi có thể không đồng ý với Knuth ở đây, tôi không chắc, nhưng tôi nghĩ anh ta đang nói về tối ưu hóa cấp thấp trong khi tôi đang nói về tối ưu hóa cấp cao.

Hãy nhớ rằng, trích dẫn đó có nguồn gốc từ năm 1974. Vào năm 1974, máy tính hoạt động chậm và sức mạnh tính toán đắt đỏ, điều này khiến một số nhà phát triển có xu hướng tối đa hóa quá mức, từng dòng một. Tôi nghĩ đó là những gì Knuth đang chống lại. Anh ấy đã không nói "đừng lo lắng về hiệu suất", bởi vì vào năm 1974, đó sẽ chỉ là một cuộc nói chuyện điên rồ. Knuth đang giải thích cách tối ưu hóa; Nói tóm lại, người ta chỉ nên tập trung vào các nút thắt cổ chai, và trước khi bạn làm điều đó, bạn phải thực hiện các phép đo để tìm ra các nút thắt cổ chai.

Lưu ý rằng bạn không thể tìm thấy các nút cổ chai cho đến khi bạn đã viết một chương trình để đo lường, điều đó có nghĩa là một số quyết định về hiệu suất phải được đưa ra trước khi có bất cứ điều gì tồn tại để đo lường. Đôi khi những quyết định này rất khó thay đổi nếu bạn hiểu sai. Vì lý do này, thật tốt khi có một ý tưởng chung về những thứ chi phí để bạn có thể đưa ra quyết định hợp lý khi không có dữ liệu cứng.

Làm thế nào sớm để tối ưu hóa, và bao nhiêu lo lắng về hiệu suất phụ thuộc vào công việc. Khi viết các kịch bản mà bạn sẽ chỉ chạy một vài lần, lo lắng về hiệu suất hoàn toàn thường là một sự lãng phí hoàn toàn thời gian. Nhưng nếu bạn làm việc cho Microsoft hoặc Oracle và bạn đang làm việc trên một thư viện mà hàng ngàn nhà phát triển khác sẽ sử dụng theo hàng ngàn cách khác nhau, bạn có thể trả tiền để tối ưu hóa địa ngục, để bạn có thể bao quát tất cả sự đa dạng trường hợp sử dụng hiệu quả. Mặc dù vậy, nhu cầu về hiệu suất phải luôn được cân bằng với nhu cầu về khả năng đọc, duy trì, thanh lịch, mở rộng, v.v.


2
Amen. Tối ưu hóa sớm được ném ra xung quanh quá tự do những ngày này bởi những người cố gắng biện minh bằng cách sử dụng công cụ sai cho công việc. Nếu bạn biết công cụ phù hợp cho công việc trước thời hạn, thì không có lý do gì để không sử dụng nó.
nghiền nát

13

Cá nhân, như được đề cập trong một chủ đề trước , tôi không tin tối ưu hóa sớm là xấu trong các tình huống mà bạn biết bạn sẽ gặp vấn đề về hiệu suất. Ví dụ, tôi viết phần mềm mô hình hóa và phân tích bề mặt, nơi tôi thường xuyên giao dịch với hàng chục triệu thực thể. Lập kế hoạch cho hiệu suất tối ưu ở giai đoạn thiết kế vượt trội hơn nhiều so với tối ưu hóa muộn của một thiết kế yếu.

Một điều khác cần xem xét là ứng dụng của bạn sẽ mở rộng như thế nào trong tương lai. Nếu bạn cho rằng mã của bạn sẽ có tuổi thọ dài, tối ưu hóa hiệu suất ở giai đoạn thiết kế cũng là một ý tưởng tốt.

Theo kinh nghiệm của tôi, tối ưu hóa muộn cung cấp phần thưởng ít ỏi với giá cao. Tối ưu hóa ở giai đoạn thiết kế, thông qua lựa chọn thuật toán và tinh chỉnh, là cách tốt hơn. Tùy thuộc vào một trình hồ sơ để hiểu cách mã của bạn hoạt động không phải là một cách tuyệt vời để có được mã hiệu suất cao, bạn nên biết điều này trước.


Điều này chắc chắn là chính xác. Tôi đoán rằng tối ưu hóa sớm là khi mã được thực hiện phức tạp / khó hiểu hơn vì lợi ích không rõ ràng, theo cách chỉ có tác động cục bộ (thiết kế có tác động toàn cầu).
Paul de Vrieze

2
Đó là tất cả về định nghĩa. Tôi lấy tối ưu hóa như thiết kế và viết mã để thực hiện một cách tối ưu. Hầu hết ở đây dường như coi nó là hack về mã khi họ thấy nó không đủ nhanh hoặc hiệu quả. Tôi dành nhiều thời gian để tối ưu hóa, thường là trong quá trình thiết kế.

3
Tối ưu hóa thiết kế khi bắt đầu, Tối ưu hóa mã ở cuối.
BCS

Bạn khá đúng trong trường hợp của bạn, tuy nhiên đối với hầu hết các lập trình viên, họ tin rằng họ sẽ gặp vấn đề về hiệu năng, nhưng thực tế họ sẽ không bao giờ làm thế. Nhiều người lo lắng về hiệu suất khi xử lý 1000 thực thể, khi thử nghiệm cơ bản trên dữ liệu sẽ cho thấy hiệu suất vẫn ổn cho đến khi họ đạt 1000000 thực thể.
Toby Allen

1
"Lập kế hoạch cho hiệu suất tối ưu ở giai đoạn thiết kế vượt trội hơn nhiều so với tối ưu hóa muộn của thiết kế yếu" và "tối ưu hóa muộn cung cấp phần thưởng ít ỏi ở mức giá cao" rất tốt! Có lẽ không đúng với 97% của tất cả các hệ thống được sản xuất, nhưng nó là dành cho nhiều người - nhiều hệ thống không chắc chắn -.
Olof Forshell 10/03/2015

10

Trong thực tế, tôi đã học được rằng không tối ưu hóa sớm thường là gốc rễ của mọi tội lỗi.

Khi mọi người viết phần mềm, ban đầu nó sẽ gặp vấn đề, như mất ổn định, tính năng hạn chế, khả năng sử dụng kém và hiệu suất kém. Tất cả những thứ này thường được sửa, khi phần mềm đáo hạn.

Tất cả những thứ này, ngoại trừ hiệu suất. Không ai quan tâm đến hiệu suất. Lý do rất đơn giản: nếu một phần mềm gặp sự cố, ai đó sẽ sửa lỗi và đó là, nếu một tính năng bị thiếu, ai đó sẽ thực hiện và thực hiện, nếu phần mềm có hiệu suất kém thì trong nhiều trường hợp không phải do thiếu vi mô, nhưng do thiết kế xấu và không ai sẽ chạm vào thiết kế của phần mềm. KHÔNG BAO GIỜ.

Nhìn vào Bochs. Nó chậm như địa ngục. Nó sẽ bao giờ nhanh hơn? Có thể, nhưng chỉ trong phạm vi một vài phần trăm. Nó sẽ không bao giờ có được hiệu năng tương đương với phần mềm ảo hóa như VMWare hoặc VBox hoặc thậm chí QEMU. Bởi vì nó chậm theo thiết kế!

Nếu vấn đề của một phần mềm là nó chậm, thì vì nó RẤT chậm và điều này chỉ có thể được khắc phục bằng cách cải thiện hiệu suất bằng vô số. + 10% đơn giản sẽ không làm cho phần mềm chậm nhanh. Và bạn thường sẽ không nhận được hơn 10% bằng cách tối ưu hóa sau này.

Vì vậy, nếu hiệu suất là BẤT KY quan trọng đối với phần mềm của bạn, bạn nên tính đến điều đó ngay từ đầu, khi thiết kế phần mềm, thay vì nghĩ "ồ, nó chậm, nhưng chúng ta có thể cải thiện điều đó sau". Bởi vì bạn không thể!

Tôi biết rằng điều đó không thực sự phù hợp với trường hợp cụ thể của bạn, nhưng nó trả lời cho câu hỏi chung "Tối ưu hóa sớm có thực sự là gốc rễ của mọi tội lỗi không?" - với số KHÔNG rõ ràng.

Mọi tối ưu hóa, giống như bất kỳ tính năng, vv phải được thiết kế cẩn thận và thực hiện cẩn thận. Và bao gồm một đánh giá thích hợp về chi phí và lợi ích. Không tối ưu hóa một thuật toán để lưu một vài chu kỳ ở đây và ở đó, khi nó không tạo ra mức tăng hiệu suất có thể đo được.

Ví dụ: bạn có thể cải thiện hiệu suất của chức năng bằng cách nội tuyến, có thể tiết kiệm một số chu kỳ, nhưng đồng thời bạn có thể tăng kích thước của tệp thực thi của mình, tăng cơ hội TLB và bộ nhớ cache mất chi phí hàng nghìn chu kỳ hoặc thậm chí hoạt động phân trang, sẽ giết hiệu suất hoàn toàn. Nếu bạn không hiểu những điều này, "tối ưu hóa" của bạn có thể trở nên tồi tệ.

Tối ưu hóa ngu ngốc là xấu xa hơn tối ưu hóa "sớm", nhưng cả hai vẫn tốt hơn so với không tối ưu hóa sớm.


6

Có hai vấn đề với PO: thứ nhất, thời gian phát triển được sử dụng cho công việc không thiết yếu, có thể được sử dụng để viết nhiều tính năng hơn hoặc sửa nhiều lỗi hơn và thứ hai là ý thức bảo mật sai lầm rằng mã đang chạy hiệu quả. PO thường liên quan đến việc tối ưu hóa mã sẽ không phải là cổ chai, trong khi không nhận thấy mã sẽ. Bit "sớm" có nghĩa là tối ưu hóa được thực hiện trước khi một vấn đề được xác định bằng các phép đo thích hợp.

Về cơ bản, vâng, điều này nghe có vẻ như tối ưu hóa sớm, nhưng tôi không nhất thiết phải sao lưu trừ khi nó giới thiệu các lỗi - sau tất cả, nó đã được tối ưu hóa ngay bây giờ (!)


Bạn có nghĩa là nói "viết nhiều bài kiểm tra" thay vì "viết nhiều tính năng hơn", phải không? :)
Greg Hewgill

1
nhiều tính năng hơn đòi hỏi nhiều bài kiểm tra hơn :)
workmad3

À, vâng! Đó chính xác là những gì tôi muốn nói ...
harriyott

2
Mã giới thiệu phức tạp hơn nữa, và có thể sẽ không được sử dụng phổ biến. Sao lưu nó (và những thứ tương tự) ra giữ cho mã sạch sẽ.
Paul de Vrieze

3

Tôi tin rằng đó là cái mà Mike Cohn gọi là 'mạ vàng' mã - tức là dành thời gian cho những thứ có thể tốt nhưng không cần thiết.

Ông khuyên chống lại nó.

PS 'Mạ vàng' có thể là loại chuông có chức năng đặc biệt khôn ngoan. Khi bạn nhìn vào mã, nó có dạng tối ưu hóa không cần thiết, các lớp 'được chứng minh trong tương lai', v.v.


2
Tôi nghĩ rằng "mạ vàng" khác với tối ưu hóa. Tối ưu hóa nói chung là tất cả về việc cố gắng đạt được hiệu suất cao nhất trong khi "mạ vàng" là về việc thêm "chuông và còi" (tất cả các chức năng bổ sung) không quan trọng đối với sản phẩm nhưng có vẻ rất tuyệt vời.
Scott Dorman

3

Vì không có vấn đề gì trong việc hiểu mã, nên trường hợp này có thể được coi là một ngoại lệ.

Nhưng trong tối ưu hóa chung dẫn đến mã ít đọc và dễ hiểu hơn và chỉ nên được áp dụng khi cần thiết. Một ví dụ đơn giản - nếu bạn biết rằng bạn phải sắp xếp chỉ một vài yếu tố - thì hãy sử dụng BubbleSort. Nhưng nếu bạn nghi ngờ rằng các yếu tố có thể tăng lên và bạn không biết bao nhiêu, thì tối ưu hóa với QuickSort (chẳng hạn) không phải là xấu, mà là điều bắt buộc. Và điều này nên được xem xét trong quá trình thiết kế chương trình.


1
Đừng đồng ý. Tôi muốn nói không bao giờ sử dụng một loại bong bóng. Quicksort đã trở thành một tiêu chuẩn defacto và được hiểu rõ, và dễ thực hiện như một loại bong bóng trong tất cả các kịch bản. Mẫu số chung thấp nhất không còn thấp nữa;)

1
Đối với số lượng vật phẩm thực sự nhỏ, việc đệ quy cần thiết cho quicksort có thể làm cho nó chậm hơn một bong bóng phong nha mặc dù ... không đề cập đến việc một bong bóng nhanh hơn trong trường hợp xấu nhất của quicksort (cụ thể là nhanh chóng liệt kê danh sách đã sắp xếp)
workmad3

vâng, nhưng đó chỉ là một ví dụ về cách chọn thuật toán cho các nhu cầu khác nhau;)

Đúng, nhưng tôi sẽ có quicksort như là loại sắp xếp mặc định của tôi. Nếu tôi nghĩ bubbleort sẽ cải thiện hiệu suất, đây sẽ là một sự tối ưu hóa, không phải là cách khác. Tôi chọn quicksort làm mặc định của mình vì nó được hiểu rõ và thường tốt hơn.

2
Ý tưởng của tôi về một loại sắp xếp mặc định là bất cứ điều gì thư viện cung cấp cho tôi (qsort (), .sort (), (sort ...), bất cứ điều gì).
David Thornley

3

Tôi đã thấy rằng vấn đề với tối ưu hóa sớm hầu hết xảy ra khi viết lại mã hiện có để nhanh hơn. Tôi có thể thấy làm thế nào có thể là một vấn đề khi viết một số tối ưu hóa phức tạp ở nơi đầu tiên, nhưng chủ yếu tôi thấy tối ưu hóa sớm nuôi dưỡng cái đầu xấu xí của nó trong việc sửa chữa những gì không (được biết là) đã phá vỡ.

Và ví dụ tồi tệ nhất về điều này là bất cứ khi nào tôi thấy ai đó triển khai lại các tính năng từ một thư viện chuẩn. Đó là một lá cờ đỏ lớn. Giống như, tôi đã từng thấy ai đó thực hiện các thói quen tùy chỉnh cho thao tác chuỗi vì anh ta lo ngại rằng các lệnh tích hợp quá chậm.

Điều này dẫn đến mã khó hiểu hơn (xấu) và mất nhiều thời gian cho công việc có lẽ không hữu ích (xấu).


3

Từ một góc nhìn khác, theo kinh nghiệm của tôi, hầu hết các lập trình viên / nhà phát triển không có kế hoạch thành công và "nguyên mẫu" hầu như luôn luôn trở thành Phiên bản 1.0. Tôi có trải nghiệm đầu tiên với 4 sản phẩm gốc riêng biệt, trong đó mặt trước sang trọng, gợi cảm và chức năng cao (về cơ bản là UI) dẫn đến sự chấp nhận và nhiệt tình của người dùng trên diện rộng. Trong mỗi sản phẩm này, các vấn đề về hiệu suất bắt đầu xuất hiện trong khoảng thời gian tương đối ngắn (1 đến 2 năm), đặc biệt là khi các khách hàng lớn hơn, khó tính hơn, bắt đầu chấp nhận sản phẩm. Hiệu suất rất sớm thống trị danh sách các vấn đề, mặc dù phát triển tính năng mới chiếm ưu thế trong danh sách ưu tiên của quản lý. Khách hàng ngày càng trở nên thất vọng hơn khi mỗi bản phát hành thêm các tính năng mới nghe có vẻ hay nhưng gần như không thể truy cập được do vấn đề về hiệu suất.

Vì vậy, các lỗi thiết kế và triển khai rất cơ bản mà ít hoặc không quan tâm trong "loại nguyên mẫu" đã trở thành vật cản lớn cho sự thành công lâu dài của các sản phẩm (và các công ty).

Bản demo khách hàng của bạn có thể trông và hoạt động tốt trên máy tính xách tay của bạn với XML DOM, SQL Express và nhiều dữ liệu được lưu trong bộ nhớ cache phía máy khách. Hệ thống sản xuất có thể sẽ gặp sự cố nếu bạn thành công.

Vào năm 1976, chúng tôi vẫn đang tranh luận về các cách tối ưu để tính căn bậc hai hoặc sắp xếp một mảng lớn và câu ngạn ngữ của Don Knuth đã hướng đến sai lầm là tập trung vào việc tối ưu hóa loại thói quen cấp thấp đó ngay từ đầu trong quá trình thiết kế thay vì tập trung vào giải quyết vấn đề và sau đó tối ưu hóa các vùng mã hóa cục bộ.

Khi người ta lặp lại câu ngạn ngữ như một cái cớ để không viết mã hiệu quả (C ++, VB, T-SQL hoặc cách khác) hoặc vì không thiết kế đúng cách lưu trữ dữ liệu hoặc không xem xét kiến ​​trúc công việc mạng, thì IMO họ chỉ đang chứng minh hiểu biết rất nông cạn về bản chất thực sự của công việc của chúng tôi. cá đuối


1
Haha, hoặc khi bản demo với ba người dùng trở thành bản phát hành 1.0 với một nghìn.
Olof Forshell

1

Tôi cho rằng nó phụ thuộc vào cách bạn định nghĩa "sớm". Làm cho chức năng cấp thấp nhanh chóng khi bạn viết không phải là xấu. Tôi nghĩ đó là một sự hiểu lầm của trích dẫn. Đôi khi tôi nghĩ rằng trích dẫn có thể làm với một số trình độ hơn. Tôi muốn phản hồi ý kiến ​​của m_pGladinator về khả năng đọc.


1

Câu trả lơi con phụ thuộc vao nhiêu thư. Tôi sẽ lập luận rằng hiệu quả là một vấn đề lớn đối với một số loại công việc nhất định, chẳng hạn như các truy vấn cơ sở dữ liệu phức tạp. Trong nhiều trường hợp khác, máy tính đang dành phần lớn thời gian chờ đợi đầu vào của người dùng, vì vậy tối ưu hóa hầu hết mã là một sự lãng phí công sức và phản tác dụng tồi tệ nhất.

Trong một số trường hợp, bạn có thể thiết kế cho hiệu quả hoặc hiệu suất (nhận thức hoặc thực tế) - chọn một thuật toán phù hợp hoặc thiết kế giao diện người dùng để các hoạt động đắt tiền nhất định xảy ra trong nền chẳng hạn. Trong nhiều trường hợp, hồ sơ hoặc các hoạt động khác để xác định các điểm nóng sẽ mang lại cho bạn lợi ích 10/90.

Một ví dụ về điều này tôi có thể mô tả là mô hình dữ liệu tôi đã từng làm cho một hệ thống quản lý vụ án tại tòa án có khoảng 560 bảng trong đó. Nó bắt đầu được chuẩn hóa ('được chuẩn hóa đẹp mắt' khi nhà tư vấn từ một công ty lớn nhất định đặt nó) và chúng tôi chỉ phải đặt bốn mục dữ liệu không chuẩn hóa vào đó:

  • Một chế độ xem cụ thể để hỗ trợ màn hình tìm kiếm

  • Một bảng duy trì kích hoạt để hỗ trợ một màn hình tìm kiếm khác không thể thực hiện được với chế độ xem cụ thể hóa.

  • Một bảng báo cáo không chuẩn hóa (điều này chỉ tồn tại vì chúng tôi phải thực hiện một số báo cáo thông lượng khi dự án kho dữ liệu bị đóng hộp)

  • Một bảng duy trì kích hoạt cho một giao diện phải tìm kiếm gần đây nhất trong số khá nhiều sự kiện khác nhau trong hệ thống.

Đây là (tại thời điểm đó) dự án J2EE lớn nhất ở Australasia - hơn 100 năm thời gian của nhà phát triển - và nó có 4 mục không chuẩn hóa trong lược đồ cơ sở dữ liệu, một trong số đó không thực sự thuộc về nó.


1

Tối ưu hóa sớm không phải là gốc rễ của TẤT CẢ tội ác, đó là điều chắc chắn. Tuy nhiên, có những nhược điểm của nó:

  • bạn đầu tư nhiều thời gian hơn trong quá trình phát triển
  • bạn đầu tư thêm thời gian để thử nghiệm nó
  • bạn đầu tư nhiều thời gian hơn để sửa các lỗi mà nếu không thì sẽ không có

Thay vì tối ưu hóa sớm, người ta có thể thực hiện các thử nghiệm khả năng hiển thị sớm, để xem liệu có nhu cầu thực sự để tối ưu hóa tốt hơn không.


1

Hầu hết những người tuân thủ "PMO" (trích dẫn một phần, nghĩa là) nói rằng tối ưu hóa phải dựa trên các phép đo và các phép đo không thể được thực hiện cho đến khi kết thúc.

Đó cũng là kinh nghiệm của tôi từ sự phát triển hệ thống lớn mà việc kiểm tra hiệu năng được thực hiện vào cuối, khi sự phát triển gần hoàn thành.

Nếu chúng ta làm theo "lời khuyên" của những người này, tất cả các hệ thống sẽ chậm đến mức khó tin. Chúng cũng sẽ đắt vì nhu cầu phần cứng của chúng lớn hơn nhiều so với dự kiến ​​ban đầu.

Tôi từ lâu đã ủng hộ việc thực hiện các bài kiểm tra hiệu năng theo định kỳ trong quá trình phát triển: nó sẽ chỉ ra cả sự hiện diện của mã mới (trước đây không có mã nào) và trạng thái của mã hiện có.

  • Hiệu năng của mã mới được triển khai có thể được so sánh với mã tương tự hiện có. "Cảm nhận" về hiệu suất của mã mới sẽ được thiết lập theo thời gian.
  • Nếu mã hiện tại đột nhiên gặp trục trặc, bạn hiểu rằng có điều gì đó đã xảy ra với nó và bạn có thể điều tra nó ngay lập tức, không (nhiều) sau đó khi nó ảnh hưởng đến toàn bộ hệ thống.

Một ý tưởng thú cưng khác là thiết bị phần mềm ở cấp độ khối chức năng. Khi hệ thống thực thi, nó thu thập thông tin về thời gian thực hiện cho các khối chức năng. Khi nâng cấp hệ thống được thực hiện, có thể xác định khối chức năng nào hoạt động như đã làm trong phiên bản trước và những khối đã xuống cấp. Trên màn hình của phần mềm, dữ liệu hiệu suất có thể được truy cập từ menu trợ giúp.

Kiểm tra này mảnh tuyệt vời về những gì PMO có thể hoặc có thể không có ý nghĩa.

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.