Khi nào 'tối ưu hóa mã' == 'cấu trúc dữ liệu'?


9

Một bài viết gần đây của ycombinator liệt kê một bình luận với các nguyên tắc của một lập trình viên tuyệt vời.

#7. Lập trình viên giỏi: Tôi tối ưu hóa mã. Lập trình viên tốt hơn: Tôi cấu trúc dữ liệu. Lập trình viên tốt nhất: sự khác biệt là gì?

Thừa nhận các khái niệm chủ quan và gây tranh cãi - có ai có một vị trí về điều này có nghĩa là gì không? Tôi có, nhưng tôi muốn chỉnh sửa câu hỏi này sau đó với suy nghĩ của mình để không dẫn đến câu trả lời.


2
Danh sách tài liệu tham khảo của bạn có một loạt các mục mát mẻ trong đó. Cảm ơn.
DeveloperDon

Câu hỏi này (mà tôi hỏi) có một câu trả lời mà đề cập đến trích dẫn này cũng như: programmers.stackexchange.com/q/168013/15028
TCSGrad

Câu trả lời:


16

Chín trong số mười lần, khi bạn cấu trúc mã / mô hình của mình tốt, tối ưu hóa sẽ trở nên rõ ràng. Đã bao nhiêu lần bạn nhìn thấy một tổ ong bắp cày và thấy nó hoàn toàn dưới mức tối ưu, khi tái cấu trúc nó, rất nhiều sự dư thừa đã trở nên vô cùng rõ ràng.

Một nhà thiết kế biết rằng anh ta đã đạt được sự hoàn hảo không phải khi không còn gì để thêm, mà là khi không còn gì để lấy đi. - Antoine de Saint-Exupery

Một hệ thống có cấu trúc tốt sẽ có bản chất tối thiểu và do tính chất tối thiểu của nó, nó sẽ được tối ưu hóa bởi vì nó có liên quan trực tiếp đến mức độ ít để thực hiện mục tiêu của nó.

Chỉnh sửa: Để giải thích về điểm mà người khác đã loại bỏ khỏi điều này, cũng hoàn toàn chính xác khi xem tuyên bố là xác định mối quan hệ giữa mã và dữ liệu. Do đó, mối quan hệ đó là: Nếu bạn thay đổi cấu trúc dữ liệu của mình, bạn sẽ cần thay đổi mã của mình để tôn trọng cấu trúc bị thay đổi. Nếu bạn muốn tối ưu hóa mã của mình, rất có thể bạn sẽ cần thay đổi cấu trúc dữ liệu của mình để làm cho mã của bạn có khả năng xử lý dữ liệu tối ưu hơn.

Điều đó nói rằng, có một khả năng hoàn toàn riêng biệt đang được trốn tránh ở đây, và đó có thể là người bạn này có quan hệ với YCombinator có thể đề cập đến mã dữ liệu AS trong truyền thống đồng âm của LISP. Đó là một sự căng thẳng để cho rằng đây là ý nghĩa trong tâm trí của tôi, nhưng đó là YCombinator vì vậy tôi sẽ không loại trừ rằng trích dẫn chỉ đơn giản nói rằng LISPers là "Lập trình viên xuất sắc nhất".


1
Điều này không nói lên "dữ liệu" và làm thế nào "không có sự khác biệt giữa tối ưu hóa mã và cấu trúc dữ liệu". Tối ưu hóa mã không cấu trúc lại dữ liệu xấu trừ khi đây là một loại máy tự tiêu hóa, hoàn thiện, máy móc
New Alexandria

1
@NewAlexandria mô hình được đề cập là "dữ liệu". Thông thường, mã xấu và một mô hình xấu đi đôi với nhau. Sửa cái này đòi hỏi phải sửa cái kia.

