Tối ưu hóa C++ - Kỹ thuật nâng cao hiệu suất theo Kurt Guntheroth

Người đăng

Ẩn danh

Thể loại

Sách kỹ thuật

2016

387
0
0

Phí lưu trữ

75 Point

Tóm tắt

I. Tổng quan về tối ưu hóa hiệu năng C

Tối ưu hóa C++ là quá trình cải thiện hiệu suất chương trình một cách có hệ thống. Đây không phải là bước tùy chọn mà là một phần thiết yếu của quy trình phát triển phần mềm chuyên nghiệp. Cuốn sách Optimized C++ của Kurt Guntheroth, xuất bản năm 2016 bởi O'Reilly Media, tổng hợp các kỹ thuật đã được chứng minh qua thực tiễn. Hiệu suất chương trình phụ thuộc vào nhiều yếu tố: thuật toán, cấu trúc dữ liệu, quản lý bộ nhớ và mức độ đồng thời. Quy tắc 90/10 phát biểu rằng 90% thời gian chạy tập trung vào 10% mã nguồn. Tối ưu hóa đúng chỗ mang lại cải thiện đáng kể. Ví dụ thực tế từ thiết bị nhúng Fluke 9010A cho thấy: tối ưu hóa một hàm duy nhất trong 45 phút đã cải thiện thông lượng tổng thể lên 7%. Điều này minh chứng rằng tối ưu hóa có chọn lọc và có đo lường là phương pháp hiệu quả nhất. Các chiến lược cốt lõi bao gồm sử dụng trình biên dịch tốt hơn, chọn thuật toán phù hợp, giảm phân bổ bộ nhớ, loại bỏ tính toán dư thừa và tăng tính đồng thời. Mỗi chiến lược tác động đến các tầng khác nhau của hệ thống và cần được đánh giá dựa trên đo lường thực tế.

1.1. Tối ưu hóa là một phần của phát triển phần mềm

Tối ưu hóa không mâu thuẫn với quy trình phát triển phần mềm. Đây là một giai đoạn có thể lặp lại sau khi chức năng đã hoạt động đúng. Nhiều lập trình viên lầm tưởng rằng tối ưu hóa sớm là phương pháp tốt. Thực tế ngược lại: cần đo lường trước, tối ưu sau. Khi chức năng ổn định, công việc tối ưu hóa mới có ý nghĩa thực tiễn. Thời gian bỏ ra để đo lường và phân tích luôn cho kết quả tốt hơn so với tối ưu hóa theo trực giác. Tài liệu từ O'Reilly khẳng định rằng tối ưu hóa hiệu quả và không tốn kém nếu được thực hiện đúng thời điểm và đúng vị trí trong mã nguồn.

1.2. Quy tắc 90 10 trong phân tích hiệu năng

Quy tắc 90/10 là nguyên lý nền tảng của tối ưu hóa hiệu năng. Phần lớn thời gian CPU tập trung ở một số điểm nóng rất nhỏ trong chương trình. Xác định đúng điểm nóng là chìa khóa thành công. Công cụ đo lường như profiler giúp phát hiện các hàm tiêu tốn nhiều tài nguyên nhất. Sau khi tối ưu điểm nóng đầu tiên, điểm nóng tiếp theo thường có đóng góp nhỏ hơn nhiều. Kinh nghiệm từ dự án Fluke 9010A xác nhận điều này: sau cải tiến đầu tiên đạt 7%, không tìm được thay đổi nào khác cho kết quả trên 1%. Vì vậy, tối ưu hóa cần dừng khi lợi ích biên giảm xuống mức không đáng kể.

II. Phân tích các yếu tố ảnh hưởng đến hiệu năng C

