Là tối ưu hóa vi mô quan trọng khi mã hóa?


178

Gần đây tôi đã hỏi một câu hỏi về Stack Overflow để tìm hiểu lý do tại sao isset () nhanh hơn strlen () trong PHP . Điều này đặt ra câu hỏi xung quanh tầm quan trọng của mã có thể đọc được và liệu các cải tiến hiệu suất của micro-giây trong mã có đáng để xem xét hay không.

Cha tôi là một lập trình viên đã nghỉ hưu, và tôi đã cho ông xem các câu trả lời. Ông hoàn toàn chắc chắn rằng nếu một lập trình viên không xem xét hiệu năng trong mã của họ ngay cả ở cấp vi mô thì họ không phải là lập trình viên giỏi.

Tôi không chắc lắm - có lẽ sự gia tăng sức mạnh tính toán có nghĩa là chúng ta không còn phải xem xét các loại cải tiến hiệu suất vi mô này? Có lẽ loại xem xét này là tùy thuộc vào những người viết mã ngôn ngữ thực tế? (của PHP trong trường hợp trên).

Các yếu tố môi trường có thể quan trọng - Internet tiêu thụ 10% năng lượng của thế giới. Tôi tự hỏi làm thế nào lãng phí một vài micro-giây mã khi được nhân rộng hàng nghìn tỷ lần trên hàng triệu trang web?

Tôi muốn biết câu trả lời tốt nhất dựa trên sự thật về lập trình.

Là tối ưu hóa vi mô quan trọng khi mã hóa?

Tóm tắt cá nhân của tôi về 25 câu trả lời, cảm ơn tất cả.

Đôi khi chúng ta cần thực sự lo lắng về tối ưu hóa vi mô, nhưng chỉ trong những trường hợp rất hiếm. Độ tin cậy và khả năng đọc là quan trọng hơn nhiều trong phần lớn các trường hợp. Tuy nhiên, việc xem xét tối ưu hóa vi mô theo thời gian không gây hại. Một sự hiểu biết cơ bản có thể giúp chúng ta không đưa ra những lựa chọn tồi tệ rõ ràng khi mã hóa như

if (expensiveFunction() || counter < X)

Nên là

if (counter < X || expensiveFunction())

( Ví dụ từ @ zidarsk8 ) Đây có thể là một hàm rẻ tiền và do đó thay đổi mã sẽ là tối ưu hóa vi mô. Nhưng, với một sự hiểu biết cơ bản, bạn sẽ không phải làm thế, bởi vì bạn sẽ viết nó chính xác ngay từ đầu.


123
Lời khuyên của cha đã lỗi thời . Tôi sẽ không hỏi nó cải thiện hiệu suất bao nhiêu. Tôi sẽ hỏi nút cổ chai ở đâu. Sẽ không có vấn đề gì nếu bạn cải thiện hiệu suất của một phần mã nếu nó không có sự khác biệt tổng thể, liên kết chậm nhất của bạn sẽ xác định tốc độ. Trong PHP, điều này là ghi vào mạng (trừ khi bạn có thể chứng minh biện pháp IE khác); trong đó chuyển thành viết mã dễ đọc hơn là quan trọng hơn.
Martin York

61
Nếu từ khóa được xem xét, anh ta không sai. Bạn phải có một số manh mối về nó.
JeffO

37
Tôi rất buồn vì câu nói Tối ưu hóa sớm nổi tiếng chưa được đề cập: "Các lập trình viên lãng phí rất nhiều 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 về hiệu quả thực sự có một tiêu cực mạnh Chúng ta nên quên đi hiệu quả nhỏ, nói khoảng 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 đó. "
Tamara Wijsman

13
Bạn có thể cung cấp một nguồn về "10% năng lượng của thế giới" không?
Michael Easter

17
coder does not consider performance in their code even at the micro level, they are not good programmersrất khác với tối ưu hóa vi mô. Nó chỉ là mã hóa tốt.
woliveirajr

Câu trả lời:


90

Tôi đều đồng ý và không đồng ý với bố của bạn. Hiệu suất nên được nghĩ đến sớm, nhưng tối ưu hóa vi mô chỉ nên được nghĩ đến sớm nếu bạn thực sự biết rằng phần lớn thời gian sẽ được dành cho các phần mã nhỏ của CPU.

Vấn đề với tối ưu hóa vi mô là nó thường được thực hiện mà không có bất kỳ khái niệm nào về cách các chương trình thực sự dành nhiều thời gian hơn mức cần thiết.

Kiến thức này xuất phát từ kinh nghiệm thực hiện điều chỉnh hiệu suất, như trong ví dụ này , trong đó một chương trình có vẻ đơn giản, không có hiệu quả rõ ràng, được thực hiện thông qua một loạt các bước chẩn đoán và tăng tốc, cho đến khi nó nhanh hơn 43 lần so với lúc ban đầu.

Những gì nó thể hiện là bạn không thể thực sự đoán hoặc trực giác vấn đề sẽ ở đâu. Nếu bạn thực hiện chẩn đoán, trong trường hợp của tôi là tạm dừng ngẫu nhiên , các dòng mã chịu trách nhiệm cho một phần thời gian đáng kể được ưu tiên hiển thị. Nếu bạn nhìn vào những cái đó, bạn có thể tìm thấy mã thay thế, và do đó giảm thời gian tổng thể xuống khoảng một phần.

Những thứ khác bạn không sửa vẫn mất nhiều thời gian như trước đây, nhưng vì tổng thời gian đã giảm, những thứ đó giờ chiếm phần lớn hơn, vì vậy nếu bạn làm lại tất cả, phần đó cũng có thể bị loại bỏ. Nếu bạn tiếp tục thực hiện việc này qua nhiều lần lặp, đó là cách bạn có thể tăng tốc lớn mà không nhất thiết phải thực hiện bất kỳ tối ưu hóa vi mô nào .

Sau loại kinh nghiệm đó, khi bạn tiếp cận các vấn đề lập trình mới, bạn sẽ nhận ra các phương pháp thiết kế ban đầu dẫn đến sự thiếu hiệu quả như vậy. Theo kinh nghiệm của tôi, nó xuất phát từ việc thiết kế quá mức cấu trúc dữ liệu, cấu trúc dữ liệu không chuẩn hóa, phụ thuộc lớn vào thông báo, đại loại như vậy.


120

Tối ưu hóa vi mô chỉ quan trọng nếu các con số nói rằng nó là.

Các yêu cầu mà bạn đang phát triển phải có một số đặc điểm kỹ thuật của dữ liệu hiệu suất, nếu hiệu suất hoàn toàn là vấn đề đối với khách hàng hoặc người dùng. Khi bạn đang phát triển phần mềm, bạn nên kiểm tra hiệu năng của hệ thống của mình theo các yêu cầu này. Nếu bạn không đáp ứng các yêu cầu về hiệu suất, thì bạn cần lập hồ sơ cơ sở mã của mình và tối ưu hóa khi cần để đạt được các yêu cầu về hiệu suất. Khi bạn ở trong hiệu suất yêu cầu tối thiểu, bạn không cần phải loại bỏ bất kỳ hiệu năng nào ra khỏi hệ thống, đặc biệt là nếu bạn sẽ thỏa hiệp khả năng đọc và khả năng duy trì của mã nữa (theo kinh nghiệm của tôi, mã được tối ưu hóa cao sẽ ít đọc hơn và duy trì, nhưng không phải luôn luôn). Nếu bạn có thể nhận được hiệu suất tăng thêm mà không làm giảm các thuộc tính chất lượng khác của hệ thống,

Tuy nhiên, có những trường hợp trong đó hiệu suất là vô cùng quan trọng. Tôi chủ yếu suy nghĩ trong các hệ thống thời gian thực và các hệ thống nhúng. Trong các hệ thống thời gian thực, việc thay đổi thứ tự các hoạt động có thể có tác dụng rất lớn trong việc đáp ứng các thời hạn khó khăn cần thiết cho hoạt động đúng, thậm chí có thể ảnh hưởng đến kết quả tính toán. Trong các hệ thống nhúng, bạn thường bị giới hạn bộ nhớ, sức mạnh CPU và năng lượng (như năng lượng pin), vì vậy bạn cần giảm kích thước nhị phân của mình và giảm số lượng tính toán để tối đa hóa tuổi thọ hệ thống.


Mặt khác, nếu có vấn đề giữa việc sử dụng chức năng chậm hơn so với nhanh hơn, không có lý do gì để sử dụng chức năng chậm hơn - như ở đây trong trường hợp hiện tại.
Mavrik

7
@Mavrik Đúng vậy. Nếu bạn có hai chức năng, X và Y và Y nhanh hơn X (ít nhất là đối với các điều kiện cụ thể của bạn), không có lý do gì để không sử dụng Y, nếu mã vẫn có thể đọc và duy trì được. Nhưng nếu bạn không biết về Y và bạn cần cấu trúc lại mã để sử dụng Y thay vì X và hiệu suất (của đoạn mã đó) không phải là vấn đề, thì không có lý do gì để thực hiện thay đổi đó. Đó là tất cả về sự đánh đổi - hiệu suất, thời gian, chi phí, nỗ lực, khả năng đọc / bảo trì, v.v.
Thomas Owens

2
Tôi hoàn toàn đồng ý, tôi chỉ muốn đưa ra quan điểm này khi nói đến tối ưu hóa vi mô - nếu nó không làm bạn tốn bất kỳ chi phí nào về khả năng đọc / thời gian, hãy làm điều đó. Nếu không thì không.
Mavrik

Mã được tối ưu hóa cao +1 ít có thể đọc và duy trì ... nhưng không phải lúc nào cũng vậy.
Boz

Nhiều trường hợp trong đó hiệu suất là quan trọng: (1) chơi game; (2) số lượng lớn dữ liệu; (3) trang web lưu lượng truy cập cao; (4) khả năng đáp ứng của UI rất phức tạp; (5) dịch vụ được cho là chạy trong nền như kiểm tra vi rút; (6) tài chính; (7) điện thoại thông minh; vân vân Nó hầu như không giới hạn trong các trường hợp bí truyền như RTS và các hệ thống nhúng.
Rex Kerr

103

Bất cứ khi nào bất cứ ai hỏi về tối ưu hóa , tôi đều nhắc về trích dẫn từ Michael A. Jackson

Nguyên tắc tối ưu hóa chương trình đầu tiên: Đừng làm điều đó.

Quy tắc thứ hai của Tối ưu hóa chương trình (chỉ các chuyên gia!): Đừng làm điều đó chưa .

Trích dẫn từ Wikipedia sửa cho tiếng Anh Anh. *số 8')

Ẩn trong quy tắc thứ hai là lập hồ sơ mã của bạn và chỉ dành thời gian tối ưu hóa những thứ sẽ tạo ra sự khác biệt.

Khi lập trình trong lắp ráp, khẳng định của cha bạn là chính xác. Nhưng đó là gần với kim loại hơn so với hầu hết mọi người chương trình ngày nay. Ngày nay, ngay cả việc cố gắng tối ưu hóa bản thân (mà không cần lược tả) có thể dẫn đến việc làm cho mã của bạn chạy chậm hơn so với việc bạn đã làm một cái gì đó theo cách phổ biến hơn, vì cách phổ biến có nhiều khả năng được tối ưu hóa bởi các trình biên dịch JIT hiện đại .