1
@NewAlexandria Tôi đề cập đến việc cấu trúc các mô hình của bạn như cấu trúc "dữ liệu", quan điểm của tôi chỉ đơn giản là về cấu trúc dữ liệu / mã là đồng nghĩa vì chúng là một phần của toàn bộ hệ thống và phụ thuộc lẫn nhau. Để cấu trúc tốt cũng sẽ yêu cầu thay đổi khác, đây có lẽ là nhiều hơn những gì bạn đang tìm kiếm? Tôi đã cố gắng giải thích cấu trúc và tối ưu hóa giống nhau như thế nào, không phải mã và dữ liệu có liên quan như thế nào, có lẽ tôi đã hiểu nhầm câu hỏi của bạn nếu đó là phần khó hiểu với bạn?
Jimmy Hoffa

Tôi nghĩ rằng đây là cách gần nhất để làm sáng tỏ ý nghĩa chính xác của chủ đề. Tôi chắc chắn biết làm thế nào điều này hoạt động, nhưng hy vọng rằng ai đó đã nhìn thấy một cái gì đó sâu sắc hơn trong câu hỏi tôi đã trích dẫn.
New Alexandria

4

Tôi nghĩ rằng tác giả đang gợi ý rằng bất kỳ cấu trúc lại dữ liệu đều dẫn đến tái cấu trúc mã. Do đó, việc cơ cấu lại dữ liệu với mục tiêu tối ưu hóa hệ thống của bạn cũng sẽ buộc bạn phải tối ưu hóa mã của mình, nhắc nhở "sự khác biệt là gì?" phản ứng.

Lưu ý rằng một "lập trình viên xuất sắc" có thể trả lời "sự khác biệt là gì?" có một số khác biệt còn lại ở đó: một khi bạn mạo hiểm tối ưu hóa để cải thiện việc sử dụng bộ đệm CPU, bạn có thể giữ nguyên bố cục cấu trúc dữ liệu của mình, nhưng thay đổi thứ tự bạn truy cập chúng có thể giúp ích rất nhiều Sự khác biệt.


Thú vị về điều đó, tôi có ấn tượng rằng sự tương đồng giữa cấu trúc và tối ưu hóa là chủ đề của tuyên bố, không phải là mối quan hệ giữa mã và dữ liệu, mặc dù bạn hoàn toàn đúng về mối quan hệ và điều đó cũng giải thích điều đó. Cảm thấy như chọn ra một công án :)
Jimmy Hoffa

Đôi khi cơ cấu lại dữ liệu cho phép tái cấu trúc mã, nhưng tôi nghĩ đôi khi khi bạn hoàn thành, mã mới có rất ít điểm chung với mã cũ.
Nhà phát

OTOH, việc sắp xếp dữ liệu cho kích thước dòng bộ đệm có thể có tác động lớn. ;-p
Macke

3

Hãy xem xét ví dụ rõ ràng nhất về điều này - "tìm kiếm dữ liệu người dùng quá chậm!"

Nếu dữ liệu người dùng của bạn không được lập chỉ mục hoặc ít nhất là được sắp xếp, thì việc cơ cấu lại dữ liệu của bạn sẽ nhanh chóng mang lại hiệu suất mã tăng lên. Nếu dữ liệu được cấu trúc đúng và bạn chỉ lặp qua bộ sưu tập (thay vì sử dụng các chỉ mục hoặc thực hiện một cái gì đó như tìm kiếm nhị phân) thì sửa đổi mã mang lại hiệu suất mã tăng.

Lập trình viên là người giải quyết vấn đề. Mặc dù rất hữu ích để phân biệt giữa các thuật toán và cấu trúc dữ liệu, chúng thường không thể tồn tại một cách cô lập. Các lập trình viên giỏi nhất biết điều này và không cô lập bản thân một cách không cần thiết.


1

Tôi không đồng ý với tuyên bố được đề cập ở trên, ít nhất là không cần giải thích. Tôi thấy mã hóa là hoạt động liên quan đến việc sử dụng một số cấu trúc dữ liệu. Cấu trúc dữ liệu nói chung sẽ ảnh hưởng đến mã hóa. Vì vậy, có một sự khác biệt giữa hai theo ý kiến ​​của tôi.

Tôi nghĩ rằng tác giả nên viết phần cuối là "Lập trình viên xuất sắc nhất: Tôi tối ưu hóa cả hai."

Có một cuốn sách tuyệt vời (ít nhất là khi nó được xuất bản) được gọi là: Thuật toán + Cấu trúc dữ liệu = Chương trình .


