Dot Net Tutorials

How to Execute Multiple Tasks in C#

Back to: C#.NET Tutorials For Beginners and Professionals

In this article, I will discuss How to Execute Multiple Tasks in C# using the WhenAll Method with Examples. Please read our previous article, which discusses How to Return a Value from a Task in C# with Examples.

How to Execute Multiple Tasks in C#?

So far, we have been executing one task at a time, but we sometimes have many tasks we want to execute simultaneously. We can do that with Task.WhenAll method. With Task.WhenAll method, we can have a list of tasks, and all the tasks will be executed concurrently. When all of the tasks are finished, we will be able to continue the execution of a method.

Example to Understand Task.WhenAll Method:

Let us understand how to execute multiple tasks concurrently using the Task.WhenAll method in C#. We will do an example where we want to process multiple credit cards. 

We are going to use the following CreditCard class in our example. The following CreditCard class has two properties, i.e., CardNumber and Name, and one static method, i.e., GenerateCreditCards, to generate a collection of CreditCard. The GenerateCreditCards method takes one integer number as a parameter and then creates a collection of that many numbers of credit cards and returns that collection.

Next, we need to create one async method to process the credit cards. For this, we are creating the following ProcessCard Async method. This method takes the CreditCard as an input parameter and processes that credit card. Here, you can make any API call to process the Credit Card. But for simplicity, we just delay the execution for 1 second using the Task.Delay Asynchronous Method and then print the message that the credit is processed and return a string containing the processed credit card information for future use if required.

Next, we are creating another asynchronous method to execute multiple tasks concurrently. For this purpose, we are creating the following ProcessCreditCards async method. This method takes the collection of cards that we want to be processed. Then, the ForEach loop processes the cards individually by calling the ProcessCard async method. While calling the ProcessCard async method, we are not using the await operator. The return type of ProcessCard is Task<string>. So here, I have created a collection of type Task<string>, i.e., List< Task<string>> tasks , to store the response coming from the ProcessCard method. Next, we call the Task.WhenAll method by passing that Task<string> collection. To check the time, here we use a stopwatch showing the time the WhenAll method takes to process all the credit cards.

Please note the following statement:

  • await Task.WhenAll(tasks): This statement tells that there is a list of tasks. Please wait for all of the tasks to be done before continuing with the execution of this method, and all of the tasks will be run simultaneously. As tasks contain 10 entries, all these 10 tasks are to be executed simultaneously.

Next, Modify the Main method as follows. From the main method, we call the static GenerateCreditCards method of the CreditCard class by passing an integer number, i.e., 10, as an argument. This GenerateCreditCards method will return a collection of 10 Credit Cards. And then, we are calling the ProcessCreditCards by passing that credit card collection as an argument.

Complete Example code:

Whatever we discussed as of now, everything is put in the below example.

How to Execute Multiple Tasks using the WhenAll Method in C# with Examples

You can see it is taking little more than 1 second to process all the Credit Cards. One more point: when we are executing multiple tasks concurrently, you can never predict the order of execution. Now, let us observe the output. If you remember, within the ProcessCard method, we delayed the execution for one second. But after that, as we execute multiple tasks using Task.WhenAll method, all the tasks execution is completed within little more than 1 second. This is because of Task.WhenAll method executes all the tasks concurrently, drastically improving our application’s performance.

Execution without Task.WhenAll Method in C#:

Now, let us execute the same application without using Task.WhenAll and observe how long it takes to process 10 credit cards. Please modify the ProcessCreditCards method as follows. Here, we remove the Task.WhenAll method and its related code. Here, we are using the await operator.

With the above changes in place, run the application and observe the output shown in the image below.

Execution without Task.WhenAll Method in C#

It takes more than 10 seconds to process 10 credit cards compared to a little more than 1 second when using Task.WhenAll Method in C#. Now, I hope you understand when and how to use Task.WhenAll in C#.

Offloading the Current Thread – Task.Run Method in C#

Let us understand what you mean by Offloading the Current Thread in C# with an Example. Let us modify the example as follows. Now, we are trying to process 100000 credit cards. In the example below, we removed the statement that prints the credit card details on the console. Further, we have used a stopwatch to check how long the main thread takes.

Offloading the Current Thread - Task.Run Method in C#

You can see the Main thread taking approximately 9 seconds. Let us observe why. Please have a look at the below image. The following for each loop of our ProcessCreditCards method runs 100000 times, which will take some time, approximately 9 seconds. So, until the await Task.WhenAll(tasks) statement is called, our Main thread is frozen. As soon as we call, await Task.WhenAll(tasks) method, the thread is active and starts processing.

How to Execute Multiple Tasks using the WhenAll Method in C# with Examples

We don’t want our Main thread to freeze for 9 seconds because one of the main reasons to use asynchronous programming in C# is to have a responsive UI. So, we don’t want the UI or Main thread to be frozen.

How do we overcome the above problem?

In any way, we need to make the Main Thread available. For that, we can offload each loop to another thread using the Task.Run Asynchronous Method in C#. Let us see how. Please have a look at the below image. We need to use Task.Run method and using a delegate, we need to use the for each loop, further as Task.Run method is an asynchronous method, so we need to use the await operator, as shown in the image below.

How to Execute Multiple Tasks using the WhenAll Method in C# with Examples

With the above changes, the for-each loop will be executed by another thread, and as we use the await method before Task.Run so the main thread will be free and continue its execution. The complete example code is given below.

With the above changes in place, now run the application and observe the output shown in the image below. Now, the main thread is not frozen and is completed in milliseconds.

Task.Run method in C# with Examples

WhenAll Methods of Task Class in C#:

If you go to the definition of Task class, you will see four overloaded versions of this method available. They are as follows:

  • WhenAll(IEnumerable<Task> tasks): It Creates a task that will be completed when all of the Task objects in an enumerable collection have been completed. Here, the parameter tasks specify the tasks to wait on for completion. It returns a task that represents the completion of all supplied tasks.
  • WhenAll<TResult>(params Task<TResult>[] tasks): It creates a task that will be completed when all of the Task objects in an array have been completed. Here, the parameter tasks specify the tasks to wait on for completion. The Type parameter TResult specifies the type of the completed task. It returns a task that represents the completion of all supplied tasks.
  • WhenAll<TResult>(IEnumerable<Task<TResult>> tasks): It creates a task that will be completed when all of the Task objects in an enumerable collection have been completed. Here, the parameter tasks specify the tasks to wait on for completion. The Type parameter TResult specifies the type of the completed task. It returns a task that represents the completion of all supplied tasks.
  • WhenAll(params Task[] tasks): It creates a task that will be completed when all Task objects in an array have been completed. Here, the parameter tasks specify the tasks to wait on for completion. It returns a task that represents the completion of all supplied tasks.

In the next article, I will discuss Limiting the Number of Concurrent Tasks in C# with Examples. In this article, I explain How to Execute Multiple Tasks using the WhenAll Method in C# with Examples. I hope you enjoy this How to Execute Multiple Tasks using Task.WhenAll Method in C# article.

dotnettutorials 1280x720

About the Author: Pranaya Rout

Pranaya Rout has published more than 3,000 articles in his 11-year career. Pranaya Rout has very good experience with Microsoft Technologies, Including C#, VB, ASP.NET MVC, ASP.NET Web API, EF, EF Core, ADO.NET, LINQ, SQL Server, MYSQL, Oracle, ASP.NET Core, Cloud Computing, Microservices, Design Patterns and still learning new technologies.