Ngay cả trong C, bạn phải khá giỏi trong việc tối ưu hóa để biết thêm về cách tối ưu hóa một phần mã so với trình biên dịch.

Nếu bạn không quen thuộc với hầu hết những gì Ulrich Drepper nói về bài viết xuất sắc của mình Điều mà mọi lập trình viên nên biết về bộ nhớ , thì có lẽ bạn đang thua cuộc ngay cả khi cố gắng tối ưu hóa chính mình. Tuy nhiên, trái ngược với tiêu đề bài báo (thực sự là một sự tôn kính đối với David Goldberg, điều mà mọi nhà khoa học máy tính nên biết về Số học dấu phẩy động ) không có mức độ hiểu biết này không nhất thiết ngăn bạn trở thành một lập trình viên giỏi, chỉ là một loại khác lập trình viên.

isset()so với strlen()trong PHP

Tôi không biết PHP, vì vậy nó thực sự không rõ ràng isset()là phải làm gì. Tôi có thể suy ra nó từ ngữ cảnh, nhưng điều này có nghĩa là nó sẽ tối nghĩa tương tự với các lập trình viên PHP mới làm quen và thậm chí có thể khiến các lập trình viên có kinh nghiệm hơn phải thực hiện gấp đôi. Đây là loại sử dụng thành ngữ của một ngôn ngữ có thể làm cho việc bảo trì trở thành một cơn ác mộng.

Không chỉ vậy, nhưng không có gì đảm bảo isset()sẽ luôn hiệu quả hơn, chỉ vì nó hiệu quả hơn bây giờ. Tối ưu hóa bây giờ có thể không phải là tối ưu hóa trong năm tới hoặc trong 10 năm nữa. CPU, hệ thống, trình biên dịch cải thiện và thay đổi theo thời gian. Nếu hiệu năng của PHP strlen()là một vấn đề, PHP có thể sẽ được sửa đổi trong tương lai, thì tất cả các tối ưu hóa () có thể cần phải được loại bỏ để tối ưu hóa mã một lần nữa.

Mọi tối ưu hóa đều có khả năng trở thành một khả năng chống tối ưu hóa trong tương lai , vì vậy nên được coi là một mùi mã có thể, được giữ ở mức tối thiểu.

Một ví dụ từ kinh nghiệm cá nhân

Để làm ví dụ cho việc chống tối ưu hóa như vậy , tôi đã từng phải vệ sinh một cơ sở mã lớn chứa đầy mã của biểu mẫu if x==0 z=0 else z=x*yvì ai đó đã đưa ra giả định rằng một dấu phẩy động nhân sẽ luôn đắt hơn một nhánh. Trên kiến ​​trúc đích ban đầu, việc tối ưu hóa này làm cho mã chạy nhanh hơn, nhưng thời gian thay đổi.

Khi chúng tôi thử sử dụng mã này trên một CPU hiện đại hơn, có hiệu năng cao, hiệu năng rất tệ - mỗi một trong những câu lệnh này đều gây ra lỗi đường ống. Đơn giản hóa tất cả các dòng mã này để z=x*ylàm cho chương trình chạy một trật tự cường độ nhanh hơn trên kiến ​​trúc mới, khôi phục hiệu suất bị mất do chống tối ưu hóa .

Các vấn đề chúng ta thường phải tối ưu hóa cho ngày hôm nay rất khác với những vấn đề chúng ta phải tối ưu hóa trong 20 hoặc thậm chí 10 năm trước.

Sau đó chúng ta lo lắng về làm công việc nhất cho mỗi chu kỳ đồng hồ, bây giờ chúng ta có nhiều khả năng được lo lắng về bừng đường ống, mispredictions chi nhánh và bỏ lỡ bộ nhớ cache ở cấp CPU, nhưng ổ khóa và thông tin liên lạc interprocess đang trở nên nhiều ý nghĩa hơn khi chúng ta chuyển sang đa kiến trúc quá trình và đa bộ xử lý. Giấy của Drepper thực sự có thể giúp hiểu được nhiều vấn đề này.


3
Lỗi đường ống và bộ nhớ cache là những gì bạn muốn tránh: D Họ có chi phí khủng khiếp. nhưng chỉ trên các phần của mã mà loại bỏ chúng rất nhiều rất nhiều lần.
deadalnix

7
Một điều tôi muốn nói thêm là trình biên dịch đã đi một chặng đường dài và sẽ tối ưu hóa rất nhiều thứ cho bạn. AFAIK, họ làm tối ưu hóa mã sạch, dễ đọc hơn những thứ khó hiểu.
Becuzz

3
+1 để cung cấp một ví dụ thực tế về tối ưu hóa vi mô gây lãng phí thời gian - và tiết lộ rằng Michael Jackson là một lập trình viên.
Boz

1
+1 Ví dụ. Nó hoàn toàn minh họa tại sao bạn nên để các biến đổi tầm thường cho trình biên dịch.
back2dos

1
@Rex Kerr> trong ví dụ điển hình, chi phí đến từ việc phân nhánh, gây ra tình trạng đường ống của CPU. Phép nhân điểm nổi cũng đắt. Những gì cao cấp hơn phụ thuộc rất nhiều vào FPU và chiều dài đường ống của CPU chạy mã. Tôi sẽ không ngạc nhiên khi mã này chạy nhanh hơn trên CPU cũ có đường ống ngắn hơn và FPU kém hiệu quả hơn CPU hiện tại.
deadalnix

84
  1. Viết mã, đó là sạch sẽ, súc tích, đơn giản và tự giải thích.
  2. Thực hiện các bài kiểm tra hiệu suất để xác định tắc nghẽn.
  3. Tối ưu hóa các phần quan trọng.

Theo nguyên tắc thông thường: 95% mã của bạn được chạy 5% thời gian. Không có điểm nào trong việc tối ưu hóa trước khi bạn lập hồ sơ / điểm chuẩn mã của bạn và xem 5% nào đang chạy 95% thời gian.

Mọi kẻ ngốc đều có thể thực hiện tối ưu hóa vi mô và bất kỳ trình biên dịch / thời gian chạy tốt nào cũng sẽ làm điều này cho bạn.
Tối ưu hóa mã tốt là chuyện nhỏ. Viết mã được tối ưu hóa và cố gắng làm cho nó tốt sau đó là tẻ nhạt ở mức tốt nhất và không bền vững ở mức tồi tệ nhất.

Nếu bạn nghiêm túc quan tâm đến hiệu suất, thì đừng sử dụng PHP cho mã quan trọng về hiệu năng. Tìm các nút cổ chai và viết lại chúng với phần mở rộng C. Ngay cả việc tối ưu hóa vi mô mã PHP của bạn vượt quá giới hạn mã hóa cũng sẽ không giúp bạn có được tốc độ nhanh như vậy.

Cá nhân, tôi thích thực hiện tối ưu hóa vi mô rất nhiều khi tôi bắt đầu lập trình. Bởi vì nó là hiển nhiên. Bởi vì nó thưởng cho bạn một cách nhanh chóng. Bởi vì bạn không phải đưa ra quyết định quan trọng. Đó là phương tiện hoàn hảo của sự trì hoãn. Nó cho phép bạn chạy trốn khỏi các phần thực sự quan trọng của phát triển phần mềm: Thiết kế các hệ thống mạnh mẽ, linh hoạt, có thể mở rộng, mạnh mẽ.


2
Câu trả lời hay nhất cho tôi đã được tìm thấy, đáng chú ý, trong Hướng dẫn dành cho nhà phát triển Bugzilla: "Nếu bạn đang cố gắng thông minh thay vì cố gắng đọc được, thì có lẽ bạn đang cố gắng làm mọi thứ" nhanh hơn? " : không giải quyết vấn đề trước khi bạn biết nó tồn tại. Nếu bạn không biết (bằng các thử nghiệm chi tiết, thực tế) rằng mã của bạn chậm, đừng lo lắng về việc làm cho nó "nhanh hơn". Điều này không chỉ giới hạn ở tối ưu hóa - nhiều lập trình viên liên tục giải quyết các vấn đề mà chưa ai từng gặp phải. Đừng làm vậy. " bugzilla.org/docs/developer.html#general
Marco

7
Tôi thường đồng ý - ngoại trừ một dòng, tôi cho rằng "mọi kẻ ngốc đều nghĩ rằng họ có thể tối ưu hóa vi mô" ...;)
Nim

@Nim: Điểm lấy;)
back2dos

26

Tôi đồng ý với cha của bạn: "Nếu một lập trình viên không xem xét hiệu suất trong mã của họ ngay cả ở cấp vi mô, họ không phải là lập trình viên giỏi." Chìa khóa là "xem xét hiệu suất". Điều đó không tương đương với "thực hiện tối ưu hóa vi mô ở mọi bước".

Tôi đồng ý với hầu hết các ý kiến ​​khác - những gì được sử dụng để làm cho các chương trình C nhanh hơn có thể không làm như vậy ngày hôm nay - nhưng có những điều nghiêm trọng khác cần xem xét: Tôi nên sử dụng C hoặc C ++? Các lớp với các toán tử quá tải đơn giản có thể giết chết hiệu năng nếu bạn sử dụng chúng nhiều. Có vấn đề gì không? Nó phụ thuộc vào ứng dụng của bạn, nhưng nếu bạn thậm chí không KIẾM nó, bạn không phải là một lập trình viên giỏi. Một số người có thể xem xét nó trong khoảng 2 mili giây và loại bỏ nó, nhưng tôi nghĩ rằng có quá nhiều nghĩa đen thậm chí không xem xét nó.

Thực tế là với tối ưu hóa, mã có thể khó đọc hơn. Mã sẽ mất nhiều thời gian hơn để viết. Mã sẽ ở đâu đó giữa nhanh hơn một chút và thứ tự cường độ nhanh hơn (điều đó hiếm). Khách hàng của bạn có thể sẽ không biết sự khác biệt.

Một thực tế khác là mọi người thích sử dụng lại mã, và nơi nó kết thúc có thể hoàn toàn khác so với khi bạn viết nó. Đột nhiên mọi người có thể quan tâm.

Ví dụ, giả sử bạn đã viết một cái gì đó như Angry Birds trên PC hoặc cho bảng điều khiển trò chơi. Bạn đã bỏ qua việc tối ưu hóa trong hệ thống vật lý và hệ thống đồ họa của mình - bởi vì lõi kép 2,5 GHz về cơ bản là tối thiểu trong những ngày này và trò chơi của bạn hoạt động đủ tốt. Sau đó, điện thoại thông minh đi cùng và bạn muốn cổng nó. Ôi chết tiệt, lõi ARM 600 MHz ?

Hãy nghĩ về một trang web - thứ gì đó được ném vào nhau vào cuối tuần như Hot or Not . Bạn sử dụng bất cứ cơ sở dữ liệu nào đều có ích, hãy viết mọi thứ với sự phát triển nhanh chóng, khởi chạy bằng cách gửi email cho bạn bè của bạn một URL. Ba tháng sau, máy chủ của bạn sắp chết vì quá tải và bạn không thể làm gì để mở rộng quy mô. Lúc nào chả vậy. Các trang web lớn nhất có hóa đơn điện được đo bằng hàng trăm kilowatt hoặc thậm chí megawatt. Hãy nghĩ về điều đó, có những megawatt được lưu thông qua tối ưu hóa mã.

Giống như cha bạn nói, ít nhất bạn phải xem xét nó. Hầu hết mọi người thậm chí không biết hiệu suất trên bàn là bao nhiêu và phủ bóng lên nó bằng một câu châm biếm nhanh về "tối ưu hóa sớm" và "không làm điều đó". Đây không phải là những lập trình viên giỏi.

Đây không phải là một ý kiến ​​phổ biến trên các trang web này. Tạm biệt điểm danh tiếng ....


3
Chắc chắn, bạn nên xem xét nó (ở phía sau đầu của bạn) và thường từ chối nó, trừ khi nó được coi là có giá trị. Bạn cần xem xét rằng tối ưu hóa thường thấp hơn khả năng đọc mã và có thể tăng thời gian thực hiện mã và duy trì theo hệ số 10 hoặc hơn. Nếu chương trình không cần nhiều CPU, nó thường không cần thiết. Hãy nhận ra rằng trình biên dịch của bạn thường tối ưu hóa tốt hơn nhiều so với bạn và rằng nhiều tối ưu hóa của bạn sẽ thực sự ảnh hưởng đến hiệu suất. Nếu nó không xứng đáng với thời gian của bạn để kiểm tra tối ưu hóa và hồ sơ của bạn, thì nó không đáng để bạn dành thời gian để tối ưu hóa.
dr jimbob

3
Ví dụ Angry Birds của bạn cho thấy chính xác lý do tại sao bạn không nên tối ưu hóa sớm. Khi chuyển từ máy tính để bàn sang bàn điều khiển sang (các) thiết bị di động, bạn đang xử lý (ít nhất) ba loại phần cứng và tối ưu hóa rất khác nhau cho một loại có thể gây tổn hại thay vì trợ giúp cho loại khác. Tệ hơn, tối ưu hóa sẽ làm cho mã khó hiểu hơn, do đó khó chuyển hơn. Chắc chắn, chọn các thuật toán hiệu quả ngay từ đầu, nhưng lưu tối ưu hóa vi mô cho giai đoạn điều chỉnh hiệu suất khi dữ liệu thực sẽ cho bạn biết sự cố ở đâu trên mỗi nền tảng.
Caleb

@Caleb: Ví dụ Angry Birds minh họa tại sao không tối ưu hóa cho phần cứng cụ thể. Nó cũng minh họa cách bạn có thể xây dựng toàn bộ ứng dụng mà không cần thực hiện tối ưu hóa "mức C" chung chung và sau đó bị đốt cháy. Trên thực tế không bị đốt cháy, nhưng gặp khó khăn vượt quá ý định ban đầu của bạn.
phkahler

25

Trước tiên hãy lấy trường hợp của bạn: PHP

  • Tôi không nghĩ PHP là một loại ngôn ngữ (cả vì bản chất và miền ứng dụng chính của nó) mà bạn cần phải lo lắng về những "tối ưu hóa vi mô" này. Mã PHP hầu hết được tối ưu hóa với bộ nhớ đệm opcode.
  • Các chương trình được viết bằng PHP không bị ràng buộc bởi CPU, chúng chủ yếu là ràng buộc I / O , vì vậy những tối ưu hóa này sẽ không đáng để bạn dành thời gian.
  • Bất cứ điều gì bạn PHẢI tối ưu hóa có lẽ nên được đưa vào một phần mở rộng C và sau đó được tải động trong thời gian chạy PHP
  • Vì vậy, như bạn có thể thấy, chúng tôi không nhận được sự khuyến khích nào bằng cách tối ưu hóa mã của chúng tôi trong PHP - mặt khác, nếu bạn dành thời gian đó để làm cho mã PHP dễ đọc và dễ bảo trì hơn - điều đó sẽ trả cho bạn nhiều cổ tức hơn.

Nói chung,

Tôi sẽ không dành nhiều thời gian để tối ưu hóa mã của mình bằng ngôn ngữ động như Python hay Ruby - bởi vì, chúng KHÔNG được thiết kế cho các tác vụ xử lý số lượng lớn của CPU. Họ giải quyết các loại vấn đề khác nhau trong đó mô hình hóa một tình huống trong thế giới thực theo cách thức phức tạp (dễ đọc và duy trì) - được gọi là biểu cảm - quan trọng hơn tốc độ. Nếu tốc độ là mối quan tâm hàng đầu, họ sẽ không năng động ngay từ đầu.

Đối với các chương trình được biên dịch (C ++, Java), tối ưu hóa là quan trọng hơn. Nhưng ở đó cũng vậy, trước tiên bạn phải xem xét tính chất / tên miền / mục đích của chương trình bạn đang viết. Bạn cũng nên cân nhắc cẩn thận thời gian để tối ưu hóa vi mô so với lợi ích từ việc tối ưu hóa đó. Nếu bạn cần tối ưu hóa nhiều hơn nữa, thì bạn cũng có thể xem xét đi xuống một bước - và mã hóa các đoạn mã đó trong trình biên dịch chương trình.

Vì vậy, để trả lời câu hỏi ban đầu của bạn - "Tối ưu hóa vi mô có quan trọng khi mã hóa không?" -- Câu trả lơi con phụ thuộc vao nhiêu thư --

  • Bạn đang làm gì: miền ứng dụng, độ phức tạp?
  • Những cải tiến tốc độ microsecond có thực sự quan trọng đối với chương trình của bạn không?
  • Loại tối ưu hóa nào sẽ đạt được nhiều nhất? Nó có thể không phải luôn luôn được tối ưu hóa mã, nhưng một cái gì đó bên ngoài.
  • Bao nhiêu "lòng tốt" (về tốc độ) bạn đang gặt hái được trong thời gian bạn đầu tư tối ưu hóa vi mô?
  • Có thể đạt được tốc độ tốt hơn theo những cách khác - bằng cách thay đổi phần cứng, RAM & bộ xử lý, thực thi mã song song hoặc trên hệ thống phân tán?

Không chỉ tốn thời gian tối ưu hóa vi mô (tối ưu hóa mã cho vấn đề đó), nó còn "bóp méo" khả năng đọc tự nhiên của mã của bạn, do đó làm cho nó trở nên nặng về bảo trì. Luôn coi đó là giải pháp cuối cùng - luôn cố gắng tối ưu hóa toàn bộ ứng dụng bằng cách áp dụng phần cứng tốt hơn và kiến ​​trúc tốt hơn là tối ưu hóa các tệp mã riêng lẻ.


18

Dường như có nhiều câu trả lời rằng tối ưu hóa vi mô là

tất cả về sự đánh đổi - hiệu suất, thời gian, chi phí, nỗ lực, khả năng đọc / bảo trì, v.v.

Nhưng tôi cũng biết rằng có một số tối ưu hóa mà không có tác động dễ đọc và tôi chỉ muốn làm những điều đó cho vui. Tôi đã thấy trên một số bài tập ở trường của tôi (tất cả đều dựa trên tốc độ), rằng thật tuyệt khi xem xét tối ưu hóa vi mô khi viết các câu điều kiện như:

if (counter < X && shouldDoThis()) // shouldDoThis() is an expensive function

luôn luôn đẹp hơn

if (shouldDoThis() && counter < X ) 

Có khá nhiều cách để "tăng tốc" mã của bạn như thế và sự khác biệt thường không đáng kể (không phải lúc nào cũng vậy), nhưng tôi cảm thấy tốt hơn nếu tôi viết nó như thế.

Tôi không biết liệu có ai còn coi đây là một sự tối ưu hóa thực sự không, nhưng tôi nghĩ một lập trình viên nên biết và xem xét những điều này khi viết mã của họ.


2
Nó có thể không quan trọng đối với trường hợp cụ thể này. Tuy nhiên tôi nghĩ rằng điều rất quan trọng là có thể nhận ra các tối ưu hóa như thế này để khi vấn đề, bạn không phải mất thời gian không cần thiết để cấu hình và tối ưu hóa sau thực tế.
tskuzzy

4
Đây là một ví dụ rất nguy hiểm . Một tối ưu hóa nên không bao giờ thay đổi hành vi . Thậm chí gợi ý rằng đó cheap() && expensive()là một sự tối ưu hóa của việc expensive () && cheap()mời mọi người thay thế một cách mù quáng bằng cái khác mà không quan tâm đến sự thay đổi ngữ nghĩa quan trọng mà nó tạo ra (trong các ngôn ngữ &&là toán tử ngắn mạch).
Đánh dấu gian hàng

5
Nếu các chức năng không có tác dụng phụ, chúng tương đương và một là nhanh hơn. Nếu chúng có tác dụng phụ, người ta không nên viết mã như thế này ngay từ đầu. Tôi thậm chí sẽ nói đây là một việc nên được thực hiện theo thói quen - trừ khi nó thực sự thay đổi hành vi.
phkahler

3
@MarkBooth Tôi phải đồng ý với phkahler ở đây, không có chức năng nào trong số này có tác dụng phụ! Thứ tự của condionos trong một tuyên bố if phải không có ảnh hưởng đến kết quả của chương trình. Ví dụ của tôi sẽ được viết tốt hơn if (x<100 && isPrime(x)), chỉ để làm cho nó rõ ràng hơn.
zidarsk8

1
@ zidarsk8 - Nếu tối ưu hóa thay đổi bất cứ điều gì ngoài tốc độ thực hiện thì đó không phải là tối ưu hóa . Là lập trình viên, chúng ta thường phải thực dụng và đôi khi điều đó có nghĩa là chúng ta không thể đảm bảo rằng tất cả các chức năng được sử dụng với toán tử ngắn mạch là thuần túy - đặc biệt là khi mã của chúng ta gọi các thư viện bên thứ ba mà chúng ta không kiểm soát được. Trong tình huống đó, bạn phải cẩn thận rằng các lập trình viên thiếu kinh nghiệm không được khuyến khích giới thiệu các lỗi trong tên tối ưu hóa .
Đánh dấu gian hàng

11

Đầu sự nghiệp của tôi, những tuyên bố về chăn như "không tối ưu hóa vi mô" đã dẫn đến nhiều nhầm lẫn. Tất cả mọi thứ là hoàn cảnh; do đó, lý do mọi người nói, "thực hành tốt nhất" chứ không phải "làm điều này".

"Thực hành tốt nhất" là lựa chọn hàng đầu xem xét tất cả các trường hợp. Ví dụ, LINQEntity Framework nên được sử dụng thay cho SQL nội tuyến. Tại công ty của tôi, chúng tôi đang trên SQL Server 2000 . SQL Server 2000 không hỗ trợ Entity Framework. Thực hành tốt nhất yêu cầu:

  • Bán cho ông chủ của tôi ý tưởng mua một phiên bản SQL Server mới có nghĩa là vài nghìn đô la.
  • Bán nhà phát triển trên ý tưởng học công nghệ mới.

Tôi biết từ kinh nghiệm điều này sẽ không xảy ra. Vì vậy, tôi có thể bỏ thuốc lá, căng thẳng đến tận cùng hoặc không tuân theo thực tiễn tốt nhất.

Có những cân nhắc chính trị, kỹ thuật và tiền tệ đằng sau các quyết định ảnh hưởng đến kết quả chung. Hãy nhớ thực tế này khi đưa ra quyết định và chọn trận chiến của bạn một cách khôn ngoan.

" Đối với tất cả mọi thứ có một mùa, một thời gian cho mọi hoạt động dưới trời. "


1
BTW, bạn có thể sử dụng Dapper như một thay thế micro-ORM cho SQL nội tuyến.
Dan

2
LINQ and Entity Framework should be used in lieu of inline SQL- Cho đến khi bạn thực sự cần SQL nội tuyến để tối ưu hóa một cái gì đó; SQL mà EF tạo ra không phải lúc nào cũng tối ưu.
Robert Harvey

1
fwiw, nếu ông chủ của bạn lo lắng về chi phí cấp phép của SQL 2k8 (hoặc bất cứ điều gì khác có thể là hiện tại), bạn nên chỉ ra rằng nó đủ cũ để sớm xuất hiện trên EOL RẤT (nếu chưa có)
warren

@warren - Một số công ty không xem xét những điều như vậy. Đối với một số người, nếu nó vẫn "hoạt động" thì họ sẽ không nâng cấp. Bởi công việc, ý tôi là máy chủ vẫn chạy. Chúng tôi đã thấy thiếu sự hỗ trợ với EF. Điều đó chỉ đơn giản là không đủ để thuyết phục họ chi tiêu bất kỳ khoản tiền nào.
P.Brian.Mackey

1
Để bạn biết, bạn có thể sử dụng EF với SQL 2000. Trình thiết kế không hoạt động, nhưng khung thực thể thực sự hỗ trợ SQL 2000. Để vượt qua giới hạn của trình thiết kế, bạn có thể tạo cơ sở dữ liệu cục bộ trong sql 2008 express với cùng một lược đồ là cơ sở dữ liệu sql 2000, trỏ người thiết kế vào đó để tạo tất cả các lớp, sau đó đi vào tệp .edmx và thay đổi phiên bản cơ sở dữ liệu đích thành 2000 và trỏ chuỗi kết nối vào cơ sở dữ liệu 2000 máy chủ sql của bạn. Không phải là giải pháp tốt nhất, nhưng nếu bạn không thể nâng cấp thì nó hoạt động.
Neil

8

Đây luôn là một sự đánh đổi.

Đầu tiên, ngành công nghiệp máy tính là về tiền cuối cùng. Những gì bạn cần làm với tư cách là một nhà phát triển là tạo ra giá trị cho khách hàng để bạn nhận được tiền (đó là sự đơn giản hóa nhưng điểm chính là ở đây).

Thời gian phát triển tốn tiền. Máy điện tốn tiền quá. Thông thường, chi phí thứ hai này thấp hơn so với chi phí đầu tiên. Vì vậy, đây là vốn để có mã có thể đọc và mã có thể bảo trì, vì vậy nhà phát triển có thể dành phần lớn thời gian để cung cấp giá trị.

Tối ưu hóa vi mô có thể, trong một số trường hợp, là quan trọng. Nhưng chúng thường liên quan đến mã ít đọc hơn hoặc mã có thể mở rộng ít hơn (đây không phải là trường hợp ví dụ được liên kết của bạn, nhưng nói chung, nó là). Điều này sẽ có giá tại một số thời điểm của nhà phát triển. Lần này đắt hơn điện máy, đây là một sự lãng phí.

Thứ hai, tối ưu hóa vi mô trong một dự án lớn có thể làm cho việc duy trì / phát triển ngày càng khó hơn. Vấn đề với điều đó là khi phát triển, một số tối ưu hóa khác có thể không thể thực hiện được. Với một ứng dụng đang phát triển, thông thường bạn sẽ kết thúc với một giải pháp chậm hơn những gì bạn sẽ có mà không thực hiện những tối ưu hóa đó.

Thứ ba, việc tối ưu hóa thường không phù hợp vì độ phức tạp của thuật toán thường sẽ khắc phục mọi tối ưu hóa vi mô mà bạn có thể thực hiện nếu tập dữ liệu phát triển. Đáng buồn thay, vì tối ưu hóa vi mô làm cho mã của bạn khó duy trì / phát triển hơn, việc tối ưu hóa có thể khó thực hiện hơn.

Đôi khi, giá trị nằm ở sự tối ưu hóa này (nghĩ về các chương trình quan trọng về độ trễ, như trong trò chơi điện tử hoặc máy bay tự động). Nhưng điều này phải được chứng minh. Thông thường chương trình của bạn dành phần lớn thời gian trong một phần mã giới hạn. Bất kể tối ưu hóa vi mô nào bạn làm, bạn sẽ không bao giờ nhận được các chương trình của mình nhanh hơn một cách có giá trị mà không xác định nút cổ chai và làm việc trên phần này.

Đặt câu hỏi của bạn như bạn đã làm cho thấy rằng bạn không đánh giá vấn đề trên một chương trình thực tế. Trong trường hợp này, bạn có thể thực hiện thủ thuật và chú ý xem nó có nhanh hơn hay không. Vì vậy, bạn đã hỏi rằng trước khi có bất kỳ vấn đề. Đây là vấn đề. Bạn đã xử lý vấn đề tối ưu hóa sai cách.

Vì bảo trì và tiến hóa thường có giá trị hơn tối ưu hóa vi mô, hãy chắc chắn có giao diện phù hợp trước khi thực hiện bất kỳ. Sau đó, nếu các phần của chương trình của bạn đủ trừu tượng cho nhau, bạn có thể tối ưu hóa vi mô mà không làm hỏng toàn bộ. Điều này đòi hỏi giao diện của bạn phải chạy đủ lâu để được tin cậy.


"Luôn có sự đánh đổi". Đúng, giảm một biến sẽ tăng biến khác, nếu chương trình nằm trên đường cong đánh đổi . Theo kinh nghiệm của tôi, hầu hết các chương trình không ở gần đường cong trao đổi và có nhiều chỗ cho cả hai biến được giảm.
Mike Dunlavey

Bảo trì và tiến hóa +1 có giá trị hơn là tối ưu hóa vi mô. Mặc dù tôi chắc chắn rằng ngành công nghiệp máy tính không chỉ là về tiền? Ví dụ, nguồn mở, giáo dục, đổi mới, quản trị, cộng đồng, v.v ... Tôi chắc chắn tiền có thể được tìm thấy ở gốc của nó, nhưng điều đó đúng với hầu hết mọi thứ.
Boz

@Boz kay> Điều này đúng một phần. Đầu tiên bởi vì ông chủ và người quản lý của bạn hầu như không biết gì về những kẻ trộm cắp và quan tâm đến tiền bạc. Nếu bạn muốn quảng bá một số công cụ nguồn mở, bạn phải cho họ biết cách nó sẽ cải thiện thương hiệu của công ty hoặc làm thế nào để giảm chi phí phát triển. Thêm vào đó, làm cho các nhà phát triển hài lòng là một cách để có được nhà phát triển tốt trong công ty của bạn. Dev tốt kiếm tiền (chủ yếu là ném chất lượng và đổi mới). Cuối cùng, tiền là chìa khóa. Và tôi đang viết rằng từ máy tính linux của tôi là một người hỗ trợ phần mềm miễn phí tuyệt vời. Giáo dục cũng vậy.
deadalnix

8

Hiệu suất là một tính năng

Bài viết của Jeff Atwood là một bài viết tuyệt vời về việc xây dựng một trang web hiệu suất cao và tầm quan trọng của việc làm như vậy ...

Điều đó nói rằng, đừng tập trung vào tối ưu hóa vi mô cho đến khi bạn cần. Có nhiều tối ưu hóa lợi ích chi phí bạn có thể thực hiện. Tập trung vào kiến ​​trúc, không phải mã. Hầu hết các trang web tôi thấy đã hoạt động chậm đều có vấn đề ở mức độ cao (lớp dịch vụ web không cần thiết, thiết kế cơ sở dữ liệu kém, kiến ​​trúc quá phức tạp) không chỉ ảnh hưởng xấu đến hiệu suất mà còn ăn sâu và khó khắc phục.

Khi bạn đang xây dựng một trang web, mã phía máy khách và logic cơ sở dữ liệu có nhiều khả năng gây ra sự cố về hiệu suất hơn so với mã phía máy chủ của bạn. Giống như bất cứ điều gì, nếu bạn có vấn đề về hiệu suất, bạn sẽ biết, thậm chí hồ sơ mã của bạn tốt hơn và bạn có thể tìm thấy chúng sớm.


7

Thời gian phát triển chi phí nhiều hơn thời gian máy tính. Đó thường là những gì bạn muốn tối ưu hóa. Nhưng:

  • Có một sự khác biệt giữa tối ưu hóa vi mô và độ phức tạp thuật toán. Dành đủ thời gian để tự tin rằng bạn đang sử dụng đúng thuật toán .
  • Hãy chắc chắn rằng bạn đang hỏi đúng câu hỏi, select (select count(*) from foo) >= 1không giống như select exists(select 1 from foo).
  • Một số thành ngữ ngôn ngữ phổ biến đơn giản là vì chúng nhanh hơn, nên sử dụng những ngôn ngữ đó, vì hầu hết những người sử dụng thành thạo ngôn ngữ này sẽ quen thuộc với chúng. (ví dụ của bạn là một ví dụ tốt).

7

Bạn muốn tối ưu hóa cái gì?

  • Hiệu suất phần mềm?
  • Độ tin cậy?
  • Năng suất lập trình viên?
  • Sự hài lòng của khách hàng?
  • Hiệu quả năng lượng?
  • Bảo trì?
  • Đến giờ đi chợ?
  • Giá cả?

"Tối ưu hóa" không phải lúc nào cũng có nghĩa là làm cho mã chạy nhanh nhất có thể. Đôi khi việc tìm ra cách nhanh nhất tuyệt đối để làm một việc gì đó rất quan trọng, nhưng đó thực sự không phải là tất cả những gì phổ biến trong hầu hết các mã. Nếu người dùng không thể nhận thấy sự khác biệt giữa 50 và 100 micro giây, thì thực tế không có sự khác biệt giữa hai mã này sẽ chỉ chạy đôi khi. Đây là một ví dụ:

Nếu bạn cần cập nhật liên tục màn hình hiển thị độ dài của đầu vào của người dùng và lượng thời gian cần có của một trong hai thói quen để xác định độ dài đó nhỏ hơn nhiều so với thời gian giữa hai lần nhấn phím liên tiếp, thì thực sự không có vấn đề gì với thói quen bạn sử dụng. Mặt khác, nếu bạn cần xác định độ dài của một tỷ chuỗi, có lẽ bạn sẽ muốn chú ý đến sự khác biệt về hiệu suất giữa các thói quen khác nhau. Trong trường hợp đầu tiên, bạn có thể thích viết mã dễ hiểu và xác minh; trong trường hợp thứ hai, bạn có thể sẵn sàng đánh đổi tốc độ dễ đọc.