0

Tối ưu hóa mã đôi khi có thể cải thiện tốc độ theo hệ số hai, và đôi khi bằng hệ số mười hoặc thậm chí hai mươi, nhưng đó là về nó. Điều đó nghe có vẻ rất nhiều và nếu 75% thời gian thực hiện chương trình được sử dụng trong một thói quen năm dòng mà tốc độ có thể dễ dàng tăng gấp đôi, thì việc tối ưu hóa như vậy có thể đáng để thực hiện. Mặt khác, việc lựa chọn cấu trúc dữ liệu của một người có thể ảnh hưởng đến tốc độ thực hiện theo nhiều bậc độ lớn. Một bộ xử lý đa luồng được tối ưu hóa hiện đại chạy mã siêu tối ưu hóa để tra cứu dữ liệu theo khóa trong danh sách liên kết tuyến tính 10.000.000 mục được lưu trữ trong RAM sẽ chậm hơn so với bộ xử lý chậm hơn nhiều chạy bảng băm được mã hóa đơn giản. Thật vậy, nếu một người có dữ liệu được đặt ra đúng cách, thậm chí là một năm 1980 '

Điều đó đã được nói, thiết kế cấu trúc dữ liệu hiệu quả thường đòi hỏi sự đánh đổi phức tạp hơn là tối ưu hóa mã. Ví dụ, trong nhiều trường hợp, cấu trúc dữ liệu cho phép dữ liệu được truy cập hiệu quả nhất sẽ kém hiệu quả hơn để cập nhật (đôi khi theo thứ tự cường độ) so với cấu trúc cho phép cập nhật nhanh và những cấu trúc cho phép cập nhật nhanh nhất có thể cho phép truy cập chậm nhất. Hơn nữa, trong nhiều trường hợp, cấu trúc dữ liệu tối ưu cho các tập dữ liệu lớn có thể tương đối kém hiệu quả với các cấu trúc nhỏ. Một lập trình viên giỏi nên cố gắng cân bằng các yếu tố cạnh tranh đó với lượng thời gian lập trình viên cần thiết để thực hiện và duy trì các cấu trúc dữ liệu khác nhau và có thể đạt được sự cân bằng hợp lý giữa chúng.


0

Cấu trúc dữ liệu thúc đẩy rất nhiều thứ liên quan đến hiệu suất. Tôi nghĩ rằng chúng ta có thể xem xét các vấn đề khó khăn và lâu dài với một ý tưởng định sẵn về cấu trúc dữ liệu lý tưởng, và trong bối cảnh suy nghĩ này, thậm chí tạo ra bằng chứng (thường bằng cảm ứng) về sự tối ưu. Ví dụ: nếu chúng ta đặt một danh sách được sắp xếp vào một mảng và đánh giá những thứ như chi phí để chèn một phần tử, chúng ta có thể quyết định trung bình chúng ta cần thay đổi 1/2 mảng cho mỗi lần chèn. Đối với mỗi tìm kiếm nhị phân , chúng ta có thể tìm thấy một mục phù hợp (hoặc không) trong các bước đăng nhập n.

Ngoài ra, nếu chúng tôi trì hoãn quyết định về cấu trúc dữ liệu (tránh tối ưu hóa sớm ) và nghiên cứu dữ liệu đến và bối cảnh chúng tôi sẽ sử dụng dữ liệu đó, độ lớn của nó, độ trễ xảy ra và vấn đề nào đối với người dùng, chúng tôi có bao nhiêu bộ nhớ so với sẽ sử dụng với các biểu diễn dữ liệu mà chúng ta biết hoặc có thể nghĩ ra.

Trong một lĩnh vực như phân loại và tìm kiếm, có rất nhiều điều để biết. Các lập trình viên thực sự tuyệt vời đã làm việc về điều này trong một thời gian dài. Hiểu rõ các vấn đề này rất hữu ích và sẽ là một điều tuyệt vời nếu bạn biết nhiều phương thức hơn khi bạn hoàn thành lớp cấu trúc dữ liệu. Cây nhị phân có thể cung cấp hiệu suất vượt trội cho các phần chèn thêm để đổi lấy việc sử dụng bộ nhớ cao hơn. Bảng băm cung cấp những cải tiến thậm chí còn lớn hơn, nhưng vẫn còn nhiều bộ nhớ hơn. Một cây radix và loại radix có thể mang đến những cải tiến hơn nữa.