2 thoughts on “How to Execute Multiple Tasks in C#”

task whenall method

Guys, Please give your valuable feedback. And also, give your suggestions about this How to Execute Multiple Tasks in C# concept. If you have any better examples, you can also put them in the comment section. If you have any key points related to How to Execute Multiple Tasks in C#, you can also share the same.

task whenall method

pls where is my last comment i summitted days before

pls where my last comment . does received yet ?

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Home » C# Concurrency » C# WhenAll

Summary : in this tutorial, you’ll learn how to use the C# WhenAll() static method of the Task class to create a task that will complete when all the input tasks are completed.

Introduction to the C# WhenAll() static method

The Task.WhenAll () method creates a task that will complete once all the input tasks are completed. The method returns a Task object that represents the completion of all the input tasks. The returned task contains the results of all the input tasks.

In practice, the Task.WhenAll () is useful for aggregating results from multiple asynchronous operations.

The following program demonstrates the Task.WhenAll () method:

How it works.

First, define a method called DoWork() that accepts an integer parameter taskId . The method displays a message indicating that the task has started, and delays for a specified number of seconds using the Task.Delay () method, and displays another message showing that the task has finished and returns the square of the taskId :

Since the method has an asynchronous operation, it is marked as an async method. Hence, it returns a Task<int> object rather than an integer.

Second, create three tasks using the Task.Run () method that executes the DoWork() method on background threads:

Third, use the Task.WhenAll () method to wait for three tasks to complete. The method returns an array of integers stored in the results variable:

Finally, show the results to the console:

Waiting for multiple HTTP requests to complete using Task.WhenAll() method

The following example shows how to use the Task.WhenAll () and HttpClient to fetch contents asynchronously from multiple URLs and calculate the total bytes:

First, define the Fetch() method that takes a string argument url and returns a Task<int> object:

The Fetch() method uses the HttpClient object to fetch the contents of the input url asynchronously. Once it completes downloading the contents of the URL, it gets the size of the contents in bytes. and return it as the integer value wrapped in a Task object.

Second, create three tasks using the Task.Run method to execute the Fetch() method asynchronously:

Third, wait for all three tasks to complete using the Task.WhenAll () method and return an array of their results as Task<int[]> object:

Finally, calculate the total size of the fetched contents by adding up the size of the content of each task using the Sum() extension method and display the result:

  • Use the Task.WhenAll () method to create a task that will complete once all the input tasks have finished.

DEV Community

DEV Community

Theodore Karropoulos

Posted on Jan 2, 2023

Understanding Task.WhenAll in C#

The Task.WhenAll method in C# allows you to create a task that is completed when a group of other tasks have finished executing. This can be useful when you want to wait for multiple tasks to complete before moving on to other parts of your code.

To use Task.WhenAll , you can pass it a list of tasks that you want to wait for. For example:

In this code, task1 , task2 , and task3 are tasks that return strings. Task.WhenAll creates a new task that is completed when all of these tasks have finished. The await operator is used to wait for the allTasks task to complete, and the results of the individual tasks are stored in an array.

There are several benefits to using Task.WhenAll :

  • It allows you to easily wait for multiple tasks to complete before moving on to other parts of your code.
  • It can improve the performance of your application by allowing you to take advantage of parallelism. If you have multiple independent tasks that can be run at the same time, Task.WhenAll can help you do this.

However, there are also some potential drawbacks to Task.WhenAll :

  • If one of the tasks passed to it throws an exception, the exception will be wrapped in an AggregateException and thrown when you call await on the returned task. This can make it harder to handle exceptions from individual tasks.
  • It can make your code harder to debug because it can be more difficult to understand what is happening when multiple tasks are running concurrently.

Internally, Task.WhenAll works by creating a new task that is set up to be completed when all of the provided tasks have finished. This new task is returned to the caller. The .NET Framework includes a thread pool, which is a collection of worker threads that are used to execute tasks asynchronously. When you call Task.WhenAll , the tasks you pass to it are scheduled to run on the thread pool.

As each task finishes, it signals the new task created by Task.WhenAll that it has completed. When all of the tasks have finished, the new task is marked as completed, and any code waiting on the task (using the await operator, for example) can continue execution.

Using Task.WhenAll , you can take advantage of parallelism when it is available, which can improve the performance of your application.

Top comments (0)

pic

Templates let you quickly answer FAQs or store snippets for re-use.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .

Hide child comments as well

For further actions, you may consider blocking this person and/or reporting abuse

nandinishinduja profile image

Tech roles which are out there

Nandini S Hinduja - Feb 12

esdanielgomez profile image

Using Azure OpenAI Service to generate images with DALL-E in .NET

Daniel Gomez - Feb 1

r0mymendez profile image

Learning AWS S3 on Localhost: Best Practices with Boto3 and LocalStack

Romi Mendez - Feb 12

brightball profile image

Call for Speakers for the 2024 Carolina Code Conference is open until April 15th

Barry Jones - Jan 9

Once suspended, tkarropoulos will not be able to comment or publish posts until their suspension is removed.

Once unsuspended, tkarropoulos will be able to comment and publish posts again.

Once unpublished, all posts by tkarropoulos will become hidden and only accessible to themselves.

If tkarropoulos is not suspended, they can still re-publish their posts from their dashboard.

Once unpublished, this post will become invisible to the public and only accessible to Theodore Karropoulos.

They can still re-publish the post if they are not suspended.

Thanks for keeping DEV Community safe. Here is what you can do to flag tkarropoulos:

tkarropoulos consistently posts content that violates DEV Community's code of conduct because it is harassing, offensive or spammy.

Unflagging tkarropoulos will restore default visibility to their posts.

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Code Maze

  • Blazor WASM 🔥
  • ASP.NET Core Series
  • GraphQL ASP.NET Core
  • ASP.NET Core MVC Series
  • Testing ASP.NET Core Applications
  • EF Core Series
  • HttpClient with ASP.NET Core
  • Azure with ASP.NET Core
  • ASP.NET Core Identity Series
  • IdentityServer4, OAuth, OIDC Series
  • Angular with ASP.NET Core Identity
  • Blazor WebAssembly
  • .NET Collections
  • SOLID Principles in C#
  • ASP.NET Core Web API Best Practices
  • Top REST API Best Practices
  • Angular Development Best Practices
  • 10 Things You Should Avoid in Your ASP.NET Core Controllers
  • C# Back to Basics
  • C# Intermediate
  • Design Patterns in C#
  • Sorting Algorithms in C#
  • Docker Series
  • Angular Series
  • Angular Material Series
  • HTTP Series
  • .NET/C# Author
  • .NET/C# Editor
  • Our Editors
  • Leave Us a Review
  • Code Maze Reviews

Select Page

How to Execute Multiple Tasks Asynchronously in C#

Posted by Code Maze | Updated Date Aug 17, 2022 | 4

How to Execute Multiple Tasks Asynchronously in C#

In this article, we are going to learn how to execute multiple tasks in C# in sequence and parallel. By using async/await , we avoid performance bottlenecks and enhance the scalability of our application. Depending on the business logic, we may need to execute functional tasks either sequentially, or in parallel.

Let’s dive into it.

Creating a Demo REST API

Let’s consider that we are developing an application for employee management in an organization. The client/UI application consumes a REST-based API that will return the employee details, salary, and appraisal rating for an employee from three different endpoints.

