Six ways to initiate tasks on another thread in .NET

Over the years, Microsoft have provided us with multiple different ways to kick off tasks on a background thread in .NET. It can be rather bewildering to decide which one you ought to use. So here’s my very quick guide to the choices available. We’ll start with the ones that have been around the longest, and move on to the newer options.

Asynchronous Delegates

Since the beginning of .NET you have been able to take any delegate and call BeginInvoke on it to run that method asynchronously. If you don’t care about when it ends, it’s actually quite simple to do. Here we’ll call a method that takes a string:

The BeginInvoke method also takes a callback parameter and some optional state. This allows us to get notification when the background task has completed. We call EndInvoke to get any return value and also to catch any exception thrown in our function. BeginInvoke also returns an IAsyncResult allowing us to check or wait for completion.

This model is called the Asynchronous Programming Model (APM). It is quite powerful, but is a fairly cumbersome programming model, and not particularly great if you want to chain asynchronous methods together as you end up with convoluted flow control over lots of callbacks, and find yourself needing to pass state around in awkward ways.

Thread Class

Another option that has been in .NET since the beginning is the Thread class. You can create a new Thread object, set up various properties such as the method to execute, thread name, and priority, and then start the thread.

This may seem like the obvious choice if you need to run something on another thread, but it is actually overkill for most scenarios.

It’s better to let .NET manage the creation of threads rather than spinning them up yourself. I only tend to use this approach if I need a dedicated thread for a single task that is running for the lifetime of my application.

The ThreadPool was introduced fairly early on in .NET (v1.1 I think) and provided an extremely simple way to request that your method be run on a thread from the thread pool. You just call QueueUserWorkItem and pass in your method and state. If there are free threads it will start immediately, otherwise it will be queued up. The disadvantage of this approach compared to the previous two is that it provides no mechanism for notification of when your task has finished. It’s up to you to report completion and catch exceptions.

This technique has now really been superseded by the Task Parallel Library (see below), which does everything the ThreadPool class can do and much more. If you’re still using it, its time to learn TPL.

BackgroundWorker Component

The BackgroundWorker component was introduced in .NET 2 and is designed to make it really easy for developers to run a task on a background thread. It covers all the basics of reporting progress, cancellation, catching exceptions, and getting you back onto the UI thread so you can update the user interface.

You put the code for your background thread into the DoWork event handler of the background worker:

and within that function you are able to report progress:

You can also check if the user has requested cancellation with the BackgroundWorker.CancellationPending flag.

The BackgroundWorker provides a RunWorkerCompleted event that you can subscribe to and get hold of the results of the background task. It makes it easy to determine if you finished successfully, were cancelled, or if an exception that was thrown. The RunWorkerCompleted and ProgressChanged events will both fire on the UI thread, eliminating any need for you to get back onto that thread yourself.

BackgroundWorker is a great choice if you are using WinForms or WPF. My only one criticism of it is that it does tend to encourage people to put business logic into the code behind of their UI. But you don't have to use BackgroundWorker like that. You can create one in your ViewModel if you are doing MVVM, or you could make your DoWork event handler simply call directly into a business object.

Task Parallel Library (TPL)

The Task Parallel Library was introduced in .NET 4 as the new preferred way to initiate background tasks. It is a powerful model, supporting chaining tasks together, executing them in parallel, waiting on one or many tasks to complete, passing cancellation tokens around, and even controlling what thread they will run on.

In its simplest form, you can kick off a background task with TPL in much the same way that you kicked off a thread with the ThreadPool .

Unlike the ThreadPool though, we get back a Task object, allowing you to wait for completion, or specify another task to be run when this one completes. The TPL is extremely powerful, but there is a lot to learn, so make sure you check out the resources below for learning more.

C# 5 async await

The async and await keywords were introduced with C# 5 and .NET 4.5 and allow you to write synchronous looking code that actually runs asynchronously. It’s not actually an alternative to the TPL; it augments it and provides an easier programming model. You can call await on any method that returns a task, or if you need to call an existing synchronous method you can do that by using the TPL to turn it into a task:

The  advantages are that this produces much easier to read code, and another really nice touch is that when you are on a UI thread and await a method, when control resumes you will be back on the UI thread again:

This model also allows you to put one try…catch block around code that is running on multiple threads, which is not possible with the other models discussed. It is also now possible to use async and await with .NET 4 using the BCL Async Nuget Package.

Here’s a slightly longer example showing a button click event handler in a Windows Forms application that calls a couple of awaitable tasks, catches exceptions whatever thread its on and updates the GUI along the way:

Obviously I can’t fully explain how to use each of these approaches in a short blog post like this, but many of these programming models are covered in depth by some of my fellow Pluralsight Authors. I’d strongly recommend picking at least one of these technologies to master (TPL with async await would be my suggestion).

Thread and ThreadPool:

  • CLR Threading (Mike Woodring)  

Asynchronous Delegates:

  • C# Events, Delegates and Lambdas (Dan Whalin) (Module 5)

BackgroundWorker:

  • Introduction to the BackgroundWorker Component (Jeremy Clark)

Task Parallel Library:

  • TPL Async (Ian Griffiths)
  • Intro to Async and Parallel Programming in .NET 4 (Joe Hummel)  
  • Async and Parallel Programming: Application Design (Joe Hummel)

Async and Await

  • Asynchronous C# 5.0 (Jon Skeet)

Thank you for explaining all these methods! I'm always having a hard time deciding on what to use!

C# 5 async await doesn't create a new Thread. Async Await goes into the state machine and runs within the same context thread on its .next invocation. Though you can run an async-await on a new thread/task, but it itself doesn't create a new thread. Note: Every asynchronously running thing doesn't run a new Thread.

sure, this is quite an old post and the technique of awaiting a Task.Run I showed in this article is very rarely needed these days as most IO operations have Async versions you can use

So, I want this UDPClient's Send and Receive methods to run indefinitely till the lifespan of my application as there are many different forms from/to where any data will be sent/received. What method will you suggest I go with.You already explained in your article that Thread Class would be helpful in my case but one thing is I'm just starting with threads so, a few Lines of code in your explanation will be much appreciated. Like if I create a thread how will I access that thread to call those methods from a different form other than from where the Thread was actually created. Thank you.

How-To Geek

How do tasks work in c# async/background threads.

If you want to make web requests in C#, or just want to do some background processing, you'll need to use asynchronous background tasks to not block up the main thread.

Quick Links

What is async/await, what are tasks.

If you want to make web requests in C#, or just want to do some background processing, you'll need to use asynchronous background tasks to not block up the main thread. We'll discuss what they are, and how to use them.

To use Tasks, you must first understand the concept of async / await . C# tasks don't have to run asynchronously, but considering the sole purpose of them is to represent an asynchronous operation, they almost always will run async. You don't want to run operations like fetching web requests and writing to hard drives on the main thread, because it would hold up the rest of the application (including the UI) while waiting for the result.

async / await  is special syntax used to deal with asynchronous operations. If a function is marked as async , it will usually return a Task, except in cases of event handlers that return void .

Inside the async function, you can use the  await  keyword to wait for async operations to finish without blocking the whole thread. Everything that comes after the await  keyword will only run after the

 operation finishes.

public async Task FetchWebResponse(string url)

var response = await SendRequest(url)

The value being awaited must be a Task, as the two go hand in hand with each other. When you call the SendRequest()  function, it returns a Task<T> , and the program waits until that task finishes. You can think of await  as a keyword used to return or wait for the value of a task to finish.

Tasks are wrappers used to deal with asynchronous functions. They essentially represent a value that will be returned in the future. You can use the await  keyword to wait for the result, or access it directly by checking if Task.IsCompleted  and then reading the value of Task.Result .

You can create them by writing an async function with a return type of Task<T> . Then, all you have to do is return a value of type T, and .NET will interpret that as returning a Task. You can use await  inside this task to wait for async operations, which in turn return a task themselves.

Create a task by writing an async function with a return type of Task<T>.

You can start running a Task using Task.Run(Action action) . This will queue up the Task on the thread pool, which will run in the background on a different thread. The thread pool takes a queue of tasks, and assigns them to CPU threads for processing. Once they return, they're put into the list of completed tasks where their values can be accessed.

Thread pool takes queue of tasks and assigns them to CPU threads for processing. Once returned, they're put intocompleted task list where their values are accessed.

However, even though it's on a background thread, it's still very important to use async/await . If you make a blocking call to an API on a background thread, and don't await  it, .NET will keep that thread blocked until it completes, filling up the thread pool with useless threads doing nothing but hurting performance.

If you need to await a task from the UI thread, start it with Task.Run , then check regularly to see if the task has been completed. If it has, you can handle the value.

To await a task from UI thread, start with Task.Run, then check regularly to see if task has completed.

You can also run and await tasks inside other Tasks. For example, say you have a function inside a task, DoExpensiveCalculation() , that takes a while to execute. Rather than processing it synchronously, you can write it as a Task, and queue up a background thread at the beginning of the main task. Then, when you need the value from that calculation, you can simply await  the task, and it will yield until the task is completed, and the return value is returned.

Run and await tasks inside other Tasks

How To Use Task.Run in C# for Multithreading

How To Use Task.Run in C# for Multithreading

Welcome! Let’s dive into the exciting world of multithreading in C#. Today, we will explore Task.Run , learn about Task Factory StartNew , and harness the might of asynchronous tasks.

Along the way, we’ll discuss various aspects that can transform how you write multithreaded programs using C#. So, let’s get started, shall we?

Understanding C# Task.Run

Isn’t it great when things just run and get the job done without hogging the primary thread? That’s exactly what Task.Run in C# does. It’s a method that allows us to start a task on a separate thread from the ThreadPool, enhancing the performance and responsiveness of your applications.

Loading code snippet...

This code snippet runs a lambda expression on a separate thread, leaving the main thread free to continue executing other tasks. Quite handy, right?

The Basics of C# Task Run

The C# Task.Run method is an integral method in multithreading programming. It’s like the bass player in a band — while invisible to many, it plays a key role in giving structure and rhythm to the harmonic ensemble. But what makes Task.Run the unsung hero in C#?

The brilliance of Task.Run lies in its ability to run operations on the ThreadPool’s threads, outside of the main thread – much like hiring an assistant to deal with administrative work while you can focus on critical tasks.

Let’s consider a basic example:

In this example, we use Task.Run to execute a potentially time-consuming calculation on a separate thread. This behavior ensures that our main thread continues to run undisturbed, keeping user interface responsive or server processing incoming requests.

Now imagine you’re teaching a kid how to tidy their room. Traditionally, they might start by picking up one toy, walk to the toy box, drop it off, and then go back for another toy. This is equivalent to a synchronous operation. With Task.Run , it’s like they’re capable of tidying up their toys and their books at the same time, vastly improving efficiency. It’s an 8-year-old with superpowers!

Task Run in .NET: What it Is Used for and How it Works?

In multithreaded applications, Task.Run is like an experienced conductor directing the orchestra, portraying harmony by managing multiple threads as they run side by side, each performing different tasks simultaneously.

Here’s an in-depth example of how we can utilize Task.Run in a .NET application:

In this code, we have an array of a million numbers. Now, adding them all might be a long operation, blocking our main thread if done synchronously. But Task.Run allows us to offload the work onto a separate thread.

As the sum is being computed, the main thread is free to do other work. When the result is needed, we use await to retrieve it. This is what makes .NET’s Task.Run a favorite tool among developers to increase responsiveness and performance of applications.

Take our kid’s room tidying example again, but this time, imagine they have friends over. While they’re busy tidying up their own mess, Task.Run is equivalent to their friends concurrently cleaning up their own messes. Each kid is a thread, and they all work together to clean the room more quickly and efficiently than one child could alone.

Gaining Control with Task Factory StartNew

Hold on to your seat! It’s time to learn about Task Factory StartNew . Think of it as the orchestra conductor of multithreading in C#. It allows you to start tasks, offers more granular control over task creation than Task.Run , and paves the way for creating complex, layered tasks.

In this example, we create a task using TaskFactory.StartNew and write to the console from a separate thread. But how does this StartNew method create such great music?

Commanding Your Code with Task Factory StartNew

Task Factory's StartNew method surely sounds fancy, doesn’t it? It’s like the conductor’s baton waving methodically to make the orchestra come alive. By controlling where and when every note (or in our case, tasks) is played, the conductor ensures a harmonious performance.

The StartNew method serves a similar purpose in the world of C#. It helps control the life cycle of a task right from its inception, offering numerous overloads to customize these task “notes” to create our code’s beautiful symphony.

In this code snippet, a task is started by the TaskFactory.StartNew method that runs a for-loop. Each iteration is paused for a second, simulating a time-consuming task. Upon executing, it prints the iteration number to the console. It’s like a clock ticking every second on a different thread, freeing the main thread to do whatever it needs simultaneously.

Diving Deeper: How Task Factory StartNew Enhances Your Programming

Task Factory StartNew has its charm that Task.Run perhaps cannot match. Don’t get me wrong, Task.Run is quite nifty for most common scenarios and should be used unless we require a tad bit more control and customization. But if we need to control task scheduling, cancellation, or need a parent/child relationship between tasks – enter Task Factory StartNew .

Think of it like the difference between a DJ playing a pre-recorded track and a conductor leading a live orchestra. Task.Run is that DJ, comfortable, pretty versatile, and can handle most party scenarios. But when you need to control every instrument and make on-the-go changes, you need the conductor, our Task Factory StartNew .

Here’s a more specific scenario. Suppose we need to start a new task but also want an option to cancel it midway if required. Task Factory's StartNew comes to the rescue.

In this code example, I’ve created a new task using Task.Factory.StartNew and also provided a cancellation token. This created task runs a for-loop for 100 iterations, but between each iteration, it checks if a cancel request has been issued. If so, it breaks the loop. I also simulated a cancel request after five seconds using cancellationTokenSource.Cancel() .

It’s pretty much like giving a kid a new toy train. And we also have a remote control to stop the train in its tracks whenever we want. The train (long-running task) runs happily on its own without interrupting the kid (main thread). But if mommy calls and it’s bedtime, we have the power to stop this train immediately and save the day!

As you can see, the StartNew method from Task Factory puts you in the driving seat, giving you control over when and how tasks are to be executed. It’s complex, indeed, but it opens up a world of possibilities for managing simultaneous tasks, which we need while dealing with advanced applications. Happy multitasking!

Navigating Asynchrony: The Role of C# Task.Run Async

Asynchronous programming is like juggling—once you master it, the performance becomes a spectacle. We’ll now move to the Async aspect of Task.Run , a key concept that will help you write highly efficient code by allowing tasks to run concurrently.

In this example, an asynchronous task is queued using Task.Run that waits for a second (simulating a long-running task) before writing to the console. But isn’t the whole deal with async tasks kind of mind-boggling at first? Let’s break it down and understand how it actually works.

A Primer on Await Task Run in C#

The await keyword in C#, as in awaiting a result or response, communicates to the .NET runtime that the execution should be paused at this line until the awaited task is complete. This ‘awaiting’ doesn’t block the thread, it just ‘waits’ until the awaited operation is complete and then resumes where it left off.

In this example, Task.Run is used to start a new Task for a time-consuming operation (simulated by Thread.Sleep(1000) ) which then is awaited using await . The control returns to the calling method until the awaited operation is complete, allowing the UI thread (in case of a GUI application like WPF or WinForms) to stay responsive. The second Console.WriteLine statement will be executed after the long-running task finishes.

Also, don’t let me forget to mention a crucial necessity. The method containing the await keyword needs to be marked async , indicating that this method contains an awaited operation. It familiarizes the .NET runtime with how to handle the execution flow.

Task Run Asynchronous Magic in C#: What You Need to Know

Whenever you use Task.Run to kick-off an asynchronous operation, you allow the .NET runtime to manage the execution of this operation on a separate thread from the ThreadPool, without blocking the calling thread. It lets your application stay responsive, especially in a GUI scenario or when you’re dealing with IO-bound operations.

In this example, Task.Run is used to start a complex calculation, simulating a CPU-intensive operation running in a different thread than the one it was called from. By doing this, we free the calling thread (presumably the UI thread) and allow the .NET runtime to handle how and when this operation is executed.

To see this magic in a real-life example, consider the case of a Windows Forms app that needs to perform a time-consuming operation such as creating a complex report or downloading a large file from a server. By offloading this heavy work to an asynchronous operation using Task.Run , you prevent the app from becoming unresponsive. Instead, the user can continue with other tasks – such as editing a document or interacting with the UI – while the operation runs in the background.

Magic indeed, isn’t it? The beauty of Task.Run is in its simplicity and power, offering you control over when and how to run tasks concurrently, improving your C# applications’ performance and responsiveness.

Exploring C# Parallel Tasks for High-Performance Computing

Parallel tasks in C# are like the members of an orchestra, each instrument plays its part independently, yet together they create a harmonious symphony. Similarly, each task does its work independently of the others but together they accomplish the overall goal. Just as a symphony conductor coordinates the actions of every musician, the .NET runtime controls the operation of every task.

Consider the previous example. Rather than having a single loop printing out numbers sequentially (like a single musician playing every note), we have multiple tasks operating simultaneously (like an orchestra playing a symphony). This is essentially how parallel execution in .NET works.

Parallel programming is particularly effective when working with data structures that can be divided into distinct parts and computed separately. Suppose you’re working with a large array of data, and you’re tasked with performing a calculation on each element.

The PerformExpensiveCalculation is an intensive operation that can sufficiently benefit from parallel execution. In the example, we use Parallel.For to perform this operation on each element of our data array simultaneously in a separate thread. These operations don’t depend on one another, so their execution order doesn’t matter, making the perfect case for parallel execution.

Parallel Tasks in C#: Driving Your Code’s Efficiency

Parallelization can significantly increase the efficiency of your C# programs, primarily when working with CPU-intensive operations or when your application deals with blocking operations.

When you’re dealing with CPU-bound operations like computations, parallelizing can distribute the work across multiple cores. On the other hand, when dealing with IO-bound operations (like reading/writing to disk or network requests), parallelizing such tasks allows your program to progress with other tasks while waiting for these operations to complete.

Here is an IO-bound example, where we download multiple files in parallel:

In the code above, while one task is waiting for a file to download, another task can start downloading the next file, thus using the resources more efficiently.

Task Start in Parallel Tasks in C#

Starting a task in C# is much like hitting the first note in a song. When you call Task.Start , you’re telling the runtime to start executing the task. This can be particularly useful in cases where you want to control when the task starts executing.

Consider the following example:

In the above example, we create 10 tasks, each of which sleeps for a second and then writes a message to the console. Task.Start is used to start each task explicitly.

Parallel execution has an inherent randomness since we can’t predict the exact time each task starts, completes or gets CPU time. Therefore, you may notice that the task numbers in the console output may not be perfectly sequential. This randomness is expected and can vary every time you run the program.

By the way, notice the use of Task.WaitAll to wait for all tasks to complete. It’s like the final note of the orchestra, signaling the end of the performance.

Getting Started with Await Task Run C#

In any multitasking orchestra, the ‘await’ keyword in C# plays the role of the conductor’s baton, guiding tasks to wait elegantly while others complete. It helps maintain the rhythm and structure of your program, while ensuring that tasks do not block each other unnecessarily. Let’s look into its workings.

Here’s an example of using await with Task.Run :

In this code, we start a task that runs ten parts, each of which behaves as a separate, long-running task. Notice that we offload the work to a different task, then use await to tell our program to continue executing other tasks in the meantime. But isn’t this fascinating and a tad intimidating? Let’s dive deeper to understand how Task.Run and await work their magic.

Insight Into C# Start Task and Await Methods

Task.Run and await smoothly work together like duet musicians who know when to start and stop so that the music flows in harmony. Task.Run can start tasks and await can make the current method wait for the task to finish before proceeding. But how’s this possible?

In this example, we create a new task that simulates a time-consuming task, just like in our previous scenario. After it starts by using Start() , the rest of the code doesn’t wait for it to complete until await is reached. Once there, the method where this block of code is located will pause until the task completes. This effectively frees up the main thread while waiting for the task to finish.

Deep Dive into Run Async Task in C#

Asynchronous programming in C# is huge – just imagine a drummer playing different rhythms with each of his limbs. Run Async aids in creating responsive apps which remain interactive even when doing heavy computations. Take a deep breath, and let’s get into it.

Here, we kick off five tasks, each waiting around for one second to mimic lengthy computations. The await inside Task.Run means that the executing of the lambda we provided will pause until Task.Delay(1000) completes, then will resume executing the Console.WriteLine call. This all happens without blocking the main thread. The call to Task.WhenAll then waits for all the tasks in its argument to complete. This allows concurrent asynchronous tasks to be easily initiated and managed. So, isn’t this an effective way of creating a multitasking program while ensuring all tasks are completed successfully? Pretty stellar, don’t you think?

Let me extend the information.

.NET Core Tasks: Advancements and Aces

There’s a symphony playing in the .NET Core world, and Tasks are playing the lead role. With .NET Core, task handling has changed for the better, providing you with more control and flexibility than ever before.

But we’re not just going to talk about it—we’re going to get our hands dirty and write some code as well. Look at this piece:

Here, we’re creating a new task and then starting it. This asynchronous operation allows our application to stay responsive. More complex examples can see tasks perform various operations and return results as necessary, all fine-tuned to improve our program’s performance.

But how is this possible? What makes .NET Core task handling all that different from the .NET Framework?

Decoding the Importance of .NET Core Task in C#

To start, .NET Core has redefined the Task implementation altogether, making it more flexible, portable, and modifiable than the .NET Framework’s predecessor.

.NET Core introduced the concept of TaskCompletionSource . This allows us to create tasks that can be manually controlled, especially when it comes to signaling their completion. Do you have a callback-based asynchronous method you’d like to translate to Task Asynchronous Pattern (TAP)? TaskCompletionSource is your friend. Here’s a simple usage:

The last line, await tcs.Task; , will wait for the callback to execute. Then it will complete, freeing up our main application flow to resume operations. And this isn’t even the end of the cool stuff TaskCompletionSource can do— but I’ll leave you to explore more.

Furthermore, with the introduction of ValueTask in .NET Core 2.1, developers can handle scenarios where an operation often completes synchronously without allocating a new task. This way, we reduce overheads and improve performance, especially in high-throughput scenarios.

In the above example, if the input number is less than 0, we don’t need to queue any task or create a Task<int> . Instead, we create a ValueTask<int> that wraps an actual value, avoiding unnecessary allocations. In case of an async operation, we wrap a Task<int> .

These features and more have made .NET Core an excellent environment for efficient, high-performance task-based programming. Your tasks in your .NET Core applications can be more responsive and lightweight, leading to a more fulfilling user experience. After all, isn’t that what every programmer—and user—wants?

Implementing C# Periodical Task for Real-Time Applications

Imagine a coffee machine repeating its brewing task every morning or a server health-monitoring system running checks every few seconds. These are perfect examples of periodic tasks in the real world. In C#, creating periodic tasks allows you to automate these repetitive operations neatly and efficiently.

A simple example of a periodic task in C# using the Timer class might look like this:

In the code snippet, we’ve just generated a task that will write “Running periodic task…” in the console every 5 seconds. Time-based, repeating tasks are fundamental to numerous applications, covering a wide range of domains from health monitoring to automated machine operations. But how are these marvels strung together in C#? Let’s delve deeper.

Setting Up Periodic Tasks in C#: A Step-By-Step Guide

Creating periodic tasks in C# can be a bit tricky. The routine is similar to the trumpet player in a band playing the same note in a rhythmic pattern, creating a perfect harmony. Sounds soothing, right? But how can we achieve it in C#?

Let’s start with a basic example. Assume we want to monitor a server’s health by pinging it every 10 seconds. Here’s how you could set it up in C#:

In this example, the periodical task starts by setting up a timer object. A timer takes a delegate function that it will call every time the specified period elapses. Here, we’ve defined an asynchronous function that simulates a server health check. We then set the timer to fire immediately after creation ( TimeSpan.Zero ) and then every 10 seconds ( TimeSpan.FromSeconds ). Now, we’ve got a well-tuned trumpet playing our rhythmic pattern. But what if we want to scale that up and add an entire brass section?

Use of C# Run Method Async in Periodical Tasks

Introducing asynchronous methods into the mix can empower our periodic task ensemble. Asynchronous periodic tasks can make your .NET applications more responsive as they ensure tasks waiting for things (like IO operations or other time-consuming tasks) don’t block the primary thread.

Let’s say you need to fetch and process customer data every hour for your application. Below is an example of how you could utilize Task.Run , async , and await to create a non-blocking periodic task in C#:

See the concert of async programming now in full swing? In this example, the Timer is initialized to run the ProcessCustomerDataAsync method every hour. We use Task.Run to execute this method on a separate thread, ensuring our primary thread doesn’t get blocked. Now, we’ve not only got our trumpet playing but a complete brass section making sweet music, all in perfect harmony.

Discovering the New Task Async C#

New Async Tasks in C# are the power tools of your concurrency toolbox. They allow developers to split time-consuming operations from the main thread and run them in the background. It’s like having an assistant who takes over your tedious tasks, leaving you free to focus on critical issues.

In this code snippet, we use new Task to create a task that performs an operation asynchronously. The task waits for a second (mimicking a long-running task) and then writes to the console. This separation takes the load off the main thread, making your application more responsive.

But the async keyword’s potential does not stop here. Let’s look at another example, handling multiple async tasks.

This script demonstrates the magic of handling multiple async tasks. Task.WhenAll efficiently waits for all the provided tasks to complete.

The Impact of New Task Async Methods in C#

The advent of async methods in C# has enhanced the control developers have over the execution flow, resulting in code that is not just efficient but also clean and readable. Async methods allow tasks to be non-blocking, ensuring your application remains responsive even during heavy computation or I/O operations.

In this example, we chain two tasks. The ContinueWith method signals Task 2 to start once Task 1 finishes, demonstrating how we can decompose complex operations into smaller, manageable tasks and run them in a controlled, sequential manner using async features.

Task.Run Async Await C# Techniques

When integrating async and await into Task.Run , we uncover various techniques to optimize multitasking. The await keyword lets the system know that the method can return at this point, freeing up the thread to handle other tasks.

Here, we use Task.Run along with async and await to start an operation that iterates 100 times. However, at each iteration, the task itself is not blocking; instead, it gives up control after each loop, allowing the thread to execute other tasks during the delay.

This flexibility of Task.Run in combination with async and await empowers us to construct complex programs where multiple tasks can execute concurrently, without blocking the main thread, making the most efficient use of system resources.

Owning Asynchronous Programming with C# Run Async

Asynchronous programming is like playing jazz – it’s all about breaking the monotony, improvising on the go, and most importantly, ensuring harmony despite the haphazardness. ‘Run Async’ in C# channels this spirit of jazz into your .NET applications, making them highly responsive and performant.

The real power of async programming lies in its ability to improve the execution flow. When a process encounters a task expected to take a long time, instead of just keeping everything on hold it delegates the task, moves on, and later comes to check on it. This makes your applications quite the juggler!

Conversely, understanding async programming requires understanding how async and await work together, like perfect dance partners, to accomplish this.

In this orchestrating script, ‘Task.Run’ starts an asynchronous task that first waits for a second and then draws @”First task finished!” on the console. Immediately after, it embarks on another long-running task of waiting for two seconds and then calls out “Second task finished!”. This interaction between run, async and await allows your application to efficiently handle multiple tasks concurrently.

Advanced Scenarios in

As programmers, we love to push the limits, don’t we? And guess what, async programming with Task.Run is just the canvas for us to test our creative boundaries.

Consider a scenario where you have to fetch data from an API and at the same time perform some local file operations. How would our artist, Task.Run , paint this?

In this masterpiece, Task.Run creates two separate tasks. One task mimics fetching data from an API and another for local file operations. The main thread doesn’t wait around aimlessly. It moves on to the next lines of codes. The Task.WhenAll method makes sure all the tasks have completed their roles.

The Balancing Act: Task Run C# Async and Error Handling

Any good performance needs to address hiccups with elegance and async programming is no exception. Exception handling is key to this.

Let’s say we are doing multiple tasks concurrently and one of them hits a snag. How do we handle this elegantly, without letting the whole performance collapse?

In this harmonious piece, we’ve introduced a try-catch block to handle any discordance. If a problem occurs inside the asynchronous task (in this case, we’re throwing an exception), it gets caught and handled gracefully.

Async and await in C#, used with Task.Run , allow you to create rhythmic melodic pieces with your code by easily allowing concurrent execution of tasks. And handling errors within this concurrency adds the right amount of grace and fluidity to your performance.

Ready for the encore? Success in async programming, much like music, comes from mastering the basics and then consistently practicing and experimenting. So, break a leg and keep coding.

You May Also Like

Optional Parameters in C#: What You Need to Know

Optional Parameters in C#: What You Need to Know

Programming in C# often requires flexibility and simplicity ...

What is Lock Keyword in C#? Main Usages

What is Lock Keyword in C#? Main Usages

IndexUnderstanding the C# Lock Keyword Can’t tell a lock fro...

Enumerate in C#: Detailed Explanation

Enumerate in C#: Detailed Explanation

Desperate to decode the mystery that is enumeration in C#? I...

Creating a JSON Class in C#: Detailed Guide

Creating a JSON Class in C#: Detailed Guide

In the world of application development, manipulation of dat...

Static Class in C#: How to Use It?

Static Class in C#: How to Use It?

Hello there, future C# aficionado! It’s time to roll down th...

DateTime Formatting in C#: Dev Guide

DateTime Formatting in C#: Dev Guide

Have you ever gotten frustrated handling dates and times in ...

Leave a reply

Comments (1).

Spaceclick

7 Ways to create tasks in .NET C#

If you are programming in C# (.NET) and you are in the situation of having to create and execute a Task in a new thread , you can proceed in many different ways.

First you add the following using directive:

 using System.Threading.Tasks;

Use one of the following methods:

  • Classic Method
  • Using Delegate
  • Using Action
  • Using Lambda with no method
  • Using Lambda with a method
  • Using Run  (.NET 4.5)
  • Using FromResult  (.NET 4.5)

Remember that it is not possible to start a Task that has already been executed.

In this case (if you have to re-execute the same Task) you will have to re-initialize the Task before you can re-execute it.

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

Parallel.ForEachAsync() and Task.Run() With When.All in C#

Posted by Aneta Muslic | Feb 20, 2024 | 0

Parallel.ForEachAsync() and Task.Run() With When.All in C#

Parallel programming is a common and broad concept in the .NET world. In this article, we compare two well-known methods we use to achieve it when running a repetitive asynchronous task. We take a look at how they behave under the hood and compare the pros and cons of each one.

Let’s make a start.

Parallel Programming

In general, parallel programming involves using multiple threads or processors to execute tasks concurrently. It aims to improve performance and responsiveness by dividing tasks into smaller parts that can be processed simultaneously. 

Apart from improving performance and responsiveness, there are additional advantages when using parallel programming. Firstly, by breaking tasks into concurrent subtasks, we can effectively reduce overall execution time. One additional benefit is throughput enhancement as a result of handling multiple tasks simultaneously. Also, running tasks in parallel helps us ensure scalability since it efficiently distributes tasks across processors. This allows performance to scale seamlessly when adding resources.

One more thing we should take into consideration when working with parallel programming is which kind of processes we are trying to parallelize. In this article, we will mention I/O-bound and CPU-bound ones.  

Become a patron at Patreon!

I/O bound processes are processes where the computational duration is determined by the time spent awaiting input/output operations, an example of this is a database call. On the other hand, we have CPU-bound processes. In this case, the performance of the CPU determines the task duration, an example is a method that does some heavy numerical calculations.

Now that we have a quick primer about parallel programming and different types of processes, let’s quickly set everything up and see it in action.

Setting up Async Methods

Since we already have a great article going more in-depth on How to Execute Multiple Tasks Asynchronously , here we will only create a baseline for the Task.WhenAll() method which we will modify when comparing the two approaches.

We start with the default web-API project and expand the WeatherForecastController method with an asynchronous method that runs multiple times:

In the context of types of processes, AsyncMethod() emulates the I/O-bound process and the task delay represents the waiting time of a sub-system response.

After we set everything up, let’s see how to execute these tasks in parallel.

Use Task.WhenAll

First, we need to refactor the GetWeatherForecastWhenAll() method to use the Task.WhenAll() method. It takes an enumerable of tasks and returns a new completed task once all the individual tasks in the collection finish running:

We define an empty list of tasks. Next, we call AsyncMethod() three times without the await keyword. This starts executing these tasks one after another without waiting for them to complete . This is exactly what we want since we add those tasks to our tasks list and use Task.WhenAll() to wait for all of them to complete.

Lastly, when all the tasks are completed, we flatten the combinedResults variable that holds the results and return the result to the user.

We need to keep thread usage in mind when we use parallel execution of tasks. Starting too many threads at once increases context-switching overhead and may impact overall application efficiency. Also, we don’t want to block the main thread. So let’s see how we can get a better understanding of how this method works under the hood regarding threads.

Thread Processing

We start by adding logging to the threads:

Here, we add a Console.WriteLine() statement at the beginning and end of each method. There, we print on which thread methods start and end by using Environment.CurrentManagedThreadId .

Now, if we execute our request, in the output window we can see how threads behave:

Let’s break this down to understand what happens.

When we send an HTTP request, a thread from the thread pool gets assigned to handle it. In our case, it is thread number 16. Then, when we invoke our async methods and we don’t use the await keyword, tasks will usually start executing on the same thread, i.e., 16.

However, when an asynchronous operation encounters the await keyword, in our case await on Task.WhenAll() , it releases the current thread to the thread pool during the waiting period for the task to be completed. When the awaiting operation completes and we want to return the result, the continuation might not necessarily resume on the original thread. That is why we see some of the tasks finish on different threads than they start on.

Besides creating a task by not using the await keyword we can also use Task.Run() method, so let’s take a look at it.

Use Task.Run With Task.WhenAll

By using the Task.Run()  method to execute tasks, we make sure that each new task executes on a separate thread :

Here, we use the Task.Run() method to execute AsyncMethod() three times in a row. Again, by skipping the await keyword we are not awaiting any method to complete, but we run them in parallel and on Task.WhenAll() await their results.

Now, let’s retake a look at the output logs when executing the request:

This time, we see that each new task starts its execution on a new thread. We expect this behavior when using Task.Run() since its purpose is to offload work from the current thread. Same as in the previous example due to the async/await nature and thread pool assigning threads, tasks finish on different threads than they originally start on.

Using Task.Run() requires caution as it might have some drawbacks. Since it offloads work to a new thread, any time it deals with a large number of tasks it can create a large number of threads, each consuming resources and possibly causing thread pool starvation.

Now that we have seen how we can explicitly offload each task to a new thread, let’s look at how we can use another method to perform these tasks in parallel.

Using Parallel.ForEachAsync

Another way we parallelize this work is to use the Parallel.ForEachAsync() method:

First, we set the MaxDegreeOfParallelism value. With this setting, we define how many concurrent operations run. If not set, it uses as many threads as the underlying scheduler provides . To determine this value for a CPU process start with the Environment.ProcessorCount . For I/O-bound processes, this value is harder to determine since it depends on the I/O subsystem, which includes network latency, database responsiveness, etc. So when working with I/O bound processes, we need to do testing with different values to determine the best value for maximum parallelization.

After, we define a ConcurrentBag for our results, which is a thread-safe collection since we use parallel execution of tasks and handle results in a loop. Allowing us to safely modify the collection without worrying about concurrency modification exceptions. Lastly, we set up Parallel.ForEachAsync() method to run three times with set options, and inside the loop, we await each result and add it to the resultBag .

One thing to mention when using the Parallel.ForEachAsync() method is that it has its underlying partitioning. This partitioning divides the input data into manageable batches and assigns each batch to a different thread for parallel processing. The exact size of the batches is determined dynamically by the framework based on factors such as the number of available processors and the characteristics of the input data. So by defining the MaxDegreeOfParallelism , we define the number of batched tasks that execute concurrently.

Regarding thread usage, since we are not explicitly altering thread assignments, threads get assigned as they usually do in the classic async/await process. One difference with the Task.WhenAll() thread usage is that most likely every task starts on its thread since we use the await keyword for each call inside the loop.

Now, let’s take a look at how the Task.Run() method behaves in this case.

Using Task.Run With Parallel.ForEachAsync

Let’s modify our method to use Task.Run() for generating tasks:

However, this may not be the best approach in this case. As we already saw, Parallel.ForEachAsync() has a built-in partitioner that creates batches of tasks and processes them in a single thread. But by using Task.Run() we offload each task into its thread. So using Task.Run() in this case, undermines the benefit of using Parallel.ForEachAsync() for chunking tasks and using fewer threads.

One more thing we may encounter when trying to parallelize the tasks is the usage of the Parallel.ForEach() method.

Pitfalls to Avoid With Parallel.ForEach

The Parallel.ForEach() method, while similar to Parallel.ForEachAsync() , lacks the designed capability to handle asynchronous work.  However, we can still encounter some examples of its usage with asynchronous tasks.

So let’s quickly check on why these approaches may not be the best workarounds and see their drawbacks.

One common thing we can see is forcing awaiting the result in synchronous code by using GetAwaiter () . GetResult() :

We should avoid this approach since by using GetAwaiter().GetResult() we block the calling thread, which is an anti-pattern of async/await . This may cause issues in deadlocks, decreased performance, and loss of context-switching benefits.

Another approach involves using async void:

In this approach, we have another anti-pattern, and that is the usage of async/void . This is a known bad practice with several reasons to avoid it. O ne such reason is that we cannot catch exceptions in the catch block.

As we can see, both of these approaches involve the use of anti-patterns to make Parallel.ForEach() them compatible with asynchronous methods. Since neither of them is a recommended way to implement parallelization, with the introduction of Parallel.ForEachAsync() in .NET 6 we have a preferable method for working with async tasks in a for-each loop.

Now that we took a look at what not to do, let’s sum up everything we’ve learned so far!

When to Use Which Approach?

As with everything in programming, how we use the knowledge from this article depends on the application’s specific requirements. Nevertheless, when choosing the right method, we should consider several factors.

When talking about CPU-bound tasks that can benefit from parallelization, the use of Parallel.ForEachAsync() stands out. Its main benefit is that it efficiently distributes the workload across multiple processor cores. Also, by setting the MaxDegreeOfParallelism we control the concurrency level we want to impose. And as we saw we can easily determine that value.

On the other hand, when dealing with I/O-bound tasks, where operations involve waiting for external resources, Task.WhenAll() becomes a preferable choice. It allows us to execute multiple asynchronous tasks concurrently, without blocking the calling thread. This makes it an efficient option for scenarios like database queries or network requests. Another benefit is that we don’t need to process results inside the loop, but we can wait on all of them and manipulate the results when they are complete.

However, it’s important to note that Task.WhenAll() lacks a built-in partitioner, and its use in a loop without proper throttling mechanisms may result in the initiation of an infinite number of tasks. So depending on the number of tasks we are executing it may be necessary to create our partition strategy or opt for Parallel.ForEachAsync() a solution.

One more thing we mentioned is initializing tasks using Task.Run() . We can use this approach when we want to have explicit control over threading but keep in mind that it can potentially lead to thread pool starvation if too many threads start at once. 

In this article, we look at two methods we use to execute repetitive tasks in parallel. We saw how both methods under the hood use threads and partition the given tasks. Also, we saw what are the differences when using the Task.Run() and how it behaves with both options. Lastly, we provide guidance on which approach is most suitable in different scenarios.

guest

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

does task create a new thread c#

This browser is no longer supported.

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

Use Visual C# to create a thread

  • 1 contributor

You can write multithreaded applications in Microsoft Visual C# .NET or in Visual C#. This article describes how a simple Visual C# application can create and manage threads.

Original product version:   Visual C# Original KB number:   815804

Requirements

The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:

  • Windows or Windows Server
  • Visual C# .NET or Visual C#

This article assumes that you are familiar with the following topics:

  • Visual C# programming
  • Visual Studio .NET Integrated Development Environment (IDE) or Visual Studio IDE

This article refers to the .NET Framework Class Library namespace System.Threading .

Create a Visual C# application with threads

Start Visual Studio .NET, Visual Studio, or Visual C# Express Edition.

Create a new Visual C# Windows Application project named ThreadWinApp .

Add a Button control to the form. By default, the button is named Button1 .

Add a ProgressBar component to the form. By default, the progress bar is named ProgressBar1 .

Right-click the form, and then click View Code .

Add the following statement to the beginning of the file:

Add the following button1_Click event handler for Button1:

Add the following variable to the Form1 class:

Add the following method to the Form1 class:

This is the code that underlies the thread. This code is an infinite loop that randomly increments or decrements the value in ProgressBar1, and then waits 100 milliseconds before it continues.

Add the following Form1_Load event handler for Form1. This code creates a new thread, makes the thread a background thread, and then starts the thread.

Verify that it works

Build and run the application. Notice that the value in ProgressBar1 changes randomly. This is the new thread in operation.

To demonstrate that the main thread is independent of the thread that changes the value of ProgressBar1, click the button on the form. You receive a dialog box with the following error message:

This is the main thread

Wait for input. Notice that the value in ProgressBar1continues to change.

Troubleshoot

In more complex applications, make sure that you synchronize multiple threads when you access shared variables. For more information, see the lock statement and related topics in the Visual C# .NET online help documentation.

For more information, see Thread Class .

Was this page helpful?

Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see: https://aka.ms/ContentUserFeedback .

Submit and view feedback for

Additional resources

IMAGES

  1. C# ThreadPool and Its Task Queue Explained (With Example)

    does task create a new thread c#

  2. C# program to create a new thread

    does task create a new thread c#

  3. Creating Simple Threads in C# and Role of Thread.Join() With Examples

    does task create a new thread c#

  4. How to Run Code in a New Thread in C#

    does task create a new thread c#

  5. Creating Simple Threads in C# and Role of Thread.Join() With Examples

    does task create a new thread c#

  6. Task And Thread In C#

    does task create a new thread c#

VIDEO

  1. Method Overloading in OOP C#8(Darija)

  2. Thread → Task. Многопоточность и Асинхронность

  3. The .NET Thread Pool Starvation Detection and Improve performance and stability of sync

  4. Crawl data từ website đa luồng với C#. Async await task thread và parallel

  5. 83 C# C Sharp Thread Object

  6. 87 C# C Sharp Threading Naming Thread

COMMENTS

  1. c#

    Short answer: No. Tasks are executed via a thread pool. Here'r a blog about this: Threads vs. Tasks: A task does not create its own OS thread. Instead, tasks are executed by a TaskScheduler; the default scheduler simply runs on the ThreadPool Share Improve this answer Follow answered Aug 22, 2014 at 13:01 Matt 6,050 25 37

  2. Task Class (System.Threading.Tasks)

    Definition Remarks Constructors Properties Methods Explicit Interface Implementations Extension Methods Applies to Thread Safety See also Definition Namespace: System. Threading. Tasks Assembly: System.Runtime.dll Represents an asynchronous operation. C# public class Task : IAsyncResult, IDisposable Inheritance Object Task Derived System.

  3. Task And Thread In C#

    22 This article describes the definition and uses of Task And Thread: What is Task? What is Thread? Why do we need Task? Why do we need Thread? How to implement Task How to implement Thread Differences between Task And Thread What is Task in C#? .NET framework provides Threading.Tasks class to let you create tasks and run them asynchronously.

  4. Task-based asynchronous programming

    Tasks provide two primary benefits: More efficient and more scalable use of system resources. Behind the scenes, tasks are queued to the ThreadPool, which has been enhanced with algorithms that determine and adjust to the number of threads. These algorithms provide load balancing to maximize throughput.

  5. Six ways to initiate tasks on another thread in .NET

    You can create a new Thread object, set up various properties such as the method to execute, thread name, and priority, and then start the thread. var t = new Thread (BackgroundTask); t.Name = "My Thread" ; t.Priority = ThreadPriority.AboveNormal; t.Start ( "Thread" );

  6. Tasks vs Threads in C#

    t.Start(); // ... t.Join(); Here we are spawning a new thread to do a "complex" computation. When we call the Join () method, the current thread waits until the target thread terminates. There is nothing wrong with this code, but we should be aware that spawning a thread has a cost.

  7. How Do Tasks Work In C#? Async/Background Threads

    How Do Tasks Work In C#? Async/Background Threads By Anthony Heddings Published Aug 24, 2020 If you want to make web requests in C#, or just want to do some background processing, you'll need to use asynchronous background tasks to not block up the main thread. Readers like you help support How-To Geek.

  8. Task.Run Method (System.Threading.Tasks)

    The Run (Action, CancellationToken) method is a simpler alternative to the TaskFactory.StartNew (Action, CancellationToken) method. It creates a task with the following default values: Its CreationOptions property value is TaskCreationOptions.DenyChildAttach. It uses the default task scheduler.

  9. C# Threading and Multithreading: A Guide With Examples

    You instantiate an object of the Thread class, passing it a ThreadStart delegate which points to the method to be executed in the new thread, and then call the Start () method. Here's an example: void MyFunction () { // Some work here } Thread myThread = new Thread (new ThreadStart (MyFunction)); myThread.Start ();

  10. How to Run Code in a New Thread in C#

    How to Run Code in a New Thread in C# Posted by Bartosz Jarmuż | Updated Date Dec 21, 2021 | 2 Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn how to create a full production-ready ASP.NET Core API using only the latest .NET technologies.

  11. How To Use Task.Run in C# for Multithreading

    That's exactly what Task.Run in C# does. It's a method that allows us to start a task on a separate thread from the ThreadPool, enhancing the performance and responsiveness of your applications. Loading code snippet... This code snippet runs a lambda expression on a separate thread, leaving the main thread free to continue executing other tasks.

  12. c#

    First question: When I click the button, it will Call DoSomething and await a Task that creates a Thread from the threadpool by calling Task.Run ( if I am not mistaken ) and all of this runs asynchronously. So I achieved creating a thread that does my work but doing it asynchronously?

  13. C#

    Task.Run (Action): Task.Run () gives the Action to run on the ThreadPool, which takes a thread from the ThreadPool and runs our code on that thread as per schedule and availability. Once the ...

  14. Creating threads and passing data at start time

    Creating a new Thread object creates a new managed thread. The Thread class has constructors that take a ThreadStart delegate or a ParameterizedThreadStart delegate; the delegate wraps the method that is invoked by the new thread when you call the Start method. Calling Start more than once causes a ThreadStateException to be thrown.

  15. 7 Ways to create tasks in .NET C#

    If you are programming in C# (.NET) and you are in the situation of having to create and execute a Task in a new thread, you can proceed in many different ways. First you add the following using directive: using System.Threading.Tasks; Use one of the following methods: Classic Method Task.Factory.StartNew(() => { Console.WriteLine("Hello […]

  16. The managed thread pool

    Using the thread pool. The easiest way to use the thread pool is to use the Task Parallel Library (TPL).By default, TPL types like Task and Task<TResult> use thread pool threads to run tasks.. You can also use the thread pool by calling ThreadPool.QueueUserWorkItem from managed code (or ICorThreadpool::CorQueueUserWorkItem from unmanaged code) and passing a System.Threading.WaitCallback ...

  17. Parallel.ForEachAsync() and Task.Run() With When.All in C#

    That is why we see some of the tasks finish on different threads than they start on. Besides creating a task by not using the await keyword we can also use Task.Run() method, so let's take a look at it. Use Task.Run With Task.WhenAll. By using the Task.Run() method to execute tasks, we make sure that each new task executes on a separate thread:

  18. Azure OpenAI Service announces Assistants API, New Models for

    Building customizable, purpose-built AI that can sift through data, suggest solutions, and automate tasks just got easier. The Assistants API supports persistent and infinitely long threads. This means that as a developer you no longer need to develop thread state management systems and work around a model's context window constraints.

  19. c#

    How to create a thread? Ask Question Asked 14 years, 9 months ago Modified 4 years, 11 months ago Viewed 121k times 67 The method below is what I want to be done in that thread: public void Startup (int port,string path) { Run (path); CRCCheck2 (); CRCCheck1 (); InitializeCodeCave ( (ushort)port); }

  20. Using threads and threading

    You create a new thread by creating a new instance of the System.Threading.Thread class. You provide the name of the method that you want to execute on the new thread to the constructor. To start a created thread, call the Thread.Start method.

  21. How to create a thread by using Visual C#

    Use Visual C# to create a thread Article 05/07/2022 1 contributor Feedback In this article Requirements Create a Visual C# application with threads Troubleshoot References You can write multithreaded applications in Microsoft Visual C# .NET or in Visual C#. This article describes how a simple Visual C# application can create and manage threads.