Cấu trúc dữ liệu sáng tạo có thể giúp điều chỉnh lại một vấn đề và mở ra cánh cửa cho các thuật toán mới giúp các ứng dụng cứng nhanh hơn và đôi khi không thể thực hiện được các nhiệm vụ.


0

Để đưa ra dự đoán tốt nhất của tôi về ý nghĩa của bài viết, tôi sẽ giả sử một ẩn ý không được nói (dường như bị thiếu trong bài viết) mà bất kỳ lập trình viên nào cũng nên hiểu về tối ưu hóa:

  • tối ưu hóa chỉ đến sau khi bạn có chương trình và chạy chính xác:
    • làm cho nó chạy chính xác, sau đó làm cho nó chạy nhanh
    • nguyên tắc này là điểm của câu châm ngôn của Knuth, "tối ưu hóa sớm là gốc rễ của mọi tội lỗi"
  • nếu và khi bạn xác định rằng tối ưu hóa không còn sớm, trước tiên bạn phải đo lường chính xác để xác định những gì thực sự cần tối ưu hóa, và lặp đi lặp lại trong quá trình tối ưu hóa, để cho biết những tác động của bạn khi tối ưu hóa đang có.
    • nếu mã của bạn chạy trong quá trình phát triển, trình lược tả là bạn của bạn trong việc này.
    • nếu mã của bạn chạy trong sản xuất, bạn phải sử dụng mã của mình và kết bạn với hệ thống ghi nhật ký của mình.

Bây giờ, sau đó: các phép đo của bạn sẽ cho bạn biết nơi nào trong mã của bạn, máy đang đốt nhiều chu kỳ nhất. Một lập trình viên "tốt" sẽ tập trung vào việc tối ưu hóa các phần của mã, thay vì lãng phí thời gian để tối ưu hóa các phần không liên quan.

Tuy nhiên, bạn thường có thể kiếm được lợi nhuận lớn hơn bằng cách xem xét toàn bộ hệ thống và tìm cách nào đó cho phép máy thực hiện ít công việc hơn. Thông thường, những thay đổi này yêu cầu làm lại việc tổ chức dữ liệu của bạn; do đó, một lập trình viên "tốt hơn" sẽ thấy mình cấu trúc dữ liệu thường xuyên hơn không.

"Lập trình viên giỏi nhất" sẽ có một mô hình tinh thần thấu đáo về cách thức hoạt động của máy, nền tảng tốt trong thiết kế thuật toán và hiểu biết thực tế về cách họ tương tác. Điều này cho phép anh ta coi hệ thống là một tổng thể tích hợp - anh ta sẽ thấy không có sự khác biệt giữa tối ưu hóa mã và dữ liệu, bởi vì anh ta đánh giá chúng ở cấp độ kiến ​​trúc.


-1

Lập trình viên tốt nhất: sự khác biệt là gì?

Lập trình viên giỏi nhất? Số lập trình viên tệ hại. Tôi giả sử từ "tối ưu hóa" có nghĩa là những thứ mà các lập trình viên thường cố gắng tối ưu hóa, bộ nhớ hoặc thời gian CPU. Theo nghĩa này, tối ưu hóa đi ngược lại với hầu hết các số liệu phần mềm khác. Khả năng hiểu, khả năng bảo trì, khả năng kiểm tra, v.v.: Viết một thuật toán tối ưu tốc độ / không gian có chi phí cao hơn đáng kể về thời gian của nhà phát triển so với việc mã hóa thuật toán một cách ngây thơ như được trình bày trong một số văn bản hoặc tạp chí. Một lập trình viên tệ hại không biết sự khác biệt. Một trong những tốt. Lập trình viên giỏi nhất biết cách xác định chính xác những gì cần được tối ưu hóa và thực hiện một cách thận trọng.

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.