Parallel Programming with C# and .NET Fundamentals of Concurrency and Asynchrony Behind Fast-Paced Applications — Vaskaran Sarcar Foreword by Naga Santhosh Reddy Vootukuri
Parallel Programming with C# and .NET Fundamentals of Concurrency and Asynchrony Behind Fast-Paced Applications Vaskaran Sarcar Foreword by Naga Santhosh Reddy Vootukuri
Parallel Programming with C# and .NET: Fundamentals of Concurrency and Asynchrony Behind Fast-Paced Applications ISBN-13 (pbk): 979-8-8688-0487-8 ISBN-13 (electronic): 979-8-8688-0488-5 https://doi.org/10.1007/979-8-8688-0488-5 Copyright © 2024 by Vaskaran Sarcar This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation, broadcasting, reproduction on microfilms or in any other physical way, and transmission or information storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now known or hereafter developed. Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark. The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to proprietary rights. While the advice and information in this book are believed to be true and accurate at the date of publication, neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or omissions that may be made. The publisher makes no warranty, express or implied, with respect to the material contained herein. Managing Director, Apress Media LLC: Welmoed Spahr Acquisitions Editor: Smriti Srivastava Development Editor: Laura Berendson Coordinating Editor: Kripa Joseph Cover designed by eStudioCalamar Cover image designed by Freepik (www.freepik.com) Distributed to the book trade worldwide by Apress Media, LLC, 1 New York Plaza, New York, NY 10004, U.S.A. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail orders-ny@springer-sbm.com, or visit www.springeronline.com. Apress Media, LLC is a California LLC and the sole member (owner) is Springer Science + Business Media Finance Inc (SSBM Finance Inc). SSBM Finance Inc is a Delaware corporation. For information on translations, please e-mail booktranslations@springernature.com; for reprint, paperback, or audio rights, please e-mail bookpermissions@springernature.com. Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook versions and licenses are also available for most titles. For more information, reference our Print and eBook Bulk Sales web page at http://www.apress.com/bulk-sales. Any source code or other supplementary material referenced by the author in this book is available to readers on GitHub (https://github.com/Apress/Parallel-Programming-with-CSharp- and-.NET). For more detailed information, please visit https://www.apress.com/gp/services/ source-code. If disposing of this product, please recycle the paper Vaskaran Sarcar Near Garia Station, Post: Garia Kuntala Furniture, 2nd Floor Kolkata, West Bengal, India
To those who are often labeled as “workaholics,” “introverted,” or “antisocial,” only because they forget the world while coding.
v Table of Contents About the Author ���������������������������������������������������������������������������������xi About the Technical Reviewer �����������������������������������������������������������xiii Acknowledgments ������������������������������������������������������������������������������xv Foreword ������������������������������������������������������������������������������������������xvii Introduction ���������������������������������������������������������������������������������������xix Chapter 1: Understanding Tasks �����������������������������������������������������������1 Stepping into Parallel Development ����������������������������������������������������������������������1 Introduction to the Task Parallel Library ���������������������������������������������������������������3 How Does the TPL Help?����������������������������������������������������������������������������������4 The Concept of Tasks ��������������������������������������������������������������������������������������������4 Creating and Executing a Task ������������������������������������������������������������������������5 Passing and Returning Values �����������������������������������������������������������������������14 Continuation Tasks ����������������������������������������������������������������������������������������������20 Simple Continuation ��������������������������������������������������������������������������������������21 Specialized Continuation �������������������������������������������������������������������������������23 Nested Tasks �������������������������������������������������������������������������������������������������������29 Using TaskCreationOptions ����������������������������������������������������������������������������31 Using TaskContinuationOptions ���������������������������������������������������������������������33 Discussion of Waiting ������������������������������������������������������������������������������������������42 Why Do We Wait? �������������������������������������������������������������������������������������������43 How Do We Wait?�������������������������������������������������������������������������������������������44
vi Exercises �������������������������������������������������������������������������������������������������������������57 Summary�������������������������������������������������������������������������������������������������������������61 Solutions to Exercises �����������������������������������������������������������������������������������������61 Chapter 2: Handling Special Scenarios ����������������������������������������������71 Introduction to Exceptions ����������������������������������������������������������������������������������71 Understanding the Challenge ������������������������������������������������������������������������71 Retrieving the Error Details ���������������������������������������������������������������������������76 Exception Management ���������������������������������������������������������������������������������80 Final Suggestion ��������������������������������������������������������������������������������������������91 Understanding Cancellations ������������������������������������������������������������������������������91 Different Ways of Cancellation ����������������������������������������������������������������������92 Monitoring Task Cancellation ����������������������������������������������������������������������103 Cancelling Child Tasks ���������������������������������������������������������������������������������107 Managing Multiple Cancellation Tokens ������������������������������������������������������107 Organizing Exceptions and Cancellations ���������������������������������������������������������112 Case Study 1: Using Wait() ���������������������������������������������������������������������������112 Case Study 2: Using Wait(token) ������������������������������������������������������������������115 Handling I/O-Bound Tasks ���������������������������������������������������������������������������������117 Using TaskCompletionSource ����������������������������������������������������������������������118 Exercises �����������������������������������������������������������������������������������������������������������125 Summary�����������������������������������������������������������������������������������������������������������136 Solutions to Exercises ���������������������������������������������������������������������������������������136 Chapter 3: Exploring Synchronization and Concurrent Collections ����������������������������������������������������������������������������������������143 Synchronization ������������������������������������������������������������������������������������������������143 Understanding Why We Need Synchronization ��������������������������������������������145 Using Lock Statements ��������������������������������������������������������������������������������148 Table of ConTenTs
vii Using Interlocked Classes ���������������������������������������������������������������������������150 Signaling Using AutoResetEvent ������������������������������������������������������������������154 Concurrent Collections ��������������������������������������������������������������������������������������162 System�Collections�Concurrent Namespace ������������������������������������������������162 IProducerConsumerCollection<T> Interface �����������������������������������������������163 Notable Characteristics �������������������������������������������������������������������������������168 ConcurrentStack<T> �����������������������������������������������������������������������������������172 ConcurrentQueue<T> ����������������������������������������������������������������������������������182 ConcurrentBag<T> ��������������������������������������������������������������������������������������185 BlockingCollection<T> ��������������������������������������������������������������������������������194 Note from Microsoft�������������������������������������������������������������������������������������201 ConcurrentDictionary<TKey,TValue> ����������������������������������������������������������201 Exercises �����������������������������������������������������������������������������������������������������������210 Summary�����������������������������������������������������������������������������������������������������������213 Solutions to Exercises ���������������������������������������������������������������������������������������214 Chapter 4: Working on Parallel Loops ����������������������������������������������219 Revisiting Sequential Loops ������������������������������������������������������������������������������219 Experimenting with Parallel Loops��������������������������������������������������������������������220 Introducing the Parallel Class ����������������������������������������������������������������������221 Parallel�ForEach �������������������������������������������������������������������������������������������222 Parallel�For ��������������������������������������������������������������������������������������������������223 Parallel�Invoke ���������������������������������������������������������������������������������������������226 Scenarios for Parallel Execution �����������������������������������������������������������������������230 Case Study 1 ������������������������������������������������������������������������������������������������231 Case Study 2 ������������������������������������������������������������������������������������������������232 Analysis �������������������������������������������������������������������������������������������������������234 Table of ConTenTs
viii Useful Parameters ��������������������������������������������������������������������������������������������234 Using ParallelLoopState�������������������������������������������������������������������������������235 Using ParallelOptions ����������������������������������������������������������������������������������241 Managing Cancellations ������������������������������������������������������������������������������������245 Following the Previous Approach ����������������������������������������������������������������245 Recommended Approach ����������������������������������������������������������������������������246 Handling Exceptions �����������������������������������������������������������������������������������������250 Fine-Tuning �������������������������������������������������������������������������������������������������������254 Using Thread-Local Variables ����������������������������������������������������������������������256 Using Partition-Local Variables ��������������������������������������������������������������������260 Additional Note ��������������������������������������������������������������������������������������������260 Reviewing Different Coding Styles ��������������������������������������������������������������������265 Introducing the ParallelEnumerable Class ���������������������������������������������������266 Exercises �����������������������������������������������������������������������������������������������������������267 Summary�����������������������������������������������������������������������������������������������������������271 Solutions to Exercises ���������������������������������������������������������������������������������������272 Chapter 5: Parallel LINQ ��������������������������������������������������������������������279 Prerequisite Knowledge ������������������������������������������������������������������������������������279 Imperative vs� Declarative Programming ����������������������������������������������������279 PLINQ Supports Declarative Programming ��������������������������������������������������280 Understanding LINQ Is Beneficial ����������������������������������������������������������������281 The Path Toward Parallelism �����������������������������������������������������������������������������281 Converting LINQ into PLINQ Using AsParallel�����������������������������������������������282 Using the ParallelEnumerable Class ������������������������������������������������������������283 Introducing ForAll ����������������������������������������������������������������������������������������284 Table of ConTenTs
ix Getting Familiar with PLINQ ������������������������������������������������������������������������������286 The First Program ����������������������������������������������������������������������������������������286 Do Parallel Queries Run Faster Than Sequential Queries? ��������������������������291 Forcing Parallelism and Controlling the Degree ������������������������������������������298 Merging Data ����������������������������������������������������������������������������������������������������300 Merge Options ���������������������������������������������������������������������������������������������300 Managing Special Scenarios �����������������������������������������������������������������������������306 Handling Exceptions ������������������������������������������������������������������������������������306 Handling Cancellations ��������������������������������������������������������������������������������310 Exercising Aggregation �������������������������������������������������������������������������������������315 Sequential Custom Aggregation ������������������������������������������������������������������316 Parallel Custom Aggregation �����������������������������������������������������������������������318 Exercises �����������������������������������������������������������������������������������������������������������322 Summary�����������������������������������������������������������������������������������������������������������325 Solutions to Exercises ���������������������������������������������������������������������������������������326 Chapter 6: Simplifying Asynchronous Programming �����������������������333 Introduction to async and await ������������������������������������������������������������������������334 Understanding async �����������������������������������������������������������������������������������335 Understanding await �����������������������������������������������������������������������������������339 State Machines Are Behind the Scenes �������������������������������������������������������349 Task�Run vs� Task�Factory�StartNew �����������������������������������������������������������������359 Task�Factory�StartNew Treats Ordinary Lambdas and Asynchronous Lambdas Differently ������������������������������������������������������������������������������������360 Task�Run Treats Ordinary Lambdas and Asynchronous Lambdas Uniformly �����������������������������������������������������������������������������������������������������361 Unwrapping Using the Unwrap Method �������������������������������������������������������362 Unwrapping Using await������������������������������������������������������������������������������362 Table of ConTenTs
x Asynchronous Construction ������������������������������������������������������������������������������363 Approach 1 ��������������������������������������������������������������������������������������������������366 Approach 2 ��������������������������������������������������������������������������������������������������368 Approach 3 (Using a Static Method aka Factory) ����������������������������������������372 Approach 4 (Lazy Initialization)��������������������������������������������������������������������375 Introducing ValueTasks �������������������������������������������������������������������������������������383 Consuming ValueTasks ��������������������������������������������������������������������������������384 Reviewing Exceptions ���������������������������������������������������������������������������������������387 Exercises �����������������������������������������������������������������������������������������������������������390 Summary�����������������������������������������������������������������������������������������������������������393 Solutions to Exercises ���������������������������������������������������������������������������������������394 Appendix A: Supplementary Notes ���������������������������������������������������403 Appendix B: Recommended Reading ������������������������������������������������443 Appendix C: Other Books by the Author �������������������������������������������445 Index �������������������������������������������������������������������������������������������������447 Table of ConTenTs
xi Vaskaran Sarcar obtained his master’s of engineering from Jadavpur University, Kolkata (India), and his master’s of computer applications from Vidyasagar University, Midnapore (India). He was a National Gate Scholar (2007–2009) and has more than 12 years of experience in education and the IT industry. He devoted his early years (2005–2007) to the teaching profession at various engineering colleges, and later he joined HP India PPS R&D Hub in Bangalore. He worked there for more than 10 years and became a senior software engineer and team lead. After that, he decided to follow his passion and is now an independent full-time author. You can find his books at https://amazon.com/author/ vaskaran_sarcar and find him on LinkedIn at www.linkedin.com/in/ vaskaransarcar. About the Author
xiii Naga Santhosh Reddy Vootukuri is a senior software engineering manager at Microsoft, specializing in cloud computing and artificial intelligence. With a distinguished career spanning 16 years across India, China, and the United States, Naga has amassed a wealth of experience in distributed systems, microservices, and large-scale infrastructure management building cloud and intelligent systems. At Microsoft, Naga leads the Azure SQL Database team, driving initiatives to optimize SQL deployment processes for millions of databases worldwide. His leadership was pivotal in the development of Master Data Services (MDS), a critical component of Microsoft’s SQL enterprise solutions, which saw a significant increase in customer adoption under his stewardship. Naga has authored and published numerous research articles in peer- reviewed and indexed journals. He is a senior member of IEEE, teaches workshops on AI, and writes technical articles as a Core MVB member at DZone, engaging with millions of active readers. You can read his articles at https://dzone.com/authors/sunnynagavo. He also serves as an editorial board member for a highly reputed science journal (SCI), where he reviews research articles on cloud computing and AI, further solidifying his influence in the academic and professional spheres. About the Technical Reviewer
xiv Beyond his corporate roles, Naga actively contributes to the tech community by speaking at events, reviewing books for Apress, and actively helping people in forums like the Microsoft Tech Community. His commitment to advancing technology is underscored by his recent role as a judge for the Globee Awards, where he evaluated and recognized innovations in the industry. He also served as a judge for the Microsoft AI hackathon, with more than 10,000 developers participating. Throughout his career, Naga has demonstrated exceptional leadership and technical prowess, evident in his mentorship on ADP List and his key role in conducting more than 100+ interviews to recruit top talent for Microsoft. You can contact him at https://adplist.org/mentors/sunny. In summary, Naga embodies a blend of technical expertise, leadership excellence, and community engagement, making profound contributions to both Microsoft and the broader tech industry. His dedication to innovation and mentorship continues to inspire professionals and shape the future of technology globally. abouT The TeChniCal RevieweR
xv Acknowledgments First, I thank the Almighty. I sincerely believe that with His blessings only I could complete this book. I also extend my deepest gratitude and thanks to the following: • Naga Santhosh Reddy Vootukuri: He is the technical reviewer of this book, located in a different country, and works in a different time zone. Despite these factors, whenever I was in need, he provided support. He answered all my queries through phone calls, WhatsApp, and emails. Thank you one more time. • Smriti, Laura, Celestin, and the Apress team: I sincerely thank each of you for giving me another opportunity to work with you and with Apress. • Nirmal, Kim Wimpsett, Selvakumar and Pushparaj: Thanks to each of you for your exceptional support in beautifying my work. Your efforts are extraordinary. Finally, I thank those people from the online C# developer community, .NET developer community, and Stack Overflow community who have shared their knowledge in various forms. In fact, I thank everyone who directly or indirectly contributed to this work.
xvii Foreword Mastering a programming language is much like an artist perfecting their craft; it demands dedication, practice, and the right tools. In the realm of modern computing, where efficiency and speed are paramount, parallel programming stands as a cornerstone. In fact, parallel programming is like conducting an orchestra—each thread must play its part perfectly, or you end up with chaos instead of harmony. This book, Parallel Programming with C# and .NET, is an indispensable guide for anyone looking to harness the full power of parallel computing, ensuring their applications are both fast and scalable. Vaskaran Sarcar, an esteemed author, is known for his ability to explain complex ideas clearly. He is passionate, well-informed, skilled, and very knowledgeable in this area. His systematic approach and curiosity have earned him respect in the programming community. I’ve seen Vaskaran tackle tough problems with focused determination, consistently finding elegant solutions that showcase his analytical skills and dedication. Parallel Programming with C# and .NET focuses sharply on the complex world of parallel computing. Each chapter breaks down different techniques step-by-step, starting with basic concepts explained in a simple manner. It includes practical sample programs and quizzes to reinforce your understanding. This structured approach simplifies learning and ensures you can apply these concepts effectively. This pedagogical style ensures that readers not only grasp fundamental concepts but also retain them effectively.
xviii In today’s tech landscape, performance and efficiency are crucial. C# has grown beyond its Windows origins, now used in diverse environments like Mac and Linux, thanks to Microsoft’s open-source culture. This book provides advanced knowledge to help developers fully utilize C#’s capabilities, crafting efficient solutions optimized for various platforms. I am confident that Parallel Programming with C# and .NET will accelerate many developers’ learning so they become proficient in parallel computing in record time. Vaskaran’s exemplary work establishes a solid foundation for understanding and utilizing advanced language features, paving the way for creating robust software. Developers will gain clarity on complex concepts and rely on this book as their essential resource for mastering parallel computing challenges. Happy coding! Naga Santhosh Reddy Vootukuri Senior Software Engineering Manager Microsoft, Azure SQL Server (Cloud + AI division) foRewoRd
xix Introduction Modern-day software is highly responsive and scalable. As a result, support for parallel computation is an essential part of it. Undoubtedly this is an advanced concept, and the solutions are not straightforward. Many developers have been burned (and are still burning) by them. In addition, parallel programming is a vast topic that requires many different considerations. You may also note that many patterns used in the past to deal with asynchronous and parallel programming are not recommended now. This book tries to simplify the concept using modern C# features and libraries that Microsoft recommends. Welcome to your journey through Parallel Programming with C# and .NET: Fundamentals of the Concurrency and Asynchrony Behind Fast-Paced Applications. C# is a powerful programming language, well-accepted in the programming world, that can help you make a wide range of applications. Throughout C# development, supportive features and libraries have been developed to support parallel programming. This is one of the primary reasons that it is continuously growing and always in high demand. So, it is not a surprise that existing and upcoming developers (for example, college students and programming lovers) want to use C# for parallel programming. Many developers try to learn parallel programming in the shortest possible time frame. Trying to learn something as quickly as possible is laudable, but do you know the problem? We are living in a world that offers you lots of materials, advertisements, and quick fixes to capture your attention. We human beings love to daydream. So, they take advantage of this behavior and start claiming that you can learn everything in a day, a week, or a month. Is this true? Ask yourself and you’ll get the answer.
xx Malcolm Gladwell in his book Outliers (Little, Brown, and Company) talked about the 10,000-hour rule. This rule says that the key to achieving world-class expertise in any skill is, to a large extent, a matter of practicing the correct way for a total of about 10,000 hours. So, you can probably see that even though we may claim that we know something very well, we actually probably know very little. Learning is a continuous process, with no end. Then should we stop learning? Definitely, the answer is no. What should we do then? We can follow an effective learning process that teaches you how to learn quickly to serve the need. This is where I like to remind you about the Pareto principle, or 80-20 rule. This rule simply states that 80% of outcomes come from 20% of all causes. This is useful in programming too. When you truly learn the fundamental and most important aspects of parallel programming, that is when you can use it effectively to improve your code. Most importantly, your confidence level will rise, and you won’t be afraid to experiment more. This book is for those who acknowledge these facts. How Is the Book Organized? This book helps you to understand the core principles of parallel programming using six chapters with plenty of supportive materials. To give you an idea how each chapter is organized, the following list talks about the contents of the book: • Chapter 1 starts with an overview of the Task Parallel Library (TPL) and discusses tasks. These topics are the foundation for the upcoming chapters. Chapter 2 discusses special scenarios such as handling exceptions and cancellations. Chapter 3 discusses synchronization techniques and concurrent collections. Chapter 4 discusses the Parallel class, which helps you experiment with parallel loops to speed up inTRoduCTion
xxi computations. Chapter 5 discusses Parallel LINQ (PLINQ). Chapter 6 discusses simplifying asynchronous programming using the async and await keywords. Finally, the appendix provides you with some extra materials that are not discussed in the previous chapters. • I have always enjoyed learning when analyzing case studies, asking questions, and performing exercises. So, throughout this book, you will see interesting program code, “Q&A Sessions,” and exercises. By analyzing these Q&As and doing the exercises, you can verify your progress. As mentioned, these are presented to make your learning easier and more enjoyable, but most importantly, they will make you confident as a developer. • Each question in these “Q&A Sessions” is marked with Q<chapter#>.<question#>. For example, Q5.3 means question 3 from Chapter 5. At the end of the chapter, you’ll see some exercises. You can use them to evaluate your progress. Each question in these exercises is marked with E<chapter#>.<question#>. For example, E6.2 means exercise 2 from Chapter 6. • You can download all the source code for the book from the publisher’s website. Prerequisite Knowledge I expect you to be very familiar with C#. In fact, knowing about some of the advanced concepts like delegates and lambda expressions can accelerate your learning. So, I assume that you know how to compile or run a C# application in Visual Studio. This book does not invest time in basic inTRoduCTion
xxii topics, such as how to install Visual Studio on your system, how to write a “Hello World” program in C#, and so forth. In short, the target readers of this book are those who want to make the most of C# by harnessing the power of both object-oriented programming (OOP) and functional programming (FP). Who This Book Is For You will get the most from this book if you can answer “yes” to the following questions: • Are you familiar with .NET, C#, and basic object- oriented concepts such as polymorphism, inheritance, abstraction, and encapsulation? • Are you familiar with some of the advanced concepts in C# such as delegates, lambda expressions, and generics? • Do you know how to set up your coding environment? • Are you interested in knowing how the modern-day constructs of C# can help you in parallel programming? You will probably struggle with this book if you can answer “yes” to any of the following questions: • Are you looking for a C# tutorial or reference book? • Are you not ready to experiment with parallel programming using a programming language other than C#? • Do you dislike Windows, Visual Studio, and/or .NET or want to learn parallel programming without them? inTRoduCTion
Loading comments...
Reply to Comment
Edit Comment