Hiệu năng C++ bị ảnh hưởng bởi nhiều tầng kiến trúc máy tính. Trình biên dịch đóng vai trò quan trọng đầu tiên. Các compiler hiện đại như GCC và Clang có khả năng tối ưu hóa tự động ở mức cao, nhưng không thể thay thế hoàn toàn cho tư duy tối ưu của lập trình viên. Bộ nhớ là yếu tố ảnh hưởng lớn thứ hai. Phân bổ bộ nhớ động trên heap tốn kém hơn nhiều so với bộ nhớ stack. Sao chép dữ liệu không cần thiết gây lãng phí thời gian đáng kể. Hành vi cache của CPU cũng quyết định hiệu năng thực tế. Truy cập dữ liệu tuần tự nhanh hơn truy cập ngẫu nhiên vì tận dụng được cache line. Thuật toán và cấu trúc dữ liệu là tầng có tác động lớn nhất. Thay đổi thuật toán từ O(n²) xuống O(n log n) mang lại cải thiện vượt trội so với mọi kỹ thuật vi tối ưu. Tính đồng thời là chiến lược mở rộng khả năng xử lý trên phần cứng đa nhân hiện đại. Cuối cùng, các thư viện được tối ưu sẵn như Boost và Google có thể thay thế các triển khai tự viết kém hiệu quả hơn.

2.1. Tác động của trình biên dịch và thư viện đến hiệu suất

Trình biên dịch C++ không tuân thủ hoàn toàn theo chuẩn ngôn ngữ mà tuân theo chuẩn tại thời điểm phát hành. Điều này tạo ra sự không nhất quán giữa các môi trường. Tối ưu hóa dựa vào đặc điểm riêng của compiler có thể không di động sang nền tảng khác. Thư viện chuẩn C++ cung cấp nhiều thuật toán và container được tối ưu hóa sẵn. Thành thạo thư viện chuẩn là kỹ năng then chốt cho lập trình viên tối ưu hóa. Các thư viện mã nguồn mở như high-performance memory manager có thể nhanh hơn runtime mặc định và dễ tích hợp vào dự án hiện có mà không cần viết lại từ đầu.

2.2. Quản lý bộ nhớ và chi phí phân bổ động

Phân bổ bộ nhớ động là một trong những nguồn gốc chi phí ẩn phổ biến nhất trong C++. Mỗi lần gọi new hoặc malloc đều có overhead từ hệ điều hành và memory allocator. Giảm số lần phân bổ là mục tiêu tối ưu quan trọng. Kỹ thuật object pooling, arena allocator và stack allocation giúp hạn chế chi phí này. Sao chép đối tượng lớn cũng gây lãng phí đáng kể. Move semantics trong C++11 và sau đó cho phép chuyển quyền sở hữu tài nguyên thay vì sao chép, cải thiện hiệu năng trong nhiều tình huống phổ biến liên quan đến container và smart pointer.

III. Phương pháp và kỹ thuật tối ưu hóa C hiệu quả

Tối ưu hóa C++ đòi hỏi phương pháp có hệ thống, không phải trực giác. Bước đầu tiên luôn là đo lường. Profiler như Valgrind, gprof hoặc perf xác định chính xác điểm nóng. Không đo lường, không tối ưu. Bước thứ hai là phân tích nguyên nhân gốc rễ. Một hàm chậm có thể do thuật toán tệ, do cache miss hay do contention trong môi trường đa luồng. Nguyên nhân khác nhau đòi hỏi giải pháp khác nhau. Bước thứ ba là áp dụng kỹ thuật phù hợp. Sáu chiến lược chính từ sách Optimized C++ gồm: sử dụng compiler tốt hơn và dùng đúng cách, chọn thuật toán tốt hơn, dùng thư viện được tối ưu, giảm phân bổ bộ nhớ và sao chép, loại bỏ tính toán không cần thiết và tăng tính đồng thời. Bước cuối cùng là kiểm tra lại. Mọi thay đổi tối ưu phải được đo lường để xác nhận cải tiến thực sự. Đôi khi tối ưu hóa vi mô làm chậm chương trình do phá vỡ cơ chế tối ưu của compiler.

3.1. Tối ưu hóa thuật toán và cấu trúc dữ liệu

Thuật toán tốt hơn mang lại cải thiện lớn nhất. Thay thế tìm kiếm tuyến tính O(n) bằng tìm kiếm nhị phân O(log n) trên tập dữ liệu lớn tạo ra sự khác biệt lớn hơn mọi kỹ thuật vi tối ưu. Cấu trúc dữ liệu phù hợp với mô hình truy cập dữ liệu quyết định hiệu năng thực tế. Vector liên tục trong bộ nhớ thường nhanh hơn linked list vì tận dụng cache. Unordered map nhanh hơn map có thứ tự cho tra cứu đơn thuần. Sách Optimized C++ dành riêng các chương 9 và 10 cho tìm kiếm, sắp xếp và tối ưu container, phản ánh tầm quan trọng của lĩnh vực này trong thực tế.