Here, we will use a simple ASP.NET Core Web API. The controller actions in this Web API return static data for this demo:

Now, let’s take a look at the three endpoints with their response in the swagger documentation for this Web API:

Become a patron at Patreon!

We have made the Web API simple on purpose as we don’t want to deviate from the topic of this article by diving into the intricate implementation details of an ASP.NET Core Web API.

Execute Multiple Tasks in Sequence using async and await

The client application has an EmployeeProfile class which we use as a presentation model to the end-user:

Here, we override the ToString() method to append all the employee data to a single string for printing it to the console.

Since this class acts like a view model, the properties of this class are constructed from the contract classes:

The Executor class in the client application consolidates employee data from all three REST API endpoints while constructing the EmployeeProfile instance:

Here, we are executing the tasks for fetching employee details, salary, and rating in sequence using asynchronous programming .

First, we are awaiting the Task instance returned by the GetEmployeeDetails() method. Then, we do the same with  GetEmployeeSalary() in the continuation of the GetEmployeeDetails() method. Finally, we repeat the action with the GetEmployeeRating() method in the continuation of the GetEmployeeSalary() method. Hence, in this case, each task execution step waits for the previous step to finish without blocking the thread.

In these three methods ( GetEmployeeDetails() , GetEmployeeSalary() , GetEmployeeRating() ) all we do is send a simple HTTP request and process the response . Also, we are simulating a network latency in all three methods using the Task.Delay() method. Such delay is very common in enterprise-grade applications due to factors like slow database calls, geographic factors, etc.

You can find the implementation inside the EmployeeApiFacade class in the client project.

Typically, we do such sequential execution in a workflow where each task execution step is dependent on the previous one, unlike the above steps. However, here we are anyway doing it to demonstrate in a later section the performance improvement that we can achieve by executing these tasks in parallel.

Let’s now run the client application:

We get back the consolidated result. Let’s now see if we can improve the performance of this functionality.

Execute Multiple Tasks in Parallel using Task.WhenAll

Since the tasks for fetching employee details, salary and rating are independent of each other, it is easy to execute them in parallel to improve the overall performance of the workflow:

Here, we are not awaiting the Task instances from any of the methods which means that these methods will now return the Task instances instead of the result and will execute in parallel. However, we need to wait for all three methods to complete their execution before the consolidation of the result. This is achieved by using the WhenAll method from Task Parallel Library.

The Task.WhenAll method creates a Task that will be complete when all the supplied tasks have been completed. Once all three Tasks are complete, we await the individual Task instances to derive the result from them.

Alternatively, we can use the Result property from the Task instances instead of awaiting them to avoid some unnecessary state of machine-generated code during compilation:

Though using blocking code like .Result is not considered good practice under normal circumstances, in this case, it is perfectly safe to use it as all the tasks have finished execution by the time this line is executed. In fact, in this case, it is more beneficial to use this approach as it reduces the size of the compiled code.

Now, when we execute the client code, we get back the consolidated result but with an increase in the overall performance.

Improving the Exception Handling in Task.WhenAll

Handling exceptions play a major part in real-life application development. There is a problem in the above implementation in regards to handling exceptions. Let’s consider a scenario where both GetEmployeeDetails() and GetEmployeeSalary() methods throw exceptions:

In this case, we are only getting the first exception in the console and ignoring the other exception.

So, if other Task instances throw any exceptions, we will never know about it. If we want to get hold of all the exceptions for logging purposes, we need to handle Task.WhenAll a bit differently:

This method extends the Task.WhenAll method to return a ValueTuple with the results of the tasks. Most importantly, it also handles the issue with multiple exceptions by catching and rethrowing an aggregate exception on all tasks that are awaited.

Now, we can invoke the WhenAll method from the TaskExtensions class instead of the original Task.WhenAll in the calling method:

If we execute the client code now, we can see an aggregate exception in the console showing both exceptions:

Performance Comparison async/await vs. Task.WhenAll 

To compare the performance between the two approaches, we have run a benchmark with the default target count:

The ExecuteInParallel() method that uses Task.WhenAll clearly exhibits better overall performance compared to the ExecuteInSequence() method.

Sequential Task Execution using async, await, and foreach Loop

Let’s consider another business workflow where we need to invoke the same REST API endpoint multiple times. For example, invoking the /details/{id} endpoint to fetch details for three different employees. Once again, depending on the business case, we may have to do this either sequentially or in parallel.

To execute the tasks sequentially, we can use a foreach loop:

Here, for each employee id, we call the GetEmployeeDetails() method that invokes the /details/{id} endpoint in the REST API. We await the Task instance returned from the GetEmployeeDetails() method and then write the employee details to the console:

We see that all the tasks are executed. However, these tasks of fetching employee details for multiple employees can very easily be executed in parallel as they are independent of each other. So, executing them in parallel will improve the performance. Let’s see how we can achieve such improvement.

Parallel Tasks Execution using Parallel.Foreach

The Parallel.ForEach method executes a foreach operation in which the iterations may run in parallel.

Let’s re-write the example from the previous section using Parallel.ForEach :

We set the MaxDegreeOfParallelism property to 3. This property limits the number of concurrent operations by the Parallel.ForEach loop to the set value. By default, ForEach will utilize as many threads as the underlying scheduler provides. But, we are limiting this for better utilization of CPU resources in this demo as we have only 3 independent tasks.

Parallel.ForEach does not support asynchronous delegates. So, we are blocking the thread that executes the GetEmployeeDetails() method till it produces a result.

In many cases, Parallel.ForEach can provide significant performance improvements over ordinary sequential loops. However, the work of parallelizing the loop introduces complexity that can lead to problems that we don’t encounter in sequential code. In certain cases, a parallel loop might run slower than its sequential equivalent.

It is better to keep in mind the below points before using the Parallel loops:

  • Parallel loops are designed for CPU-intensive operations. It’s not always the best solution for I/O-bound operations
  • Parallel loops are not appropriate for asynchronous code flow
  • The degree of parallelism is completely dependent on the number of cores and CPU specifications so performance can vary

In the previous code block, each thread runs the independent I/O operations because of the lack of async support in the Parallel.ForEach . This is a big issue considering scalability and has the potential for thread pool starvation in an ASP.NET web application.

However, starting from .NET 6 we can use the Parallel.ForEachAsync method which is async aware.

Parallel Tasks Execution using Parallel.ForeachAsync

The Parallel.ForEachAsync executes a foreach operation on an IEnumerable<T> in which iterations may run in parallel. However, unlike the Parallel.ForEach , it returns a Task instance that represents the entire for-each operation. It also supports an async delegate. This was introduced recently as part of .NET 6.0

Now, let’s re-write the example from the previous section using Parallel.ForEachAsync :

Here, we set the MaxDegreeOfParallelism property to 3 like in the previous section for better optimization of CPU resources.

Now, on executing the client code, we see that the tasks are executed and  it  is approximately similar to the timing that we got using the Parallel.ForEach . 

Performance Comparison foreach vs. Parallel.ForEach vs. Parallel.ForEachAsync

Here also, we have run a benchmark with the default target count:

So, the Parallel.ForEach and the Parallel.ForEachAsync approaches perform better than the normal foreach . We see that there is not much difference in terms of execution time between the Parallel.ForEach and the Parallel.ForEachAsync . However, the scalability of Parallel.ForEachAsync is much higher considering that it is not blocking the individual threads anymore during the I/O operations. Hence, it minimizes the chances of thread pool starvation.

In this article, we have demonstrated a few scenarios where we may need to execute tasks in sequence and parallel. C# provides us with many approaches to achieve the same and we have covered most of them here. One must keep in mind the general pitfalls of asynchronous programming in C# while implementing such task execution.

guest

Hello, so far I use Task.WhenAll to execute multiple tasks like in the example you have given, but I want to use Parallel.ForeachAsync.

I have seen MaxDegreeOfParallelism you have set it to 3. is that because _employeeIds contains 3? If I had 20, would I have to put 20?

Chayan

The default MaxDegreeOfParallelism for the Parallel.ForEachAsync is equal to the Environment.ProcessorCount, and for all other Parallel methods(For and ForEach) it is equal to -1, which means unlimited parallelism.

The optimal value for the MaxDegreeOfParallelism for CPU-bound operations is Environment.ProcessorCount, although oversubscription might help if the workload is unbalanced.

The Parallel.ForEachAsync is used typically for I/O-bound asynchronous operations, where the sweet spot depends on the capabilities of the remote server or the bandwidth of the network. So in this case there is no rule of thumb, you will have to start with a number and fine-tune it depending on performance.

In this example, we have set the value to 3 simply as we wanted to make at max 3 parallel calls. So you can set it to 20 if your remote service and network can support such concurrent requests. But please also remember, when the CPU has to switch from one thread to another (context switch) it has a cost, so if you use too many threads and the CPU is switching all the time, you decrease the performance.

I am using it in a .NET MAUI application, where I always get a list of 20 elements, I am making a call to the google API. Thanks for the explanation. I don’t know what the correct value would be…

Dennis

Thank you for the extensive post and benchmarking. While I would write some of the code differently, I appreciate your work and different opinions! Justing starting out as a blogger, I recently posted an in-depth article on best practices in async-await in C#. Maybe you might want to have a go. Cheers,

wpdiscuz

Join our 20k+ community of experts and learn about our Top 16 Web API Best Practices .

Multithreading Made Easy: Exploring C# Task.WhenAll and Parallel.ForEach

Quick comparison of task.whenall and parallel.foreach in c#.

This table provides a concise overview of the key differences and purposes of C# Task.WhenAll and Parallel.ForEach.

Use it as a reference to choose the appropriate approach based on your specific requirements and the nature of your programming tasks.

Note : The "N/A" entries indicate that the specific feature is not applicable or relevant to the respective method.

Introduction

As a web developer, I understand the importance of efficient and responsive software applications. In today's world, where users demand faster and more interactive experiences, multithreading has become a crucial aspect of modern software development.

Multithreading allows us to execute multiple tasks concurrently, enabling better utilization of system resources and improved performance. In C#, we have powerful tools at our disposal, such as the Task and Parallel classes, that simplify the implementation of multithreaded applications.

In this blog post, I will guide you through the world of multithreading in C# and delve into two essential concepts: Task.WhenAll and Parallel.ForEach. These features offer efficient and streamlined approaches to parallel execution, allowing you to unlock the full potential of multithreading in your projects.

Before we dive into the specifics of Task.WhenAll and Parallel.ForEach, let's first gain a solid understanding of multithreading in C# and its benefits.

Understanding Multithreading in C#

Multithreading involves dividing a program's execution into multiple threads that can run concurrently. This concurrency allows us to perform computationally intensive or I/O-bound tasks without blocking the main thread, thereby enhancing responsiveness and overall performance.

In C#, the .NET framework provides robust support for multithreading. It offers various abstractions, including threads, tasks, and synchronization primitives, to simplify concurrent programming.

During this exploration, we will discuss the advantages of multithreading and how it can revolutionize your application's performance. We'll also explore how C# handles multithreading and the challenges that arise when manually managing threads.

Introducing Task.WhenAll

The Task class is a fundamental component of the Task Parallel Library (TPL) in C#. It simplifies asynchronous programming and provides a higher-level abstraction for working with concurrent operations. Task.WhenAll is a powerful method that allows us to await multiple tasks simultaneously.

In this section, we will take an in-depth look at the Task class and its purpose in C#. We'll then dive into Task.WhenAll, examining its significance in parallel execution. I will walk you through real-world examples to demonstrate how Task.WhenAll can streamline your code and improve performance over manual multithreading.

Unleashing the Power of Parallel.ForEach

The Parallel class is another powerful tool in C# that simplifies parallel programming. It abstracts away the complexities of managing threads manually and allows us to leverage parallelism effortlessly. One of its key features is Parallel.ForEach, which enables us to iterate over collections in parallel.

In this section, we will explore the capabilities of the Parallel class and focus on the versatility and benefits of Parallel.ForEach. I will guide you through practical examples to showcase how this construct can significantly improve the performance of computationally intensive tasks.

Comparing Task.WhenAll and Parallel.ForEach

In this section, we will conduct a comprehensive comparison between Task.WhenAll and Parallel.ForEach. We'll analyze their performance characteristics, scalability, and suitability for different scenarios. By understanding the strengths and weaknesses of each approach, you'll be able to make informed decisions when choosing the

Multithreading plays a crucial role in modern software development, allowing us to execute multiple tasks concurrently and leverage the full potential of our hardware resources. In C#, we have powerful tools at our disposal to simplify multithreading and enhance performance. Let's delve into the concept of multithreading in C# and understand how it can benefit our applications.

What is Multithreading and its Benefits?

Multithreading involves executing multiple threads of execution within a single process simultaneously. By dividing our program into multiple threads, we can perform tasks concurrently, making our applications more responsive, efficient, and capable of handling complex operations. Multithreading brings several advantages, including:

  • Improved Responsiveness : Multithreading enables us to handle time-consuming tasks without blocking the main thread, ensuring that our application remains responsive and user-friendly.
  • Enhanced Performance : By utilizing multiple threads, we can distribute the workload across available CPU cores, effectively utilizing the hardware resources and achieving better performance.
  • Concurrency and Parallelism : Multithreading allows us to perform tasks concurrently, enabling parallelism and efficient utilization of system resources.

How C# Handles Multithreading

C# provides robust support for multithreading through its Task and Parallel classes, which are part of the Task Parallel Library (TPL). The TPL simplifies the development of parallel and asynchronous code by abstracting the complexities of thread management.

When we create a new thread in C#, the operating system allocates resources to it, such as processor time and memory. The .NET runtime manages these threads and provides mechanisms to control their execution.

Challenges of Manual Multithreading

While multithreading offers numerous benefits, it also introduces challenges and complexities. When we manually manage threads, we need to consider several factors, including:

  • Thread Synchronization : Proper synchronization is essential when multiple threads access shared resources concurrently to avoid data corruption and race conditions.
  • Thread Coordination : Coordinating the execution of multiple threads can be challenging, especially when tasks depend on each other or require synchronization points.
  • Complexity and Debugging : As the number of threads increases, so does the complexity of the code. Debugging multithreaded code can be tricky due to race conditions and non-deterministic behavior.

To address these challenges, C# provides high-level abstractions like Task.WhenAll and Parallel.ForEach, which simplify multithreaded programming and handle many of the complexities on our behalf.

As a web developer, I understand the significance of multithreading in modern software development. It allows us to execute multiple tasks simultaneously, improving performance and responsiveness in our applications. In C#, we have powerful tools like the Task and Parallel classes that simplify multithreading. In this blog post, I want to focus on Task.WhenAll and Parallel.ForEach, two essential features that can make multithreading easier and more efficient.

