简体   繁体   English

用任务替换线程

[英]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? 我如何将其集成到下面,或者假设所有示例似乎都是一个方法调用另一个都异步/等待返回的方法,这是使用Task进行后台工作的一个不好的例子吗?

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. 任务并行库(TPL)是一个抽象,您不应该尝试直接将任务与线程进行比较。 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. Task对象代表异步任务的抽象概念-一段应该异步执行的代码,它将完成,出错(引发异常)或被取消。 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. 有很多有用的东西,例如ContinueWith() ,可以用来组成,排序和管理任务。

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). 线程是一种底层系统系统工具,可用于异步运行代码,但没有从任务并行库(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. 相反,您编写的Action由系统线程池执行。 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. TPL抽象层提供了可以扩展的TaskScheduler类-如果您具有某种异步运行代码的特殊方式,则可以编写TaskScheduler来与它一起使用TPL。

async / await is 100% compiler sugar. async / await是100%编译器糖。 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. 编译器将async方法分解为块,每个块都成为Task ,并且这些块在状态机的帮助下顺序执行,所有这些都由编译器生成。 One caution: by default, await captures the current SynchronizationContext and resumes on that context. 注意事项:默认情况下, await捕获当前的SynchronizationContext并在该上下文上恢复。 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. 因此,如果您在WPF或Windows窗体中执行此操作,则await后的继续代码实际上根本不在线程中运行,而是在UI线程上运行。 You can disable this by calling ConfigureAwait(false) . 您可以通过调用ConfigureAwait(false)禁用此功能。 Really, async / await are primarily intended for asynchronous programming in UI environments where synchronization to a main thread is important. 实际上, async / await主要用于在与主线程同步很重要的UI环境中进行异步编程。

  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. Task是工作单元,它将使用线程池中的一个或多个线程,该线程是根据要计算的估计工作量分配的。 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. 如果有另一个Task ,并且池中有暂停但仍处于活动状态的线程,而不是旋转一个新线程(这非常昂贵),而是重用已经创建的一个线程。 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. 简而言之,基于任务的并行性是:任务就是工作,ThreadPool提供资源来完成这些工作。 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. 结果,更加灵活,灵活的线程/资源利用率,尤其是在针对各种执行环境和资源可用性的通用程序中,例如云上的VM。

  1. I'm struggling to figure out async/await. 我正在努力找出异步/等待。

await implied dependency of one task from another. await暗示一项任务与另一项任务的依赖关系。 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 如果需要,您也可以通过TPL来实现,例如ContinueWith

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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