3.2. Kỹ thuật tăng tính đồng thời và giảm tính toán

Tăng tính đồng thời tận dụng phần cứng đa nhân hiện đại. Phân chia công việc độc lập ra nhiều luồng có thể cải thiện throughput tuyến tính. Tuy nhiên, đồng bộ hóa không đúng cách tạo ra bottleneck mới. Loại bỏ tính toán dư thừa là kỹ thuật đơn giản nhưng hiệu quả. Memoization lưu kết quả tính toán tốn kém để tái sử dụng. Lazy evaluation trì hoãn tính toán cho đến khi thực sự cần. Precomputation di chuyển phần tính toán không đổi ra ngoài vòng lặp. Những kỹ thuật này không yêu cầu thay đổi cấu trúc lớn mà mang lại cải thiện đáng kể trong các vòng lặp nóng.

IV. Kết luận và ứng dụng thực tiễn tối ưu hóa C

Tối ưu hóa C++ là nghệ thuật kết hợp kiến thức lý thuyết với kinh nghiệm thực tiễn. Sách Optimized C++ của Kurt Guntheroth cung cấp nền tảng vững chắc cho cả hai khía cạnh này. Nguyên tắc cốt lõi không thay đổi theo thời gian: đo lường trước, tối ưu sau, kiểm tra lại. Ứng dụng thực tiễn đầu tiên là xây dựng thói quen đo lường từ sớm. Tích hợp profiling vào quy trình phát triển giúp phát hiện vấn đề hiệu năng sớm, khi chi phí sửa chữa còn thấp. Ứng dụng thứ hai là nắm vững thư viện chuẩn C++. Nhiều container và thuật toán trong STL được tối ưu kỹ lưỡng. Sử dụng đúng cách thường hiệu quả hơn tự viết. Ứng dụng thứ ba là hiểu kiến trúc phần cứng đích. Cache behavior, branch prediction và memory layout ảnh hưởng trực tiếp đến hiệu năng mã C++. Lập trình viên hiểu phần cứng viết mã tốt hơn một cách tự nhiên. Cuối cùng, kinh nghiệm từ dự án Fluke 9010A nhắc nhở rằng đôi khi một thay đổi nhỏ, đúng chỗ, tạo ra tác động lớn hơn mọi nỗ lực tối ưu toàn diện.

4.1. Xây dựng quy trình tối ưu hóa bền vững

Quy trình tối ưu hóa bền vững bắt đầu từ benchmark rõ ràng. Thiết lập các chỉ số hiệu năng cụ thể trước khi bắt đầu tối ưu. Điều này tạo ra mục tiêu đo lường được và tiêu chí dừng rõ ràng. Tích hợp kiểm tra hiệu năng vào CI/CD pipeline ngăn chặn hiện tượng regression hiệu năng. Mỗi commit mới chạy benchmark và cảnh báo khi hiệu năng suy giảm. Tài liệu hóa quyết định tối ưu giúp đội nhóm hiểu lý do đằng sau mã phức tạp và tránh vô tình hoàn tác các tối ưu quan trọng trong tương lai.

4.2. Ứng dụng tối ưu hóa I O và quản lý bộ nhớ nâng cao

I/O là nguồn bottleneck phổ biến trong các ứng dụng thực tế. Buffered I/O, async I/O và memory-mapped files là các kỹ thuật cải thiện throughput đáng kể. Sách Optimized C++ dành riêng chương 11 cho tối ưu I/O, phản ánh tầm quan trọng trong sản xuất. Quản lý bộ nhớ nâng cao thông qua custom allocator và memory pool phù hợp với các ứng dụng có yêu cầu real-time. High-performance memory manager từ mã nguồn mở như jemalloc hay tcmalloc cung cấp hiệu năng vượt trội so với allocator mặc định trong nhiều kịch bản tải cao liên tục.

21/04/2026

Trích đoạn nội dung tài liệu

Optimized C++ PROVEN TECHNIQUES FOR HEIGHTENED PERFORMANCE Kurt Guntheroth Optimized C++ Kurt Guntheroth Beijing Boston Farnham Sebastopol Tokyo Optimized C++ by Kurt Guntheroth Copyright © 2016 Kurt Guntheroth. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://safaribooksonline. For more information, contact our corporate/ institutional sales department: 800-998-9938 or corporate@oreilly. Editors: Meghan Blanchette and Andy Oram Indexer: Judy McConville Acquisition Editor: Meghan Blanchette Interior Designer: David Futato Production Editor: Nicole Shelby Cover Designer: Randy Comer Copyeditor: Rachel Head Illustrator: Rebecca Demarest Proofreader: Jasmine Kwityn April 2016: First Edition Revision History for the First Edition 2016-04-27: First Release See http://oreilly.com/catalog/errata.csp?isbn=9781491922064 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Optimized C++, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. 978-1-491-92206-4 [LSI] Everyone thanks their spouse for helping make a book possible. It’s trite, I know. My wife Renee Ostler made this book possible by giving me permission to take months off work, by giving me time and space to focus on writing, and by staying up late asking me ques‐ tions about optimizing C++ code, even though she wasn’t particularly engaged by the topic, just to show her support. She made this project important to her because it was important to me. No author could ask for more. Table of Contents Preface. An Overview of Optimization. 1 Optimization Is Part of Software Development 2 Optimization Is Effective 3 It’s OK to Optimize 3 A Nanosecond Here, a Nanosecond There 6 Summary of Strategies for Optimizing C++ Code 6 Use a Better Compiler, Use Your Compiler Better 7 Use Better Algorithms 8 Use Better Libraries 9 Reduce Memory Allocation and Copying 10 Remove Computation 11 Use Better Data Structures 12 Increase Concurrency 12 Optimize Memory Management 12 Summary 12 2. Computer Behavior Affecting Optimization. 15 Lies C++ Believes About Computers 16 The Truth About Computers 17 Memory Is Slow 17 Memory Is Not Accessed in Bytes 18 Some Memory Accesses Are Slower than Others 19 Memory Words Have a Big End and a Little End 20 Memory Has Finite Capacity 20 Instruction Execution Is Slow 21 Making Decisions Is Hard for Computers 22 v There Are Multiple Streams of Program Execution 22 Calling into the Operating System Is Expensive 24 C++ Tells Lies Too 24 All Statements Are Not Equally Expensive 24 Statements Are Not Executed in Order 25 Summary 26 3. 27 The Optimizing Mindset 28 Performance Must Be Measured 28 Optimizers Are Big Game Hunters 29 The 90/10 Rule 29 Amdahl’s Law 31 Perform Experiments 32 Keep a Lab Notebook 34 Measure Baseline Performance and Set Goals 35 You Can Improve Only What You Measure 37 Profile Program Execution 37 Time Long-Running Code 40 “A Little Learning” About Measuring Time 40 Measuring Time with Computers 46 Overcoming Measurement Obstacles 54 Create a Stopwatch Class 58 Time Hot Functions in a Test Harness 62 Estimate Code Cost to Find Hot Code 63 Estimate the Cost of Individual C++ Statements 63 Estimate the Cost of Loops 64 Other Ways to Find Hot Spots 66 Summary 67 4. Optimize String Use: A Case Study. 69 Why Strings Are a Problem 69 Strings Are Dynamically Allocated 70 Strings Are Values 70 Strings Do a Lot of Copying 71 First Attempt at Optimizing Strings 72 Use Mutating String Operations to Eliminate Temporaries 74 Reduce Reallocation by Reserving Storage 74 Eliminate Copying of String Arguments 75 Eliminate Pointer Dereference Using Iterators 76 Eliminate Copying of Returned String Values 77 Use Character Arrays Instead of Strings 78 vi | Table of Contents Summary of First Optimization Attempt 80 Second Attempt at Optimizing Strings 80 Use a Better Algorithm 80 Use a Better Compiler 82 Use a Better String Library 83 Use a Better Allocator 87 Eliminate String Conversion 88 Conversion from C String to std::string 89 Converting Between Character Encodings 89 Summary 90 5. 91 Time Cost of Algorithms 92 Best-Case, Average, and Worst-Case Time Cost 95 Amortized Time Cost 95 Other Costs 96 Toolkit to Optimize Searching and Sorting 96 Efficient Search Algorithms 96 Time Cost of Searching Algorithms 97 All Searches Are Equal When n Is Small 98 Efficient Sort Algorithms 98 Time Cost of Sorting Algorithms 99 Replace Sorts Having Poor Worst-Case Performance 99 Exploit Known Properties of the Input Data 100 Optimization Patterns 100 Precomputation 101 Lazy Computation 102 Batching 102 Caching 103 Specialization 104 Taking Bigger Bites 104 Hinting 105 Optimizing the Expected Path 105 Hashing 105 Double-Checking 105 Summary 106 6. Optimize Dynamically Allocated Variables. 107 C++ Variables Refresher 108 Storage Duration of Variables 108 Ownership of Variables 111 Value Objects and Entity Objects 112 Table of Contents | vii C++ Dynamic Variable API Refresher 113 Smart Pointers Automate Ownership of Dynamic Variables 116 Dynamic Variables Have Runtime Cost 118 Reduce Use of Dynamic Variables 119 Create Class Instances Statically 119 Use Static Data Structures 121 Use std::make_shared Instead of new 124 Don’t Share Ownership Unnecessarily 125 Use a “Master Pointer” to Own Dynamic Variables 126 Reduce Reallocation of Dynamic Variables 127 Preallocate Dynamic Variables to Prevent Reallocation 127 Create Dynamic Variables Outside of Loops 128 Eliminate Unneeded Copying 129 Disable Unwanted Copying in the Class Definition 130 Eliminate Copying on Function Call 131 Eliminate Copying on Function Return 132 Copy Free Libraries 134 Implement the “Copy on Write” Idiom 136 Slice Data Structures 137 Implement Move Semantics 137 Nonstandard Copy Semantics: A Painful Hack 138 std::swap(): The Poor Man’s Move Semantics 138 Shared Ownership of Entities 139 The Moving Parts of Move Semantics 140 Update Code to Use Move Semantics 141 Subtleties of Move Semantics 142 Flatten Data Structures 145 Summary 146 7. Optimize Hot Statements. 147 Remove Code from Loops 148 Cache the Loop End Value 149 Use More Efficient Loop Statements 149 Count Down Instead of Up 150 Remove Invariant Code from Loops 151 Remove Unneeded Function Calls from Loops 152 Remove Hidden Function Calls from Loops 155 Remove Expensive, Slow-Changing Calls from Loops 156 Push Loops Down into Functions to Reduce Call Overhead 157 Do Some Actions Less Frequently 158 What About Everything Else? 160 Remove Code from Functions 160 viii | Table of Contents Cost of Function Calls 161 Declare Brief Functions Inline 165 Define Functions Before First Use 165 Eliminate Unused Polymorphism 165 Discard Unused Interfaces 166 Select Implementation at Compile Time with Templates 170 Eliminate Uses of the PIMPL Idiom 171 Eliminate Calls into DLLs 173 Use Static Member Functions Instead of Member Functions 173 Move Virtual Destructor to Base Class 174 Optimize Expressions 174 Simplify Expressions 175 Group Constants Together 176 Use Less-Expensive Operators 177 Use Integer Arithmetic Instead of Floating Arithmetic 177 Double May Be Faster than Float 179 Replace Iterative Computations with Closed Forms 180 Optimize Control Flow Idioms 181 Use switch Instead of if-elseif-else 182 Use Virtual Functions Instead of switch or if 182 Use No-Cost Exception Handling 183 Summary 185 8. Use Better Libraries. 187 Optimize Standard Library Use 187 Philosophy of the C++ Standard Library 188 Issues in Use of the C++ Standard Library 188 Optimize Existing Libraries 191 Change as Little as Possible 191 Add Functions Rather than Change Functionality 192 Design Optimized Libraries 192 Code in Haste, Repent at Leisure 193 Parsimony Is a Virtue in Library Design 194 Make Memory Allocation Decisions Outside the Library 194 When in Doubt, Code Libraries for Speed 195 Functions Are Easier to Optimize than Frameworks 195 Flatten Inheritance Hierarchies 196 Flatten Calling Chains 196 Flatten Layered Designs 196 Avoid Dynamic Lookup 197 Beware of ‘God Functions’ 198 Summary 199 Table of Contents | ix 9. Optimize Searching and Sorting. 201 Key/Value Tables Using std::map and std::string 202 Toolkit to Improve Search Performance 203 Make a Baseline Measurement 204 Identify the Activity to Be Optimized 204 Decompose the Activity to Be Optimized 205 Change or Replace Algorithms and Data Structures 206 Using the Optimization Process on Custom Abstractions 208 Optimize Search Using std::map 208 Use Fixed-Size Character Array Keys with std::map 208 Use C-Style String Keys with std::map 210 Using Map’s Cousin std::set When the Key Is in the Value 212 Optimize Search Using the <algorithm> Header 213 Key/Value Table for Search in Sequence Containers 214 std::find(): Obvious Name, O(n) Time Cost 215 std::binary_search(): Does Not Return Values 216 Binary Search Using std::equal_range() 216 Binary Search Using std::lower_bound() 217 Handcoded Binary Search 218 Handcoded Binary Search using strcmp() 219 Optimize Search in Hashed Key/Value Tables 220 Hashing with a std::unordered_map 221 Hashing with Fixed Character Array Keys 221 Hashing with Null-Terminated String Keys 222 Hashing with a Custom Hash Table 224 Stepanov’s Abstraction Penalty 225 Optimize Sorting with the C++ Standard Library 226 Summary 228 10. Optimize Data Structures. 229 Get to Know the Standard Library Containers 229 Sequence Containers 230 Associative Containers 230 Experimenting with the Standard Library Containers 231 std::vector and std::string 236 Performance Consequences of Reallocation 237 Inserting and Deleting in std::vector 238 Iterating in std::vector 240 Sorting std::vector 241 Lookup with std::vector 241 std::deque 242 Inserting and Deleting in std::deque 243 x | Table of Contents Iterating in std::deque 245 Sorting std::deque 245 Lookup with std::deque 245 std::list 245 Inserting and Deleting in std::list 247 Iterating in std::list 248 Sorting std::list 248 Lookup with std::list 249 std::forward_list 249 Inserting and Deleting in std::forward_list 250 Iterating in std::forward_list 251 Sorting std::forward_list 251 Lookup in std::forward_list 251 std::map and std::multimap 251 Inserting and Deleting in std::map 252 Iterating in std::map 255 Sorting std::map 255 Lookup with std::map 255 std::set and std::multiset 255 std::unordered_map and std::unordered_multimap 256 Inserting and Deleting in std::unordered_map 260 Iterating in std::unordered_map 260 Lookup with std::unordered_map 261 Other Data Structures 261 Summary 263 11. 265 A Recipe for Reading Files 265 Create a Parsimonious Function Signature 267 Shorten Calling Chains 269 Reduce Reallocation 269 Take Bigger Bites—Use a Bigger Input Buffer 272 Take Bigger Bites—Read a Line at a Time 272 Shorten Calling Chains Again 274 Things That Didn’t Help 275 Writing Files 276 Reading from std::cin and Writing to std::cout 277 Summary 278 12. 279 Concurrency Refresher 280 A Walk Through the Concurrency Zoo 281 Table of Contents | xi Interleaved Execution 285 Sequential Consistency 286 Races 287 Synchronization 288 Atomicity 289 C++ Concurrency Facilities Refresher 291 Threads 291 Promises and Futures 292 Asynchronous Tasks 295 Mutexes 296 Locks 297 Condition Variables 298 Atomic Operations on Shared Variables 301 On Deck: Future C++ Concurrency Features 304 Optimize Threaded C++ Programs 305 Prefer std::async to std::thread 306 Create as Many Runnable Threads as Cores 308 Implement a Task Queue and Thread Pool 309 Perform I/O in a Separate Thread 310 Program Without Synchronization 310 Remove Code from Startup and Shutdown 313 Make Synchronization More Efficient 314 Reduce the Scope of Critical Sections 314 Limit the Number of Concurrent Threads 315 Avoid the Thundering Herd 316 Avoid Lock Convoys 317 Reduce Contention 317 Don’t Busy-Wait on a Single-Core System 319 Don’t Wait Forever 319 Rolling Your Own Mutex May Be Ineffective 319 Limit Producer Output Queue Length 320 Concurrency Libraries 320 Summary 322 13. Optimize Memory Management.

Nội dung được bảo vệ bản quyền — Tải xuống đầy đủ