Explanation of the Task class and its purpose in C#

In C#, the Task class represents an asynchronous operation or a unit of work that can be executed concurrently. It allows us to work with tasks, schedule their execution, and handle the results asynchronously. The Task class provides a high-level abstraction for managing multithreading in our applications.

Detailed exploration of Task.WhenAll and its significance in parallel execution

Task.WhenAll is a powerful method provided by the Task class that enables us to execute multiple tasks concurrently and await their completion. It accepts an array or collection of tasks and returns a new task that completes when all the input tasks have completed.

By utilizing Task.WhenAll, we can easily parallelize our code and leverage the benefits of multithreading without dealing with the complexities of manual thread management. It simplifies the coordination and synchronization of tasks, making it easier to write efficient and responsive applications.

Benefits of using Task.WhenAll over manual multithreading

When compared to manual multithreading, Task.WhenAll offers several benefits. Firstly, it abstracts away the low-level details of thread management, allowing us to focus on the logic of our application. It simplifies the coordination of multiple tasks, reducing the chances of race conditions and deadlocks.

Task.WhenAll also provides better scalability and resource utilization. Under the hood, it utilizes the thread pool to manage the execution of tasks, which optimizes the allocation and reuse of threads, resulting in improved performance.

Code examples demonstrating the usage of Task.WhenAll

Let's take a look at a simple code example to understand how Task.WhenAll works:

In this example, we create three tasks using Task.Run, each performing a time-consuming operation represented by the DoWork method. We then use Task.WhenAll to await the completion of all tasks. Once all tasks are completed, we can process the results as needed.

Task.WhenAll simplifies the management of parallel tasks and allows us to write cleaner and more concise code, improving the readability and maintainability of our applications.

With an understanding of Task.WhenAll, let's dive into the power of Parallel.ForEach and explore how it can further simplify multithreading in C#.

As a web developer, I understand the importance of efficient multithreading in modern software development. One of the key tools in C# for achieving parallel execution is the Parallel class. In this section, we will explore the capabilities of Parallel.ForEach and understand how it can simplify and enhance our multithreading tasks.

Introduction to the Parallel Class

The Parallel class in C# provides a high-level approach to parallel programming, making it easier to leverage the power of multithreading. It offers various methods and constructs for parallel execution, including Parallel.ForEach .

Exploring Parallel.ForEach

Parallel.ForEach is a powerful construct that simplifies parallel execution by distributing iterations of a loop across multiple threads. It automates the partitioning of work and manages the threads for us, freeing us from the complexities of manual thread management.

Advantages of Using Parallel.ForEach

1. simplified parallel execution.

With Parallel.ForEach , we can parallelize the execution of loops effortlessly. It automatically distributes the workload and manages the underlying threads, saving us from the intricacies of manual multithreading. This simplification reduces development time and minimizes the chances of errors.

2. Improved Performance and Scalability

By utilizing multiple threads, Parallel.ForEach can significantly enhance the performance of our applications, especially when dealing with computationally intensive tasks or large data sets. It leverages the available CPU cores effectively, enabling faster execution and better scalability.

3. Load Balancing

Parallel.ForEach employs an intelligent load-balancing mechanism. It dynamically adjusts the workload assigned to each thread, ensuring that the computational effort is evenly distributed. This capability maximizes resource utilization and prevents individual threads from being overwhelmed or underutilized.

4. Implicit Synchronization

When working with shared resources or collections, Parallel.ForEach handles synchronization implicitly. It manages thread safety by ensuring that multiple threads do not access shared data simultaneously, reducing the likelihood of data corruption or race conditions. This simplifies our code and eliminates the need for explicit synchronization mechanisms.

Implementation Examples

Let's look at a couple of examples to see how Parallel.ForEach can be implemented in practice.

In both examples, Parallel.ForEach takes care of dividing the workload among multiple threads, executing the specified action in parallel for each element in the array or collection.

When it comes to leveraging multithreading capabilities in C#, two commonly used approaches are Task.WhenAll and Parallel.ForEach. While both techniques offer parallel execution, they have distinct features and are suitable for different scenarios. In this section, we will conduct a comprehensive comparison of Task.WhenAll and Parallel.ForEach to help you make an informed decision based on your project requirements.

Performance and Scalability

One crucial aspect to consider is the performance and scalability of each approach. Task.WhenAll allows you to execute multiple tasks concurrently, leveraging the power of asynchronous programming. This makes it ideal for scenarios where you have multiple independent tasks that can be executed concurrently. The asynchronous nature of Task.WhenAll ensures that your application remains responsive and doesn't block the main thread.

On the other hand, Parallel.ForEach is designed for parallelizing loop iterations. It is well-suited when you have a collection of items that can be processed in parallel, such as iterating over a large array or a list. Parallel.ForEach automatically partitions the workload across multiple threads, distributing the iterations efficiently. This can lead to significant performance improvements when dealing with computationally intensive tasks.

Suitability for Different Scenarios

Another aspect to consider is the suitability of each approach for different scenarios. Task.WhenAll is particularly useful when dealing with asynchronous operations, such as making multiple HTTP requests or performing I/O-bound tasks. It simplifies the coordination and synchronization of these operations, allowing you to handle the results as a single unit. Task.WhenAll is also beneficial in scenarios where you need to await multiple tasks and continue once they all complete.

Parallel.ForEach, on the other hand, shines in scenarios where you can divide the workload into smaller, independent units that can be processed concurrently. This is especially valuable when dealing with CPU-bound tasks, such as complex calculations or data processing. Parallel.ForEach automatically distributes the workload across available CPU cores, maximizing resource utilization and accelerating the overall execution.

Choosing the Appropriate Approach

To choose the appropriate approach, consider the nature of your tasks and the requirements of your project. If you have multiple independent asynchronous operations or the need to await multiple tasks, Task.WhenAll is a suitable choice. It provides simplicity, flexibility, and responsiveness.

If your focus is on parallelizing loop iterations or processing a collection of items in parallel, Parallel.ForEach is the way to go. It excels in scenarios where you can divide the workload into smaller, independent units, and can significantly improve performance for CPU-bound tasks.

Remember that you can also combine these approaches when your project requires both parallelizing loop iterations and coordinating multiple asynchronous operations. By leveraging the strengths of Task.WhenAll and Parallel.ForEach, you can achieve optimal parallel execution in your application.

Code Examples

Let's take a look at code examples to illustrate the usage of Task.WhenAll and Parallel.ForEach:

These code snippets demonstrate the usage of Task.WhenAll to coordinate multiple tasks asynchronously and await their completion. In contrast, the Parallel.ForEach example showcases how to parallelize the processing of items in a collection, leveraging the automatic workload partitioning provided by the Parallel class.

By examining these examples and considering the nature of your tasks and requirements, you can make

an informed decision on whether to use Task.WhenAll or Parallel.ForEach.

In the next section, we will explore best practices for multithreading in C#, including tips for optimizing your code, handling errors, ensuring thread safety, and improving overall performance and efficiency.

Best Practices for Multithreading with C#

Multithreading can greatly enhance the performance and responsiveness of your C# applications. However, it also introduces complexities and challenges that need to be carefully managed. Here are some best practices to follow when working with multithreaded code in C#.

1. Optimize Multithreaded Code

