简体   繁体   中英

Replacing threads with tasks

New to threading and tasks here :)

So, I wrote a simple threading program that creates a few threads and runs them asynchronously then waits for them to finish.

I then changed it to a Task. The code does exactly the same thing and the only change is I change a couple of statements.

So, two questions really:

  1. In the below code, what is the difference?
  2. I'm struggling to figure out async/await. How would I integrate it into the below, or given all examples seem to be one method calls another that are both async/await return is this a bad example of using Task to do background work?

Thanks.

    namespace ConsoleApp1
    {
            class Program
            {
                static void Main(string[] args)
                {
                    ThreadSample();
                    TaskSample();
                }

                private static void ThreadSample()
                {
                    Random r = new Random();
                    MyThreadTest[] myThreads = new MyThreadTest[4];
                    Thread[] threads = new Thread[4];

                    for (int i = 0; i < 4; i++)
                    {
                        myThreads[i] = new MyThreadTest($"T{i}", r.Next(1, 500));
                        threads[i] = new Thread(new ThreadStart(myThreads[i].ThreadSample));
                        threads[i].Start();
                    }
                    for (int i = 0; i < 4; i++)
                    {
                        threads[i].Join();
                    }

                    System.Console.WriteLine("Finished");
                    System.Console.ReadKey();
                }

                private static void TaskSample()
                {
                    Random r = new Random();
                    MyThreadTest[] myTasks = new MyThreadTest[4];
                    Task[] tasks = new Task[4];
                    for (int i = 0; i < 4; i++)
                    {
                        myTasks[i] = new MyThreadTest($"T{i}", r.Next(1, 500));
                        tasks[i] = new Task(new Action(myTasks[i].ThreadSample));
                        tasks[i].Start();
                    }
                    for (int i = 0; i < 4; i++)
                    {
                        tasks[i].Wait();
                    }

                    System.Console.WriteLine("Finished");
                    System.Console.ReadKey();
                }

            }

            class MyThreadTest
            {
                private string name;
                private int interval;

                public MyThreadTest(string name, int interval)
                {
                    this.name = name;
                    this.interval = interval;
                    Console.WriteLine($"Thread created: {name},{interval}");
                }

                public void ThreadSample()
                {
                    for (int i = 0; i < 5; i++)
                    {
                        Thread.Sleep(interval);
                        Console.WriteLine($"{name} At {i} on thread {Thread.CurrentThread.ManagedThreadId}");
                    }
                }

                public void TaskSample()
                {
                    for (int i = 0; i < 5; i++)
                    {
                        Thread.Sleep(interval);
                        Console.WriteLine($"{name} At {i} on thread {Thread.CurrentThread.ManagedThreadId}");
                    }
                }
            }
    }

The Task Parallel Library (TPL) is an abstraction, and you shouldn't try to compare Tasks directly with threads. The Task object represents the abstract concept of an asynchronous task - a piece of code that should execute asynchronously and which will either complete, fault (throw an exception) or be canceled. The abstraction means you can write and use such tasks without worrying too much about exactly how they're executed asynchronously. There are lots of useful things like ContinueWith() you can use to compose, sequence and otherwise manage tasks.

Threads are a much lower level concrete system facility that can be used to run code asynchronously, but without all the niceties you get from the Task Parallel Library (TPL). If you want to sequence tasks or anything like that, you have to code it yourself.

In your example code, you're not actually directly creating any threads. Instead, the Action s you've written are being executed by the system thread pool. Of course, this can be changed. The TPL abstraction layer provides the TaskScheduler class which you can extend - if you have some special way of running code asynchronously, you can write a TaskScheduler to use TPL with it.

async / await is 100% compiler sugar. The compiler decomposes an async method into chunks, each of which becomes a Task , and those chunks execute sequentially with the help of a state machine, all generated by the compiler. One caution: by default, await captures the current SynchronizationContext and resumes on that context. So if you're doing this in WPF or Windows Forms, your continuation code after an await isn't actually running in a thread at all, it's running on the UI thread. You can disable this by calling ConfigureAwait(false) . Really, async / await are primarily intended for asynchronous programming in UI environments where synchronization to a main thread is important.

  1. In the below code, what is the difference?

The difference is big. Task is a unit of work, which will use a thread(s) from thread pool allocated based on estimated amount of work to be computed. if there is another Task , and there are paused, but still alive threads, in the pool, instead of spinning of a new thread (which is very costy) it reuses already created one. Multiple tasks can end-up using the same thread eventually (non simultaneously obviously)

Task based parallelism in nutshell is: Tasks are jobs, ThreadPool provisions resource to complete those jobs. Consequence, more clever, elastic thread/resource utilization, especially in general purpose programs targeting variety of execution environments and resource availability, for example VMs on cloud.

  1. I'm struggling to figure out async/await.

await implied dependency of one task from another. If in your case you don't have it, other than waiting all of them to complete, what are you doing is pretty much enough. If you need, you can achieve that with TPL too via, for example, ContinueWith

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM