繁体   English   中英

用任务替换线程

[英]Replacing threads with tasks

这里是线程和任务的新手:)

因此,我编写了一个简单的线程程序,该程序创建了几个线程并异步运行它们,然后等待它们完成。

然后,我将其更改为任务。 该代码做完全相同的事情,唯一的变化是我更改了两个语句。

因此,确实有两个问题:

  1. 在下面的代码中,有什么区别?
  2. 我正在努力找出异步/等待。 我如何将其集成到下面,或者假设所有示例似乎都是一个方法调用另一个都异步/等待返回的方法,这是使用Task进行后台工作的一个不好的例子吗?

谢谢。

    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}");
                    }
                }
            }
    }

任务并行库(TPL)是一个抽象,您不应该尝试直接将任务与线程进行比较。 Task对象代表异步任务的抽象概念-一段应该异步执行的代码,它将完成,出错(引发异常)或被取消。 抽象意味着您可以编写和使用此类任务,而不必过多地担心它们如何异步执行。 有很多有用的东西,例如ContinueWith() ,可以用来组成,排序和管理任务。

线程是一种底层系统系统工具,可用于异步运行代码,但没有从任务并行库(TPL)获得的所有好处。 如果要排序任务或类似的任务,则必须自己编写代码。

在示例代码中,您实际上并没有直接创建任何线程。 相反,您编写的Action由系统线程池执行。 当然,可以更改。 TPL抽象层提供了可以扩展的TaskScheduler类-如果您具有某种异步运行代码的特殊方式,则可以编写TaskScheduler来与它一起使用TPL。

async / await是100%编译器糖。 编译器将async方法分解为块,每个块都成为Task ,并且这些块在状态机的帮助下顺序执行,所有这些都由编译器生成。 注意事项:默认情况下, await捕获当前的SynchronizationContext并在该上下文上恢复。 因此,如果您在WPF或Windows窗体中执行此操作,则await后的继续代码实际上根本不在线程中运行,而是在UI线程上运行。 您可以通过调用ConfigureAwait(false)禁用此功能。 实际上, async / await主要用于在与主线程同步很重要的UI环境中进行异步编程。

  1. 在下面的代码中,有什么区别?

差别很大。 Task是工作单元,它将使用线程池中的一个或多个线程,该线程是根据要计算的估计工作量分配的。 如果有另一个Task ,并且池中有暂停但仍处于活动状态的线程,而不是旋转一个新线程(这非常昂贵),而是重用已经创建的一个线程。 多个任务最终可能最终使用同一线程结束(显然不是同时发生)

简而言之,基于任务的并行性是:任务就是工作,ThreadPool提供资源来完成这些工作。 结果,更加灵活,灵活的线程/资源利用率,尤其是在针对各种执行环境和资源可用性的通用程序中,例如云上的VM。

  1. 我正在努力找出异步/等待。

await暗示一项任务与另一项任务的依赖关系。 如果您没有这种情况,除了等待所有步骤完成之外,您正在做什么就足够了。 如果需要,您也可以通过TPL来实现,例如ContinueWith

暂无
暂无

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

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