To ensure efficient multithreading, consider the following tips:

  • Minimize Lock Contention : Use fine-grained locks or lock-free algorithms to minimize contention and improve scalability.
  • Avoid Overhead : Use thread pooling (e.g., ThreadPool class) instead of creating excessive threads manually, which can incur unnecessary overhead.
  • Batching Operations : If possible, group similar operations together to minimize synchronization and context switching overhead.

Example of using ThreadPool for asynchronous operations:

2. Error Handling and Synchronization

Proper error handling and synchronization are critical for maintaining the integrity of multithreaded applications.

  • Exception Handling : Use appropriate exception handling mechanisms within each thread to handle exceptions gracefully. Consider using try-catch blocks or Task.Exception property for error propagation and handling.

Example of exception handling within a multithreaded context:

  • Synchronization : Use synchronization primitives such as lock or Monitor to ensure thread safety and avoid race conditions when accessing shared resources.

Example of using lock for synchronization:

3. Ensure Thread Safety

Thread safety is crucial to prevent data corruption and unpredictable behavior in multithreaded environments.

  • Immutable Data : Use immutable data structures whenever possible to eliminate the need for synchronization.
  • Thread-Safe Types : Utilize thread-safe collections ( ConcurrentDictionary , ConcurrentQueue , etc.) and thread-safe programming techniques to ensure safe concurrent access to shared data.

Example of using ConcurrentDictionary for thread-safe data access:

4. Profile and Optimize Performance

Multithreading introduces its own set of performance considerations. Monitor and optimize your multithreaded code to ensure efficient execution.

  • Profiling : Profile your multithreaded application using performance profiling tools to identify bottlenecks and areas for improvement.
  • Load Balancing : Distribute the workload evenly among threads to maximize resource utilization and avoid thread starvation.

Example of load balancing using Parallel.ForEach :

5. Test and Debug Thoroughly

Testing and debugging multithreaded code can be challenging. Follow these practices to improve the reliability and correctness of your application:

  • Unit Testing : Write comprehensive unit tests that cover different multithreaded scenarios, ensuring the expected behavior of your code.
  • Debugging Tools : Utilize debugging tools, such as breakpoints and thread inspection, to identify and resolve concurrency issues.

Remember, multithreading is a powerful tool, but it requires careful consideration and implementation.

By following these best practices, you can ensure smoother and more efficient multithreaded code in your C# applications.

In conclusion, exploring C# Task.WhenAll and Parallel.ForEach has provided us with valuable insights into simplifying multithreading in our software development projects. We have covered various aspects of multithreading, the Task and Parallel classes, and the significance of Task.WhenAll and Parallel.ForEach.

By leveraging Task.WhenAll, we can easily manage asynchronous operations and achieve parallel execution without the complexities of manual multithreading. The ability to await multiple tasks simultaneously and efficiently handle their results greatly enhances our productivity.

Parallel.ForEach, on the other hand, empowers us to parallelize iterations over collections effortlessly. With its automatic load balancing and optimized partitioning, we can achieve improved performance and scalability in scenarios involving data processing and computations.

When comparing Task.WhenAll and Parallel.ForEach, it is essential to consider the specific requirements of our projects. Task.WhenAll shines in scenarios where we deal with multiple independent tasks, such as calling external APIs or performing database operations. Parallel.ForEach, on the other hand, excels when we need to process data in parallel, such as transforming large collections or performing computationally intensive operations.

To make the most of multithreading in C#, it is crucial to follow best practices. Optimize your code by using appropriate synchronization techniques, handling errors effectively, and ensuring thread safety. Consider the performance implications of your multithreading approach and continually monitor and fine-tune your implementation.

In conclusion, by embracing Task.WhenAll and Parallel.ForEach, we can simplify and enhance our multithreading endeavors in C#. These powerful tools provide us with efficient parallel execution capabilities, improving performance and productivity in our software development projects. As experienced developers, let's continue to explore and experiment with multithreading techniques, unlocking the full potential of our applications.

Happy coding!

Feel free to explore these references for more in-depth information and examples related to multithreading, Task.WhenAll, and Parallel.ForEach in C#.

  • Task.WhenAll Method - Microsoft Docs
  • Parallel.ForEach Method - Microsoft Docs
  • Task-based Asynchronous Pattern (TAP) - Microsoft Docs
  • Parallel Programming in .NET - Microsoft Docs
  • C# Multithreading and Asynchronous Processing - Microsoft Docs

🎓 C# Mastery

Continue on your path to C# mastery by selecting an article below!

Discover the potential pitfalls of overlapping queries in Blazor applications using Entity Framework Core and learn effective strategies to avoid performance issues and ensure optimal data retrieval.

Step-by-step guide on building a simple CRUD (Create, Read, Update, Delete) application using form components in Blazor. Learn the basics of data binding, form validation, and interacting with a backend using Entity Framework Core.

Learn how to implement a custom validation constraint in Blazor form components to handle unique business rules. Enhance your data validation capabilities and create a more robust user experience in your web applications.

  • United States
  • United Kingdom

Joydip Kanjilal

By Joydip Kanjilal , Contributor, InfoWorld |

When to use Task.WaitAll vs. Task.WhenAll in .NET

Understand the differences between task.waitall and task.whenall methods and when to use which in your application..

When to use Task.WaitAll vs. Task.WhenAll in .NET

The TPL (Task Parallel Library) is one of the most interesting new features added in the recent versions of .NET framework. The Task.WaitAll and Task.WhenAll methods are two important and frequently used methods in the TPL.

The Task.WaitAll blocks the current thread until all other tasks have completed execution. The Task.WhenAll method is used to create a task that will complete if and only if all the other tasks have completed.

So, if you are using Task.WhenAll you will get a task object that isn’t complete. However, it will not block but will allow the program to execute. On the contrary, the Task.WaitAll method call actually blocks and waits for all other tasks to complete.

Essentially, Task.WhenAll will give you a task that isn’t complete, but you can use ContinueWith as soon as the specified tasks have completed their execution. Note that neither Task.WhenAll nor Task.WaitAll will actually run the tasks; i.e., no tasks are started by these methods. Here is how ContinueWith is used with Task.WhenAll: 

As Microsoft’s documentation states , Task.WhenAll “creates a task that will complete when all of the Task objects in an enumerable collection have completed.”

Task.WhenAll vs. Task.WaitAll

Let me explain the difference between these two methods with a simple example. Suppose you have a task that performs some activity with the UI thread — say, some animation needs to be shown in the user interface. Now, if you use Task.WaitAll, the user interface will be blocked and will not be updated until all the related tasks are completed and the block released. However, if you are using Task.WhenAll in the same application, the UI thread will not be blocked and would be updated as usual.

So which of these methods should you use when? Well, you can use WaitAll when the intent is synchronously blocking to get the results. But when you would want to leverage asynchrony, you would want to use the WhenAll variant. You can await Task.WhenAll without having to block the current thread. Hence, you may want to use await with Task.WhenAll inside an async method.

While Task.WaitAll blocks the current thread until all pending tasks are complete, Task.WhenAll returns a task object. Task.WaitAll throws an AggregateException when one or more of the tasks throws an exception. When one or more tasks throw an exception and you await the Task.WhenAll method, it unwraps the AggregateException and returns just the first one.

Avoid using Task.Run in loops

You can use tasks when you would like to execute concurrent activities. If you need a high degree of parallelism, tasks are never a good choice. It is always advisable to avoid using thread pool threads in ASP.Net. Hence, you should refrain from using Task.Run or Task.factory.StartNew in ASP.Net.

Task.Run should always be used for CPU bound code. The Task.Run is not a good choice in ASP.Net applications, or, applications that leverages the ASP.Net runtime since it just offloads the work to a ThreadPool thread. If you are using ASP.Net Web API, the request would already be using a ThreadPool thread. Hence, if you use Task.Run in your ASP.Net Web API application, you are just limiting scalability by offloading the work to another worker thread sans any reason.

Note that there is a disadvantage in using Task.Run in a loop. If you use the Task.Run method inside a loop, multiple tasks would be created -- one for each unit of work or iteration. However, if you use Parallel.ForEach in lieu of using Task.Run inside a loop, a Partitioner gets created to avoid creating more tasks to perform the activity than it is needed. This might improve the performance significantly as you can avoid too many context switches and still leverage multiple cores in your system.

It should be noted that Parallel.ForEach uses Partitioner<T> internally so as to distribute the collection into work items. Incidentally, this distribution doesn't happen for each task in the list of items, rather, it happens as a batch. This lowers the overhead involved and hence improves performance. In other words, if you use Task.Run or Task.Factory.StartNew inside a loop, they would create new tasks explicitly for each iteration in the loop. Parallel.ForEach is much more efficient because it will optimize the execution by distributing the work load across the multiple cores in your system.

Next read this:

  • Why companies are leaving the cloud
  • 5 easy ways to run an LLM locally
  • Coding with AI: Tips and best practices from developers
  • Meet Zig: The modern alternative to C
  • What is generative AI? Artificial intelligence that creates
  • The best open source software of 2023
  • Microsoft .NET
  • Software Development
  • Development Libraries and Frameworks

Joydip Kanjilal is a Microsoft MVP in ASP.NET, as well as a speaker and author of several books and articles. He has more than 20 years of experience in IT including more than 16 years in Microsoft .NET and related technologies.

Copyright © 2016 IDG Communications, Inc.

task whenall method

NimblePros

Task.WhenAll or Parallel.ForEach?

Article

Fati Iseni , Consulting Contractor

Recently someone asked:

A simple question. I have a set of tasks to perform and I want to optimize their performance. Basically reading a file and writing to a database. Each operation is atomic, none of them depend on one another. So, which is better? Task.WhenAll or Parallel.ForEach ?

The Task.WhenAll is about threading, while the Parallel is about concurrent utilization of the underlying resources.

This may sound the same, but there are crucial differences. When you dispatch some work to a separate thread, there is no guarantee that the thread will be scheduled in a different processor core (actually, most often will not). Even if you create 1000 threads, they may all run on the same core. So, Task.WhenAll indeed will dispatch all those threads concurrently, but this “concurrency” is only on the high app level. This does not guarantee that these threads will be dispatched concurrently at the CPU level . It’s just high level abstraction for you. And, that’s fine, because concurrency in this context is all about IO operations .

On the other hand, if you have CPU bound operations, then the way in which the work is scheduled becomes important. You want to maximize the CPU usage. That’s when you need Parallel . This will mediate all the complex communication with the OS and will ensure that it’s run on multiple cores.

You need to be careful though. If you use the default configuration, it will use the CPU to the max, and will consume all cores. And this may bring your machine to a seemingly “frozen” condition. If you have other processes on the host, they may be affected badly. So, it’s always nice to also explicitly configure the maximum allowed cores to use.

For example, if you want to calculate a factorial, or find prime numbers, you want parallel processing and you should use Parallel .

On the other hand, if your job is to get some data from some endpoint, this is in essence mostly IO, and you can use Task.WhenAll . the CPU utilization won’t make a difference here.

Ok So Which One Do I Want?

I wrote a lot, but didn’t answer the question 🙂 For this scenario, if you don’t have some heavy operations, the job only reads a file, does simple mapping and writes to a database, stick to Task.WhenAll .

It’s not as simple as I described it, but something similar 🙂. This is a high level explanation and like all such explanations, not 100% accurate. Check the documentation to learn more about the low level details.

The thread is the smallest unit that can get CPU time (in almost any OS). So, whenever you create a thread, you need an OS thread to do some work. In managed environments (like .NET) that’s a bit different, since we usually pool some defined number of threads (so we don’t ask the OS all the time, it’s a costly process). But, anyhow, you always have 1:1 mapping of App thread to OS thread (we don’t have green threads in .NET).

The subtle difference is how you have communicated your intent to OS. If you just say give me a thread, then where it is scheduled is at the OS’s discretion. You still get the impression of concurrency, since there is CPU time scheduling. The Parallel approach actually just forces the OS to dispatch those threads into as many cores as possible. So, it’s just more specific in communicating the intent to the OS.

The key difference between Task.WhenAll and Parallel.ForEach is how they deal with real OS threads. Task.WhenAll will most likely end up using threads on the same CPU as the host process, while Parallel.ForEach will aggressively try to use multiple CPUs. If you have a CPU-bound operation, you will get better performance from Parallel.ForEach , but take care you don’t saturate every CPU and “freeze” the host OS!

  • Jeremiah Cooper
  • Scott DePouw
  • Sarah "Sadukie" Dutkiewicz
  • Eric Fleming
  • Kyle McMaster
  • Thomas Mullaly
  • Dr. Michelle Smith
  • Steve "Ardalis" Smith
  • Philippe Vaillancourt
  • Cameron Young
  • Announcements
  • Career Advancement
  • Domain Driven Design
  • Software Development
  • Troubleshooting

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Task. When Any Method

Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

Creates a task that will complete when any of the supplied tasks have completed.

WhenAny(IEnumerable<Task>)

The tasks to wait on for completion.

A task that represents the completion of one of the supplied tasks. The return task's Result is the task that completed.

The tasks argument was null .

The tasks array contained a null task, or was empty.

The returned task will complete when any of the supplied tasks has completed. The returned task will always end in the RanToCompletion state with its Result set to the first task to complete. This is true even if the first task to complete ended in the Canceled or Faulted state.

WhenAny(Task[])

The tasks argument was null.

WhenAny(Task, Task)

Creates a task that will complete when either of the supplied tasks have completed.

The first task to wait on for completion.

The second task to wait on for completion.

A new task that represents the completion of one of the supplied tasks. Its Result is the task that completed first.

task1 or task2 was null .

The returned task will complete when any of the supplied tasks has completed. The returned task will always end in the RanToCompletion state with its Result set to the first task to complete. The result value is true even if the first task to complete ended in the Canceled or Faulted state.

WhenAny<TResult>(IEnumerable<Task<TResult>>)

Type parameters.

The type of the completed task.

WhenAny<TResult>(Task<TResult>[])

Whenany<tresult>(task<tresult>, task<tresult>).

The type of the result of the returned task.

A task that represents the completion of one of the supplied tasks. The returned task's TResult is the task that completed first.

In every overloaded version of Task.WhenAny() when this method returns the first completed task, the other tasks will continue running until completion, even any of them completed in the Canceled or Faulted state. So, if that behavior is not desired you may want to cancel all the remaining tasks once the first task complete.

Was this page helpful?

Submit and view feedback for

Additional resources

IMAGES

  1. Pro EP 42 : Task.WhenAll Method in C#

    task whenall method

  2. [Solved] How to use Task.WhenAll() correctly

    task whenall method

  3. Understanding Task.WhenAll in C#

    task whenall method

  4. C# : Task.WhenAll and task starting behaviour

    task whenall method

  5. asynchronous

    task whenall method

  6. [Solved] Getting return values from Task.WhenAll

    task whenall method