Trong mọi trường hợp, nếu bạn sẽ tối ưu hóa mã của mình, bạn nên lập hồ sơ mã của mình trước và sau bất kỳ thay đổi nào bạn thực hiện. Các chương trình ngày nay đủ phức tạp đến nỗi thường khó có thể biết được nút thắt ở đâu; profiling giúp bạn tối ưu hóa đúng mã và sau đó cho thấy rằng các tối ưu hóa bạn thực hiện đã thực sự hiệu quả.

Bạn đã không nói khi cha bạn nghỉ hưu hoặc ông đã làm chương trình gì, nhưng phản ứng của ông không đáng ngạc nhiên. Trong lịch sử, bộ nhớ, lưu trữ thứ cấp và thời gian tính toán đều đắt đỏ, và đôi khi rất tốn kém. Ngày nay, tất cả những thứ đó đã trở nên rất rẻ so với thời gian lập trình viên. Đồng thời, bộ xử lý và trình biên dịch đã có thể tối ưu hóa mã theo cách mà các lập trình viên không bao giờ có thể sánh được. Những ngày mà các lập trình viên sử dụng các thủ thuật nhỏ để ăn mày một vài hướng dẫn máy móc ở đây và hầu hết đã biến mất.


1
+1 Chưa kể rằng trong vài năm qua, các thiết bị di động lại trở nên phụ thuộc nhiều vào tối ưu hóa mã. Một số người không viết mã được tối ưu hóa hoặc ít nhất xem xét nó có thể gặp khó khăn khi ứng dụng chuyên sâu CPU của họ chạy trơn tru trên thiết bị di động.
Styler

+1 rất giống danh sách tối ưu hóa có thể của bạn. Ông đã sử dụng lắp ráp / fortran
Boz

@Styler: sẽ không lâu nữa cho đến khi các thiết bị di động có CPU lõi tứ với GB bộ nhớ, chúng ta đã có điện thoại thông minh lõi kép.
Lie Ryan

@Lie Ryan: yes điều này là đúng, nhưng cũng giống như hầu hết những người tiên phong họ phải đi trên những chiếc thuyền gỗ;)
Styler

7

Nó không quan trọng để tối ưu hóa vi mô trong khi viết mã. Tối ưu hóa nên được thực hiện với sự trợ giúp của một hồ sơ, tối ưu hóa mã nơi nó quan trọng.

TUY NHIÊN , một lập trình viên nên cố gắng tránh làm những việc rõ ràng ngu ngốc trong khi viết mã.

Ví dụ, không thực hiện các hoạt động đắt tiền lặp đi lặp lại trong một vòng lặp. Lưu trữ giá trị trong một biến bên ngoài vòng lặp và sử dụng giá trị đó. Đừng làm những việc như so sánh chuỗi hoặc regex lặp đi lặp lại trong một hàm thường được gọi là, khi bạn có thể tăng cấp, thực hiện so sánh và biến nó thành một số nguyên hoặc tham chiếu hàm hoặc lớp dẫn xuất.

Những điều này dễ dàng cho một lập trình viên có kinh nghiệm ghi nhớ và hầu như luôn cải thiện chất lượng mã.


Nhận ra tôi cần phải rõ ràng hơn trong chỉnh sửa câu hỏi của mình, tôi đã nói điều tương tự thực sự - tôi đã cập nhật nó.
Boz

7

Khi quyết định tối ưu hóa cái gì, hãy luôn nhớ luật của Amdahl . Xem liên kết cho toán chính xác; câu lệnh đáng nhớ cần nhớ là:

Nếu một phần trong chương trình của bạn chiếm 10% thời gian chạy và bạn tối ưu hóa phần đó để chạy nhanh gấp đôi, thì toàn bộ chương trình sẽ chỉ tăng tốc 5%.

Đây là lý do tại sao mọi người luôn nói rằng không đáng để tối ưu hóa các phần trong chương trình của bạn mà không chiếm hơn một vài phần trăm tổng thời gian chạy. Nhưng đó chỉ là một trường hợp đặc biệt của một nguyên tắc chung hơn. Luật của Amdahl cho bạn biết rằng nếu bạn cần làm cho toàn bộ chương trình chạy nhanh gấp đôi, bạn cần tăng tốc trung bình mỗi phần lên trung bình 50%. Nó cho bạn biết rằng nếu bạn cần xử lý hai mươi gigabyte dữ liệu, chỉ có hai cách để làm cho việc đó nhanh hơn thời gian để đọc hai mươi gigabyte khỏi đĩa: lấy đĩa nhanh hơn hoặc làm cho dữ liệu nhỏ hơn.

Vậy luật của Amdahl nói gì về tối ưu hóa vi mô? Nó nói rằng họ có thể có giá trị nếu họ áp dụng trên bảng. Nếu bạn có thể tắt một phần trăm thời gian chạy của mọi chức năng trong chương trình của mình, xin chúc mừng! Bạn đã tăng tốc chương trình lên một phần trăm. Điều đó có đáng để làm không? Chà, với tư cách là một người biên dịch, tôi sẽ rất vui mừng khi tìm thấy một sự tối ưu hóa đã làm điều đó, nhưng nếu bạn đang làm nó bằng tay, tôi sẽ nói hãy tìm kiếm thứ gì đó lớn hơn.


1
+1 cho trích dẫn của Amdahl, nhưng tôi không đồng ý với "để làm cho toàn bộ chương trình chạy nhanh gấp đôi, bạn cần tăng tốc mọi phần". Tôi muốn nói rằng bạn không thực sự tăng tốc bất kỳ "mảnh" nào. Thay vào đó, bạn tìm thấy công việc không cần thiết, và loại bỏ nó. Đặc biệt là các cuộc gọi chức năng, nếu chương trình là bất cứ điều gì lớn hơn một món đồ chơi. Phần lớn suy nghĩ phổ biến về hiệu suất dường như hoàn toàn bỏ qua tầm quan trọng của việc tìm toàn bộ các nhánh không cần thiết của cây cuộc gọi (có thể là các hướng dẫn đơn lẻ) và loại bỏ chúng.
Mike Dunlavey

Ma quỷ trong từ "trung bình" ở đó. Về mặt toán học, trường hợp để tăng tốc chương trình lên 50% thì mỗi phần phải được tăng tốc trung bình 50% . Bây giờ, nếu bạn có thể chia chương trình thành một công việc chiếm 75% thời gian chạy và một công việc khác chiếm 25% và tăng tốc độ lên gấp 3 lần, điều đó sẽ mang lại cho bạn 50% tổng thể mặc dù chưa làm gì cho công việc sau. Nhưng trường hợp phổ biến hơn nhiều là có hàng tá "công việc" mà mỗi công việc chiếm ít hơn 5% thời gian chạy - và sau đó bạn phải tăng tốc hoặc loại bỏ nhiều trong số chúng.
zwol

Tôi nghĩ có một trường hợp thậm chí còn phổ biến hơn. Có một "công việc" chiếm 50% thời gian, nhưng bạn thực sự không cần nó , vì vậy bạn loại bỏ nó hoàn toàn, giảm thời gian tổng thể bằng số tiền đó, sau đó lặp lại. Tôi biết điều này là khó chấp nhận - rằng các chương trình có thể dành phần lớn thời gian để làm những việc mà (trong nhận thức muộn) là hoàn toàn không cần thiết. Nhưng đây là ví dụ kinh điển của tôi .
Mike Dunlavey

6

Nó phụ thuộc vào giai đoạn phát triển của bạn, khi ban đầu bắt đầu viết một cái gì đó, tối ưu hóa vi mô không nên được xem xét vì bạn sẽ đạt được hiệu suất cao hơn bằng cách sử dụng các thuật toán tốt hơn so với sử dụng tối ưu hóa vi mô. Ngoài ra, hãy xem xét những gì bạn đang phát triển khi các ứng dụng nhạy cảm với thời gian sẽ thấy nhiều lợi ích hơn từ các cân nhắc tối ưu hóa vi mô so với các ứng dụng kinh doanh chung.

Nếu bạn đang kiểm tra và mở rộng phần mềm thì tối ưu hóa vi mô có thể sẽ làm tổn thương bạn, họ có xu hướng làm cho mã khó đọc hơn và thậm chí giới thiệu bộ lỗi độc nhất của riêng họ cần được sửa cùng với bất kỳ thứ gì khác cần sửa.

Nếu bạn thực sự nhận được khiếu nại từ người dùng về mã chậm thì họ có thể đáng xem xét nhưng chỉ khi mọi thứ khác đã được giải quyết, cụ thể là:

  • Là mã được viết tốt?
  • Là ứng dụng có thể truy cập dữ liệu của mình mà không có bất kỳ vấn đề?
  • Một thuật toán tốt hơn có thể được sử dụng?

Nếu tất cả các câu hỏi đã được trả lời và bạn vẫn gặp vấn đề về hiệu năng, thì có lẽ đã đến lúc bắt đầu sử dụng tối ưu hóa vi mô trong mã nhưng tỷ lệ cược là các thay đổi khác (ví dụ mã tốt hơn, thuật toán tốt hơn, v.v.) sẽ khiến bạn gặp khó khăn nhiều hơn một hiệu suất đạt được hơn là tối ưu hóa vi mô.


5

Tốc độ thực hiện là một trong nhiều yếu tố góp phần vào chất lượng của một chương trình. Thông thường, tốc độ có mối tương quan nghịch với khả năng đọc / bảo trì. Trong hầu hết các trường hợp, mã phải có thể đọc được để con người có thể duy trì mã. Thời gian duy nhất mà khả năng đọc có thể bị xâm phạm là khi tốc độ là một yêu cầu thiết yếu. Yêu cầu làm cho mã nhanh hơn khả năng đọc / bảo trì đầy đủ cho phép hầu như không bao giờ được áp dụng, nhưng có một số trường hợp nhất định. Điều chính cần nhớ là mã được tối ưu hóa vi mô thường là mã hack, vì vậy trừ khi có một yêu cầu được xác định ở đâu đó, thì hầu như luôn luôn là cách sai để giải quyết vấn đề. Ví dụ, người dùng sẽ hầu như không bao giờ nhận thấy sự khác biệt giữa thời gian thực hiện 0,5 giây và 1 giây trong các hoạt động CRUD, vì vậy bạn không cần phải tham gia vào một hội nghị-interop-hackfest để đạt được 0,55 giây đó. Vâng, tôi có thể lái một chiếc trực thăng để làm việc và nó sẽ nhanh gấp 10 lần, nhưng tôi không vì giá cả và thực tế là máy bay trực thăng khó bay hơn nhiều.Khi bạn tối ưu hóa mã không cần thiết, đây chính xác là những gì bạn đang làm: thêm độ phức tạp không cần thiết và chi phí để đạt được mục tiêu không cần thiết.


5

Tối ưu hóa vi mô rất quan trọng khi bạn đạt được một ràng buộc. Thứ bạn quan tâm có thể là bộ nhớ, có thể là thông lượng, có thể là độ trễ hoặc có thể là mức tiêu thụ điện. Lưu ý rằng đây là những đặc điểm cấp hệ thống; bạn không cần (và không thể) tối ưu hóa mọi chức năng theo mọi cách.

Các hệ thống nhúng có nhiều khả năng cần tối ưu hóa vi mô vì các ràng buộc dễ bị tấn công hơn. Tuy nhiên, thậm chí có tối ưu hóa vi mô chỉ đưa bạn đến nay; bạn không thể tối ưu hóa theo cách của bạn ra khỏi một thiết kế xấu. Điểm quan trọng về thiết kế tốt trong một hệ thống là bạn có thể suy luận về toàn bộ hệ thống. Các thành phần cần tối ưu hóa vi mô phải được phơi bày gọn gàng và tối ưu hóa theo cách không làm ảnh hưởng đến thiết kế của hệ thống.

Lưu ý rằng các hệ thống "nhúng" nhỏ ngày nay có thể khá gần với Vaxen hoặc PDP-11 của năm qua, vì vậy những vấn đề này được sử dụng phổ biến hơn. Trên một hệ thống mục đích chung hiện đại làm máy tính thương mại nói chung hiện đại, tối ưu hóa vi mô là rất hiếm. Đây có lẽ là một phần lý do tại sao cha bạn đảm nhận vị trí ông làm.

Tuy nhiên, không quan trọng bạn đang xử lý nano giây, mili giây, giây hay giờ; các vấn đề là như nhau. Chúng phải được đánh giá trong bối cảnh của hệ thống và những gì bạn đang cố gắng đạt được.

Đây là một ví dụ từ một câu hỏi gần đây tôi đã trả lời trên Stack Overflow cho một trường hợp cần tối ưu hóa vi mô: Bộ mã hóa video nguồn mở cho một hệ thống nhúng .


4

Vấn đề lớn nhất với tối ưu hóa vi mô là nó khiến bạn phải viết mã khó hơn để duy trì.

Một vấn đề khác là tùy thuộc vào cấu hình máy tính, đôi khi tối ưu hóa vi mô của bạn có thể có hiệu suất kém nhất so với không có 'tối ưu hóa'.

Thực hiện nhiều tối ưu hóa vi mô sẽ tiêu tốn của bạn rất nhiều thời gian để chống lại thứ gì đó không thực sự quan trọng.

Một cách tiếp cận tốt hơn là tạo mã sạch hơn, dễ bảo trì hơn và nếu bạn gặp vấn đề về hiệu năng, bạn chạy một hồ sơ để tìm ra điều gì thực sự làm cho mã của bạn chậm. Và biết chính xác những gì thực sự xấu, bạn có thể sửa chữa nó.

Tôi không nói rằng việc không tối ưu hóa vi mô là lý do để viết mã ngu ngốc.


4

Nếu bạn bắt đầu lo lắng về mili giây, bạn nên xem xét từ bỏ PHP và sử dụng C hoặc hội thay thế. Không phải là tôi muốn làm điều này, thật vô nghĩa khi thảo luận về những con số như vậy và sử dụng một ngôn ngữ kịch bản. Mã của bạn có lặp lại với lệnh này thường xuyên không?

Các yếu tố môi trường không còn tồn tại ở đây, dù sao thì các máy chủ đó vẫn hoạt động 24/7 và nếu chúng thực sự xử lý một cái gì đó sẽ chỉ quan trọng nếu đó thực sự là một nhiệm vụ chạy trong một thời gian rất dài.

Rất có thể là ánh sáng trong văn phòng của bạn và năng lượng mà máy tính của chúng tôi sử dụng trong khi tất cả chúng ta đang gõ câu hỏi và câu trả lời, sử dụng nhiều năng lượng hơn bất kỳ loại tối ưu hóa vi mô nào bạn có thể áp dụng một cách hợp lý cho các ứng dụng của mình sẽ tiết kiệm.


+1 tắt đèn hoặc không trả lời câu hỏi.
Boz

4

Bạn nên chọn thuật toán tốt nhất, đơn giản cho nhiệm vụ. Lý do nó cần phải đơn giản là để giữ cho mã có thể đọc được. Lý do nó cần phải là tốt nhất, là để tránh bắt đầu với các đặc điểm thời gian chạy xấu. Đừng mù quáng chọn BubbleSort khi bạn biết rằng bạn sẽ có bộ dữ liệu lớn. Nó là tốt, tuy nhiên, đối với loại 10 yếu tố thường xuyên.

THEN, nếu các số hồ sơ cho thấy rằng sự lựa chọn của bạn về thuật toán đơn giản, tốt nhất không đủ tốt, bạn có thể bắt đầu tối ưu hóa (thường là chi phí dễ đọc).


BubbleSort thực sự có thể tốt hơn quicksort hoặc mergesort khi dữ liệu của bạn gần như được sắp xếp chỉ với một vài yếu tố đi lạc không quá xa đích đến cuối cùng của chúng. Đối với tất cả các tác vụ khác, bạn nên sử dụng chức năng sắp xếp tích hợp sẵn mà ngôn ngữ lập trình của bạn cung cấp cho bạn; đó là cách đơn giản nhất để bắt đầu (và chức năng sắp xếp tích hợp trong hầu hết các ngôn ngữ có hiệu suất tốt). LỜI KHUYÊN BAD : start out with bad runtime characteristic, đừng cố tình bắt đầu với một đặc tính thời gian chạy xấu.
Lie Ryan

@Lie, nếu bạn BIẾT rằng dữ liệu của bạn sắp được sắp xếp và bạn CÓ THỂ sử dụng bubbleort, bạn không chính xác chọn thuật toán của mình một cách mù quáng ... Cũng cảm ơn vì đã chỉ ra lỗi chính tả.

4

Tôi đã nói điều đó trước đây và tôi sẽ nói ở đây: "Tối ưu hóa sớm là gốc rễ của mọi tội lỗi" . Đây phải là một trong những quy tắc ở trung tâm của bất kỳ lập trình viên nào.

Mã có thể, đến một điểm, luôn luôn nhanh hơn hiện tại. Trừ khi bạn đang lắp ráp bằng tay với một con chip cụ thể, luôn có thứ gì đó đạt được thông qua tối ưu hóa. Tuy nhiên, trừ khi bạn MUỐN lắp ráp bằng tay cho mọi thứ bạn làm, phải có một mục tiêu định lượng, một khi bạn gặp, bạn nói "thế là đủ" và ngừng tối ưu hóa, ngay cả khi vẫn còn một kẻ hút hiệu suất rõ ràng đang nhìn chằm chằm bạn vào mặt

Mã đẹp, thanh lịch, cực kỳ hiệu quả là vô ích nếu nó không hoạt động (và bằng "công việc", ý tôi là tạo ra sản lượng dự kiến ​​cho tất cả các đầu vào dự kiến). Do đó, sản xuất mã hoạt động LUÔN LUÔN là ưu tiên hàng đầu. Sau khi nó hoạt động, bạn đánh giá hiệu suất và nếu nó thiếu, bạn tìm cách để làm cho nó tốt hơn, đến mức nó đủ tốt.

Có một số điều bạn phải quyết định trước sẽ ảnh hưởng đến hiệu suất; các quyết định rất cơ bản như ngôn ngữ / thời gian chạy bạn sẽ sử dụng để thực hiện giải pháp này. Nhiều trong số này sẽ tác động đến hiệu suất bằng nhiều đơn đặt hàng lớn hơn nhiều so với việc gọi một phương thức này với phương pháp khác. Thành thật mà nói, PHP, với tư cách là một ngôn ngữ kịch bản, đã là một điểm nhấn về hiệu năng, nhưng vì rất ít trang web được viết kịch bản được xây dựng từ dưới lên trong C / C ++, nó có thể so sánh với các công nghệ khác mà bạn có thể chọn (Java Servlets, ASP.NET , Vân vân).

Sau đó, kích thước tin nhắn I / O là kẻ giết người hiệu suất lớn nhất tiếp theo của bạn. Tối ưu hóa những gì bạn đọc và ghi vào đĩa cứng, cổng nối tiếp, ống mạng, v.v. thường sẽ cải thiện thời gian chạy của chương trình theo nhiều bậc độ lớn ngay cả khi các thuật toán đằng sau các hoạt động I / O có hiệu quả. Sau đó, giảm độ phức tạp Big-O của thuật toán, và sau đó nếu bạn hoàn toàn phải, bạn có thể "tối ưu hóa vi mô" bằng cách chọn các cuộc gọi phương thức ít tốn kém hơn và đưa ra các quyết định bí truyền khác ở mức thấp.


2
+1 Sản xuất mã hoạt động LUÔN LUÔN là ưu tiên hàng đầu.
Boz

2
@Keith, thực sự Knuth đã nói điều đó trước tiên, và anh ấy đã nói khá nhiều hơn thế.

"Làm cho nó hoạt động, sau đó làm cho nó hoạt động nhanh như nó cần để làm việc", Anon.
John Saunders

1
Thật ra tôn giáo là gốc rễ của mọi tội lỗi, nhưng tôi lạc đề.
Thomas Eding

4

Bạn đề cập rằng cha của bạn là một lập trình viên đã nghỉ hưu. Các lập trình viên làm việc trong thế giới máy tính lớn phải rất quan tâm đến hiệu suất. Tôi có thể nhớ việc nghiên cứu một hoạt động của Hải quân Hoa Kỳ nơi máy tính lớn của họ bị giới hạn phần cứng với 64 KB bộ nhớ cho mỗi người dùng. Trong thế giới lập trình đó, bạn phải tìm ra từng chút nhỏ bạn có thể.

Bây giờ mọi thứ đã khác rất nhiều và hầu hết các lập trình viên không cần phải lo lắng quá nhiều về tối ưu hóa vi mô. Tuy nhiên, các lập trình viên hệ thống nhúng vẫn làm và cơ sở dữ liệu mọi người vẫn rất cần sử dụng mã được tối ưu hóa.


3

Mã nên được viết để hoàn toàn rõ ràng về những gì nó làm. Sau đó, nếu và chỉ khi nó quá chậm, hãy quay lại và tăng tốc nó. Mã luôn có thể được thay đổi để nhanh hơn sau này, nếu có thể hiểu được - nhưng may mắn thay đổi nó sẽ rõ ràng nếu nó nhanh.


3

Điều quan trọng là:

1) Cuộc sống của ai đó phụ thuộc vào mã của bạn. Một chức năng mất 25ms để thực hiện trong máy đo nhịp tim của ai đó có lẽ là một ý tưởng tồi.

Cá nhân tôi thực hiện một cách tiếp cận hai hướng - có những tối ưu hóa vi mô mà bạn có thể làm mà không ảnh hưởng đến khả năng đọc - rõ ràng bạn muốn sử dụng chúng. Nhưng nếu nó ảnh hưởng đến khả năng đọc, hãy chờ đợi - bạn sẽ không nhận được nhiều lợi ích và thực sự có thể khiến bạn mất nhiều thời gian hơn để gỡ lỗi trong một đoạn đường dài.


2
Chỉ cần một vài điểm nhỏ trong ví dụ của bạn: Một chức năng trong máy đo nhịp tim mất 25ms sẽ không thành vấn đề miễn là các tác vụ cần thiết khác có thể xảy ra với thời gian đáp ứng được yêu cầu. Ngắt là tốt cho việc này. Và độ trễ 25ms cho một thứ chỉ giám sát các sự kiện trong thế giới thực để cập nhật màn hình cho tiêu dùng của con người có lẽ không phải là vấn đề.
janm

3

Là tối ưu hóa vi mô quan trọng khi mã hóa?

Không, cho rằng có các nền tảng như JVM.NET , nơi mã được viết cho máy ảo và do đó cố gắng tối ưu hóa thực thi có thể không hoạt động tốt như những gì tối ưu trên máy tính để bàn của nhà phát triển không nhất thiết phải giống nhau trên máy chủ. Hãy xem cách xa phần cứng một số phần mềm cấp cao này cho một điểm khác ở đây. Một cái gì đó để xem xét được đưa ra sự đa dạng của phần cứng, làm thế nào thực tế để tối ưu hóa mã cho các chip cụ thể như CPU ​​hoặc GPU khi một mô hình mới có thể sẽ xuất hiện trong vòng chưa đầy một năm?

Một câu hỏi khác ở đây cần xem xét là hiệu suất được đo bằng số liệu nào: Tốc độ thực thi, bộ nhớ được sử dụng trong thực thi, tốc độ phát triển các tính năng mới, kích thước của cơ sở mã trên máy chủ ở dạng được biên dịch hoặc khử, khả năng mở rộng, khả năng duy trì, v.v. .? Nếu được đưa ra đủ rộng, câu hỏi trở nên tầm thường, nhưng tôi không chắc bạn có ý định thực hiện rộng đến mức nào mà thực sự có thể là gần như mọi thứ miễn là nó có thể được đo theo một cách nào đó.


Một số tối ưu hóa vi mô có thể hoạt động và một số có thể không hoạt động, đó là nơi người ta có thể tự hỏi làm thế nào đáng giá để thực hiện công việc đó so với các công việc khác có thể được xem là ưu tiên cao hơn nhiều như các tính năng mới hoặc sửa lỗi. Câu hỏi khác là liệu việc nâng cấp phần cứng hay phần mềm có thể phá vỡ một số tối ưu hóa đó hay không.


1
Lưu ý rằng bạn hoàn toàn có thể thực hiện tối ưu hóa vi mô trên các nền tảng như JVM và .NET, chúng chỉ có các hình thức hơi khác nhau. Nhưng điều tương tự cũng đúng nếu bạn so sánh và trình biên dịch C đơn giản, cũ với trình biên dịch tối ưu hóa hiện đại hơn: các tối ưu hóa mà người dùng có thể làm sẽ khác.
Joachim Sauer

1

Tôi nghĩ rằng có một sự khác biệt lớn giữa lập trình tốt và tối ưu hóa vi mô.

Nếu có hai cách để thực hiện cùng một nhiệm vụ, một cách nhanh hơn cách khác và cả hai đều có cùng khả năng đọc, bạn nên sử dụng nhanh hơn. Luôn luôn. Và đây là chương trình tốt. Không có lý do để không sử dụng một thuật toán tốt hơn để giải quyết vấn đề. Và thậm chí tài liệu rất dễ dàng: đặt tên thuật toán, mọi người sẽ có thể google nó và tìm thêm thông tin về cách thức hoạt động của nó.

Và các thuật toán tốt đã được tối ưu hóa. Họ sẽ nhanh thôi. Chúng sẽ nhỏ. Họ sẽ sử dụng bộ nhớ tối thiểu cần thiết.

Ngay cả khi sử dụng chúng, chương trình của bạn vẫn không có hiệu suất đó, chúng vẫn có thể xem xét tối ưu hóa vi mô. Và bạn sẽ phải thực sự biết ngôn ngữ để có thể tối ưu hóa vi mô.

Và luôn có chỗ để chi thêm một số tiền cho phần cứng. Phần cứng là rẻ, lập trình viên là đắt tiền . Đừng dành quá nhiều thời gian / tiền bạc bằng cách tối ưu hóa khi bạn chỉ có thể mua phần cứng.


1

Khả năng đọc mã IMHO quan trọng hơn tối ưu hóa vi mô vì trong hầu hết các trường hợp, tối ưu hóa vi mô không có giá trị.

Bài viết về tối ưu hóa vi giác quan :

Như hầu hết chúng ta, tôi cảm thấy mệt mỏi khi đọc các bài đăng trên blog về tối ưu hóa vi mô không có ý nghĩa như thay thế in bằng echo, ++ $ i bằng $ i ++ hoặc trích dẫn kép bằng dấu ngoặc đơn. Tại sao? Bởi vì 99.999999% thời gian, nó không liên quan. Tại sao? Vì 99,99% thời gian, bạn nên cài đặt một trình tăng tốc PHP như APC hoặc thêm các chỉ mục bị thiếu này vào các cột cơ sở dữ liệu của bạn hoặc cố gắng tránh 1000 yêu cầu cơ sở dữ liệu bạn có trên trang chủ.

print sử dụng thêm một opcode bởi vì nó thực sự trả về một cái gì đó. Chúng ta có thể kết luận rằng echo nhanh hơn in. Nhưng một opcode không có gì, thực sự không có gì.

Tôi đã thử cài đặt WordPress mới. Kịch bản tạm dừng trước khi kết thúc bằng "Lỗi xe buýt" trên máy tính xách tay của tôi, nhưng số lượng opcodes đã ở mức hơn 2,3 triệu. Đủ nói.

Vì vậy, trong hầu hết các trường hợp, tối ưu hóa vi mô sẽ tiết kiệm được 1 thao tác trong số hàng triệu, nhưng làm cho khả năng đọc trở nên tồi tệ hơn.


1

Các câu trả lời khác là đúng trên tiền. Nhưng tôi sẽ thêm một điểm nữa trong đó người ta phải phân biệt tối ưu hóa sớm / tối ưu hóa vi mô và viết mã biểu diễn phản ánh sự hiểu biết về hành vi của các cấu trúc ngôn ngữ / khung (xin lỗi, cuối cùng không thể tìm thấy một từ nào) . Điều cuối cùng là một thực hành mã hóa tốt và thường nên làm!

Tôi sẽ giải thích. Tối ưu hóa kém (đọc tối ưu hóa sớm / vi mô) không phải là khi bạn tối ưu hóa các phần của mã mà không định hình để biết liệu chúng có thực sự là nút cổ chai hay không. Đó là khi bạn tối ưu hóa dựa trên các giả định, phiên điều trần và các hành vi không có giấy tờ. Nếu nó được ghi lại và làm một cái gì đó theo cách hiệu quả / hợp lý hơn dù nó nhỏ, tôi gọi đó là tối ưu hóa tốt . Như những người khác đã tuyên bố, cả hai điều này đều có nhược điểm và hầu như không có lợi ích gì liên quan đến việc bạn kiếm được doanh nghiệp tốt, nhưng tôi vẫn làm sau, chứ không phải trước, nếu nó không hoàn toàn đánh bại khả năng đọc. Có khả năng đọc / bảo trì là vô cùng quan trọng và đó là về nơi bạn vẽ đường.

Tôi sẽ nhắc lại những điểm mà những người khác ở đây đưa ra là sự vô ích của cả tối ưu hóa tốt và xấu:

  1. Sự phụ thuộc của bạn vào một vấn đề cụ thể có thể thay đổi và bất kỳ thời gian nào để tối ưu hóa trước khi hoàn thành phần logic của ứng dụng của bạn là một sự lãng phí thời gian. Tôi có nghĩa là tối ưu hóa ở giai đoạn tương đối sớm. Hôm nay bạn có một List<T>thời gian và ứng dụng của bạn xuất xưởng, bạn phải thay đổi nó LinkedList<T>và bây giờ tất cả các điểm chuẩn là một sự lãng phí thời gian và công sức.

  2. Chủ yếu là nút cổ chai thực sự của ứng dụng của bạn (đọc là sự khác biệt có thể đo lường được) có thể là 5% mã của bạn (chủ yếu là mã sql) và tối ưu hóa 95% khác không mang lại cho khách hàng của bạn bất kỳ lợi ích nào.

  3. Thông thường "về mặt kỹ thuật" mã hiệu suất tốt hơn có nghĩa là độ chi tiết cao hơn, điều đó có nghĩa là mã dễ bị lỗi hơn, điều này có nghĩa là khả năng bảo trì khó hơn và mất nhiều thời gian hơn, điều đó có nghĩa là bạn kiếm được ít tiền hơn.

  4. Lượng khí thải carbon bạn tiết kiệm cho toàn thế giới thông qua mức tăng hiệu suất 1% rất dễ bị ảnh hưởng bởi khí nhà kính mà nhóm của bạn sẽ phải phát ra khi gỡ lỗi và duy trì mã đó.

Các tiêu cực của tối ưu hóa cụ thể là:

  1. Nó không thường mang lại cho bạn hiệu suất mà bạn mong đợi. Xem câu hỏi này trên SO, nơi tối ưu hóa đã đi sai . Trong thực tế, nó có thể có tác dụng phụ. Đó là vấn đề với hành vi không có giấy tờ.

  2. Hầu hết các trình biên dịch hiện đại sẽ làm điều đó cho bạn bằng mọi cách.

Tôi sẽ đưa ra một số ví dụ về tối ưu hóa tốt và tốt:

Những người xấu -

  1. sử dụng các loại số nguyên nhỏ hơn thay vì Int32.

  2. ++i được sử dụng thay vì i++

  3. forthay vì foreach(điều tồi tệ nhất tôi đã thấy, hoàn toàn đánh bại logic)

  4. tránh các biến đóng

    string p;
    foreach (var item in collection)
        p = ...;
    
  5. sử dụng charthay vì chuỗi trong quá trình nối chuỗi, như:

    string me = 'i' + "me myself"; // something along that line - causes boxing
    

Điều tốt (từ thế giới .NET. Nên tự giải thích) -

  1. Tra cứu đôi

    if (Dictionary<K, V>.TryGetValue(K, out V))
        do something with V
    

    thay vì

    if (Dictionary<K, V>.ContainsKey(K))
        do something with Dictionary<K, V>[K]
    
  2. Tải tất cả

    DirectoryInfo.EnumerateFiles();
    

    thay vì

    DirectoryInfo.GetFiles();
    
  3. Đúc hai giai đoạn:

    s = o as string;
    if (s != null)
        proceed
    

    thay vì

    if (o is string)
        s = (string)o;
    
  4. Nếu thứ tự không quan trọng

    if (counter < X || expensiveFunction())
    

    thay vì

    if (expensiveFunction() || counter < X)
    
  5. quyền anh

    void M<T>(T o) //avoids boxing
    {
    
    }
    

    thay vì

    void M(object o)
    {
    
    }
    

Nếu bạn hỏi tôi nếu những điều này mang lại lợi ích hiệu suất đáng chú ý, tôi sẽ nói không. Nhưng tôi sẽ đề nghị một người nên sử dụng chúng bởi vì nó bắt nguồn từ sự hiểu biết về hành vi của các cấu trúc này. Tại sao thực hiện hai cuộc gọi khi bạn chỉ có thể thực hiện 1 cuộc gọi? Từ quan điểm triết học, thực hành mã hóa tốt của nó. Và 1 & 3 thì hơi khó đọc hơn về mặt nghiêm ngặt, nhưng liệu chúng có dễ đọc không? Không, không nhiều, vì vậy tôi sử dụng. Bây giờ đó là chìa khóa - duy trì hiệu suất tốt cho tỷ lệ dễ đọc. Và khi đó, đó là về nơi bạn vẽ đường.


1

"Đáng giá" cần bối cảnh, như việc viết và đọc và duy trì đơn giản hơn bao nhiêu so với việc nó khiến người dùng phản ứng nhanh hơn, tương tác nhanh hơn, cần ít thời gian hơn để họ chờ đợi.

Tiết kiệm một vài đồng xu để mua một lon soda sẽ không giúp tôi nhiều nếu tôi phải đi một quãng đường để tiết kiệm những đồng xu đó, đặc biệt là tôi hiếm khi uống soda trong những ngày này. Tiết kiệm một vài đồng xu mỗi lon khi mua một triệu lon soda có thể là một vấn đề lớn.

Trong khi đó, tiết kiệm một vài đồng xu khi hai người ở ngay cạnh tôi và một người đưa ra điều tương tự chính xác với một vài đồng xu rẻ hơn và người kia thì không, và tôi chọn một chiếc đắt hơn vì tôi thích chiếc mũ của họ hơn có vẻ như là một trường hợp ngu ngốc bi quan.

Điều tôi thường thấy là những người gọi là "tối ưu hóa vi mô" dường như không có sự đo lường, bối cảnh và thảo luận về người dùng, khi hoàn toàn nên có cả ba để xem xét tối ưu hóa như vậy nếu chúng không áp dụng tầm thường. Đối với tôi một tối ưu hóa vi mô thích hợp ngày nay liên quan đến những thứ như bố cục bộ nhớ và các mẫu truy cập, và mặc dù chúng có vẻ "vi mô" trong tiêu điểm, chúng không có hiệu lực vi mô.

Cách đây không lâu, tôi đã giảm được một thao tác giảm từ 24 giây xuống còn 25 mili giây (nhanh hơn khoảng 960 lần), với các đầu ra giống hệt nhau (được bảo đảm bằng các thử nghiệm tự động), không thay đổi độ phức tạp thuật toán, cho quá trình khuếch tán nhiệt thể tích, qua "Tối ưu hóa vi mô" (phần lớn nhất đến từ sự thay đổi trong cách bố trí bộ nhớ đã giảm xuống còn khoảng 2 giây, phần còn lại là những thứ như SIMD và phân tích thêm về lỗi bộ nhớ cache trong VTune và sắp xếp lại bố cục bộ nhớ).

Wolfire giải thích kỹ thuật ở đây và anh ta vật lộn với thời gian cần thiết: http://blog.wolfire.com/2009/11/volumetric-heat-diffusion- leatherning /

Việc triển khai của tôi đã xoay sở để có thể làm điều đó trong một phần nghìn giây trong khi anh ta đang vật lộn để hạ nó xuống dưới một phút: nhập mô tả hình ảnh ở đây

Sau khi tôi "tối ưu hóa vi mô", nó giảm từ 24 giây xuống còn 25 giây, đó là một công cụ thay đổi trò chơi trong quy trình làm việc. Giờ đây, các nghệ sĩ có thể thay đổi giàn khoan của họ trong thời gian thực ở mức trên 30 FPS mà không phải chờ 24 giây mỗi khi họ thực hiện bất kỳ thay đổi nhỏ nào đối với giàn khoan của họ. Và điều đó thực sự đã thay đổi toàn bộ thiết kế phần mềm của tôi vì tôi không còn cần thanh tiến trình và những thứ thuộc loại này, tất cả đã trở thành tương tác. Vì vậy, đó có thể là một "tối ưu hóa vi mô" theo nghĩa là tất cả các cải tiến đều không có sự cải thiện về độ phức tạp thuật toán, nhưng nó thực sự là một "tối ưu hóa lớn" tạo ra quá trình trước đây là một quá trình không tương tác đau đớn vào thời gian thực, tương tác thay đổi hoàn toàn cách người dùng làm việc.

Đo lường, Yêu cầu kết thúc người dùng, Bối cảnh

Tôi thực sự thích bình luận của Robert ở đây và có lẽ tôi đã thất bại trong việc đưa ra quan điểm mà tôi muốn:

Vâng, xin chào. Không ai sẽ tranh luận rằng loại thay đổi này không "đáng giá". Bạn đã có thể chứng minh một lợi ích hữu hình; nhiều cái gọi là tối ưu hóa vi mô không thể.

Điều này là, mặc dù làm việc trong một lĩnh vực rất quan trọng về hiệu suất với các yêu cầu thường xuyên theo thời gian thực, lần duy nhất tôi xem xét bất kỳ tối ưu hóa vi mô nào đòi hỏi phải thực hiện theo cách của tôi.

Và tôi nhấn mạnh không chỉ các phép đo mà cả phía người dùng của nó. Tôi là một người kỳ quặc khi tôi đến với lĩnh vực hiện tại của mình (và trước đây là gamedev) với tư cách là người dùng / người hâm mộ đầu tiên, nhà phát triển thứ hai. Vì vậy, tôi chưa bao giờ hào hứng với những điều thông thường khiến các lập trình viên thích giải quyết các câu đố kỹ thuật; Tôi thấy họ là một gánh nặng, nhưng sẽ vượt qua họ thông qua giấc mơ kết thúc người dùng mà tôi đã chia sẻ với những người dùng khác. Nhưng điều đó giúp tôi đảm bảo nếu tôi tối ưu hóa bất cứ điều gì, nó sẽ có tác động thực sự đến người dùng với lợi ích thực sự. Đó là biện pháp bảo vệ của tôi chống lại tối ưu hóa vi mô một cách vô mục đích.

Theo tôi, điều đó thực sự quan trọng như trình hồ sơ, bởi vì tôi đã có những đồng nghiệp đã làm những việc như phân chia tối ưu hóa vi mô thành một tỷ khía cạnh chỉ để bóp nghẹt các mô hình sản xuất trong thế giới thực như nhân vật và phương tiện. Kết quả của họ rất ấn tượng theo nghĩa "bản demo công nghệ", nhưng hầu như vô dụng với người dùng thực tế, bởi vì họ đã định hình và đo lường và đo điểm chuẩn không phù hợp với các trường hợp sử dụng trong thế giới thực. Vì vậy, điều quan trọng là phải hiểu những gì quan trọng đối với người dùng trước tiên, bằng cách học cách suy nghĩ và sử dụng phần mềm như một hoặc cộng tác với họ (lý tưởng là cả hai, nhưng ít nhất là cộng tác với họ).


2
Vâng, xin chào. Không ai sẽ tranh luận rằng loại thay đổi này không "đáng giá". Bạn đã có thể chứng minh một lợi ích hữu hình; nhiều cái gọi là tối ưu hóa vi mô không thể.
Robert Harvey

1
@RobertHarvey Đó là loại điểm Tôi đã hy vọng để làm, vì những gì một số người gọi là "vi-tối ưu hóa" không nhất thiết phải bằng kính hiển vi có hiệu lực, nhưng nó quá phụ thuộc vào bối cảnh, đo lường vv issetvs strlendường như rất nhỏ hơn trong tập trung vắng mặt bối cảnh và đo lường. :-D
Năng lượng rồng

1
@RobertHarvey Tôi đã hy vọng nói, có thể mặc dù gián tiếp, rằng nếu có một bối cảnh tiêu cực đối với "tối ưu hóa vi mô", thì đó là loại có xu hướng không có các phép đo, bối cảnh và nhu cầu của người dùng. Tôi cũng có thể tiếp tục về trường hợp cuối cùng vì tôi có một đồng nghiệp đã tối ưu hóa địa ngục khỏi thứ gì đó hay ho, ngoại trừ không ai sử dụng nó. Tôi thậm chí nghĩ rằng tối ưu hóa phù hợp đòi hỏi một số hiểu biết từ người dùng, nếu không chúng ta có thể định hình và điều chỉnh những thứ mà người dùng không quan tâm.
Năng lượng rồng

1
Một số tối ưu hóa được thúc đẩy bởi nhu cầu cấp bách, trong khi một số khác được thúc đẩy bởi sự tò mò (theo đuổi trí tuệ và phiêu lưu). Chúng tôi cần cả hai. Trong câu chuyện của Dragon Energy, có lẽ đó không phải là "nhu cầu cấp bách", vì các nghệ sĩ dường như không phàn nàn lớn về việc không thấy bất kỳ kết quả kết xuất nào cho đến 24 giây sau mỗi lần chỉnh sửa. Trên thực tế, người dùng có thể không biết nó có thể nhanh đến mức nào, cho đến khi một lập trình viên đầu tư vào tất cả nỗ lực để đánh bại kỷ lục tốc độ. Giới hạn bản thân với nhu cầu thúc đẩy có ý nghĩa kinh doanh, nhưng làm như vậy sẽ bỏ lỡ một số cơ hội tối ưu hóa tuyệt vời hoặc thay đổi trò chơi.
rwong

1
Nói về ý nghĩa kinh doanh, đó cũng là vấn đề kiếm tiền. Mỗi động thái (ví dụ như một lập trình viên làm việc về tối ưu hóa hiệu suất) đều phải trả tiền và chi phí cần phải được thu lại để có ý nghĩa kinh doanh. Do đó, người ta phải hỏi liệu cải thiện tốc độ thay đổi trò chơi có thể được "bán" hay "tiết kiệm" được bao nhiêu tiền, nếu lập trình viên phải được sự chấp thuận của người quản lý doanh nghiệp.
rwong

0

Tôi sẽ giải thích nó theo cách này - tối ưu hóa vi mô là một quá trình tối ưu hóa một cái gì đó hoàn toàn không phải là nút cổ chai. Ví dụ: nếu chương trình của bạn gọi hai hàm A và B và A mất 100 mili giây để hoàn thành và B mất 2 micro giây và bạn tiếp tục tối ưu hóa chức năng B. Điều đó không chỉ không quan trọng, điều đó hoàn toàn sai. Nhưng tối ưu hóa chức năng B được gọi là tối ưu hóa và không tối ưu hóa vi mô. Tầm quan trọng của tối ưu hóa phụ thuộc. Giả sử bạn không có gì khác để làm và chương trình của bạn không có lỗi, thì đúng vậy, điều đó rất quan trọng. Nhưng nhìn chung bạn có những ưu tiên. Giả sử bạn cần thêm / ghi chức năng C. Nếu bạn nghĩ rằng chức năng viết C sẽ giúp bạn kiếm được nhiều tiền hơn là làm cho chương trình của bạn nhanh hơn mà không có chức năng đó, thì hãy đi tối ưu hóa. Nếu không thì theo đuổi chức năng. Cũng thế, Các lập trình viên giàu kinh nghiệm tập trung vào hiệu suất không dành nhiều thời gian để tối ưu hóa, họ chỉ viết các chương trình nhanh. Ít nhất là họ biết nên sử dụng công cụ nào và không nên mất bao nhiêu năm để tối ưu hóa (đọc vi mô) vô nghĩa.


bài này khá khó đọc (tường văn bản). Bạn có phiền chỉnh sửa ing nó thành một hình dạng tốt hơn?
gnat
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.