VIDEO

  1. How to fail a task in 3 easy steps…

  2. PROBLEM 8.1 TASK 3 ( QUANTITATIVE METHOD )

  3. Task Analysis Concept

  4. Simple Task, Right?

  5. task common method

  6. task completing method in DDB earning

COMMENTS

  1. Task.WhenAll Method (System.Threading.Tasks)

    Definition Namespace: System. Threading. Tasks Assembly: System.Runtime.dll Creates a task that will complete when all of the supplied tasks have completed. Overloads Expand table WhenAll (IEnumerable<Task>) Creates a task that will complete when all of the Task objects in an enumerable collection have completed. C#

  2. c#

    List<Task> monitoredTasks = new List<Task> (); foreach (BusRouteIdentifier bri in stop.services) { BusRouteRequest req = new BusRouteRequest (bri.id); // Start a new task to fetch the route for each stop Task getRouteTask = Task.Factory.StartNew (async () => { var route = await BusDataProviderManager.DataProvider.DataBroker.getRoute (req)...

  3. How to Execute Multiple Tasks in C#

    With Task.WhenAll method, we can have a list of tasks, and all the tasks will be executed concurrently. When all of the tasks are finished, we will be able to continue the execution of a method. Example to Understand Task.WhenAll Method: Let us understand how to execute multiple tasks concurrently using the Task.WhenAll method in C#.

  4. Consuming the Task-based Asynchronous Pattern

    When you're awaiting a Task<TResult>, the await expression is of type TResult. An await expression must occur inside the body of an asynchronous method. (These language features were introduced in .NET Framework 4.5.) Under the covers, the await functionality installs a callback on the task by using a continuation.

  5. C# WhenAll

    The Task.WhenAll () method creates a task that will complete once all the input tasks are completed. The method returns a Task object that represents the completion of all the input tasks. The returned task contains the results of all the input tasks.

  6. Using Task.WhenAll in C#: A Comprehensive Guide with Examples

    The Task.WhenAll method is a powerful tool for concurrently executing multiple tasks and awaiting their completion. In this comprehensive guide, we'll explore the usage of Task.WhenAll with detailed examples to help you understand how it works and when to use it effectively in your asynchronous C# code. Understanding Task.WhenAll

  7. c#

    How to use Task.WhenAll properly Ask Question Asked 11 years, 6 months ago Modified 10 years, 4 months ago Viewed 13k times 4 Following to this question (and its answer) I want to use TaskCompletionSource and Task.WhenAll to wait until when any task returns True firstly. So I wrote this :

  8. Chaining tasks using continuation tasks

    However, you typically call all but the Task.WhenAll(IEnumerable<Task>) and Task.WhenAll(Task[]) methods to retrieve the returned Task<TResult>.Result property, which does block the calling thread. The following example calls the Task.WhenAll(IEnumerable<Task>) method to create a continuation task that reflects the results of its 10 antecedent ...

  9. Understanding Task.WhenAll in C#

    The Task.WhenAll method in C# allows you to create a task that is completed when a group of other tasks have finished executing. This can be useful when you want to wait for multiple tasks to complete before moving on to other parts of your code. To use Task.WhenAll, you can pass it a list of tasks that you want to wait for. For example:

  10. How to Execute Multiple Tasks Asynchronously in C#

    { return await Task.FromResult(Ok(new { Id = id, Name = $"Sam_{id}", DateOfBirth = DateTime.Now.AddYears(-1 * _random.Next(20, 30)).Date, Address = "Employee Dummy Address" })); } [HttpGet("salary/ {id}")] public async Task<IActionResult> GetEmployeeSalary(Guid id) { return await Task.FromResult(Ok(new { Id = id, SalaryInEuro = 25000 })); }

  11. Multithreading Made Easy: Exploring C# Task.WhenAll and Parallel.ForEach

    Introducing Task.WhenAll. The Task class is a fundamental component of the Task Parallel Library (TPL) in C#. It simplifies asynchronous programming and provides a higher-level abstraction for working with concurrent operations. Task.WhenAll is a powerful method that allows us to await multiple tasks simultaneously.

  12. Understanding Task.WaitAll and Task.WhenAll in C#

    Task.WhenAll is an asynchronous method that returns a task that completes when all the provided tasks have completed execution. Unlike Task.WaitAll, it doesn't block the calling thread, allowing for a non-blocking and more responsive application. It's especially useful in asynchronous environments such as UI applications. Example of Task.WhenAll

  13. Maximizing Performance and Concurrency in C# with Task.WhenAll ...

    Task.WhenAll is a method in C# that allows you to execute multiple asynchronous tasks concurrently and wait for all of them to complete before continuing. This method takes an array of...

  14. When to use Task.WaitAll vs. Task.WhenAll in .NET

    The Task.WaitAll blocks the current thread until all other tasks have completed execution. The Task.WhenAll method is used to create a task that will complete if and only if all the other tasks ...

  15. Task.WaitAll vs. Task.WhenAll in C#

    Task.WhenAll is a static method that returns a single task that represents the completion of all the specified tasks. It does not block the calling thread and is a more flexible alternative to ...

  16. Multiple Async Methods, best to use WhenAll with different return types

    var tasks1 = new List<Task<List<Biz.AbstractClass>>> (); tasks1.Add (bp.GetCustomerAsAbstractAsync ()); tasks1.Add (bp.GetAccountAsAbstractAsync ()); ...plus 2 more I then call var continuation = Task.WhenAll (tasks1); this executes then the next line it gets to the .Results but then stops executing???

  17. How to: Extend the Async Walkthrough by Using Task.WhenAll

    You apply the Task.WhenAll method to a collection of tasks. The application of WhenAll returns a single task that isn't complete until every task in the collection is completed. The tasks appear to run in parallel, but no additional threads are created. The tasks can complete in any order. Important

  18. Task.WhenAll in .NET . Task.WhenAll is a static method ...

    Task.WhenAll is a static method found within the C# Task class. It generates a fresh task that concludes only when all the specified tasks as parameters reach completion. This method offers a means…

  19. Task.WhenAll in async method, then unwrapping each task

    the Task.WhenAll is the parallel part I was referring to - Jonesopolis Jan 4, 2018 at 16:28 2 @maccettura No, it's not, but the code shown here is, because it's starting multiple asynchronous operations without waiting for others to finish, resulting in them doing their work in parallel. - Servy

  20. Task.WhenAll or Parallel.ForEach?

    Task.WhenAll will most likely end up using threads on the same CPU as the host process, while Parallel.ForEach will aggressively try to use multiple CPUs. If you have a CPU-bound operation, you will get better performance from Parallel.ForEach , but take care you don't saturate every CPU and "freeze" the host OS!

  21. Task.WhenAny Method (System.Threading.Tasks)

    Definition Namespace: System. Threading. Tasks Assembly: System.Runtime.dll Creates a task that will complete when any of the supplied tasks have completed. Overloads Expand table WhenAny (IEnumerable<Task>) Creates a task that will complete when any of the supplied tasks have completed. C#

  22. c#

    2 Answers Sorted by: 6 If you really have only an IEnumerable<Task<TResult>> and the task will be created on-the-fly (e.g. due to a .Select ()) you would execute your tasks two times. So, be sure that you either give an already materialized collection to Task.WhenAll () or get the result from the return value of that method: