Task(System.Threading.Task)和Thread之间的区别

时间:2012-02-29 04:00:34

标签: c# .net task-parallel-library

据我所知,Task&线程是在线程池中发生的任务,而线程是我需要自己管理的东西..(并且该任务可以在他的任务结束时取消并返回到线程池)

但在某些博客中,我读到如果操作系统需要创建任务并创建thread =>创建(和销毁)任务会更容易。

有人可以解释为什么创建任务很简单那个线程?

(或许我在这里遗漏了一些东西......)

5 个答案:

答案 0 :(得分:19)

当你说任务是System.Threading.Task时,认为你正在谈论的是什么。如果是这种情况,那么你可以这样思考:

  • 程序可以有很多线程,但处理器核心一次只能运行一个线程。
    • 线程 非常 价格昂贵,在正在运行的线程之间切换也非常昂贵。
    • 所以......有成千上万的线程做东西效率低下。想象一下,如果你的老师给你 10,000个任务要做。你花了很多时间在他们之间骑车,你永远不会做任何事情。如果您启动太多线程,CPU也会发生同样的事情。

为了解决这个问题,.NET框架允许您创建任务。任务是捆绑到对象中的一些工作,它们允许您执行有趣的操作,例如捕获工作的输出并将工作链连接在一起(首先转到商店,然后买一本杂志。)

任务计划在线程池上。具体的线程数取决于所使用的调度程序,但默认调度程序会尝试选择一些线程,这些线程最适合您拥有的CPU核心数以及任务实际使用CPU时间的时间。如果您愿意,您甚至可以编写自己的调度程序来执行特定操作,例如确保该调度程序的所有任务始终在单个线程上运行。

因此,将“任务”视为待办事项列表中的项目。你可能一次可以做5件事,但如果你的老板给你10000,他们会在你的收件箱堆积,直到你做的前5个完成。任务和ThreadPool之间的区别在于,任务(如前所述)可以让您更好地控制不同工作项之间的关系(想象将多个指令装订在一起的待办事项),而ThreadPool只允许您排队一堆单独的单项目(功能)。

答案 1 :(得分:11)

您正在听到两种不同的任务概念。第一个是工作的概念,第二个是工作的概念。

很久以前(用计算机术语),没有线程。程序的每个运行实例都称为一个进程,因为它只是一个接一个地执行一个又一个,直到它退出。这将过程的直观概念与工厂装配线的一系列步骤相匹配。操作系统管理进程抽象。

然后,开发人员开始向工厂添加多条装配线。现在,程序可以同时执行多个操作,并且库或(更常见的是)操作系统将管理每个线程内的步骤的调度。线程是一种轻量级进程,但线程属于进程,进程中的所有线程共享内存。另一方面,多个进程不能混淆彼此的记忆。因此,Web服务器中的多个线程都可以访问有关连接的相同信息,但Word无法访问Excel的内存中数据结构,因为Word和Excel作为单独的进程运行。将进程作为一系列步骤的想法与具有线程的进程模型并不真正匹配,因此有些人将“抽象以前称为进程”称为任务。这是您在博客文章中看到的第二个任务定义。请注意,很多人仍然使用“进程”这个词来表示这一点。

嗯,随着线程变得越来越普遍,开发人员在它们之上添加了更多的抽象,以使它们更容易使用。这导致了线程池的兴起,这是一个由库管理的线程池“池”。您将库传递给作业,库选择一个线程并在该线程上运行作业。 .NET框架有一个线程池实现,当你第一次听说“任务”时,文档真的意味着你传递给线程池的工作。

从某种意义上说,文档和博客文章都是正确的。任务一词的超载是令人遗憾的混乱之源。

答案 2 :(得分:8)

线程已经成为.Net的一部分v1.0,任务在.Net 4.0中发布的任务并行库TPL中引入。

您可以将Task视为Thread的更复杂版本。它们非常易于使用,并且具有很多优于Threads的优点:

  1. 您可以为任务创建返回类型,就像它们是函数一样。
  2. 您可以使用“ContinueWith”方法,该方法将等待上一个任务,然后开始执行。 (摘要等)
  3. 摘要根据我公司的指导应该避免使用锁。
  4. 您可以使用Task.WaitAll并传递一系列任务,这样您就可以等到所有任务完成。
  5. 您可以将任务附加到父任务,因此您可以决定父项或子项是否先存在。
  6. 您可以使用LINQ查询实现数据并行。
  7. 您可以创建并行for和foreach循环
  8. 使用任务处理异常非常容易。
  9. *最重要的是,如果在单核计算机上运行相同的代码,它将只作为单个进程运行,而不会产生任何线程开销。
  10. 线程上任务的缺点:

    1. 您需要.Net 4.0
    2. 学习过操作系统的新手可以更好地理解线程。
    3. 框架新手,因此没有多少帮助。
    4. 一些提示: - 始终使用语法完美且标准的Task.Factory.StartNew方法。

      有关更多信息,请查看Task Parallel Libray http://msdn.microsoft.com/en-us/library/dd460717.aspx

答案 3 :(得分:3)

扩展Eric Lippert的评论:

Thread是一种允许应用程序并行执行多项操作的方法。例如,您的应用程序可能有一个线程处理来自用户的事件,如按钮单击,以及另一个执行长计算的线程。这样,你可以“同时”做两件事。如果您不这样做,用户将不会单击按钮,直到计算完成。因此,Thread可以执行您编写的某些代码。

另一方面,

Task代表了某种工作的抽象概念。这个工作可以有结果,你可以等到工作完成(通过调用Wait())或者说你想在工作完成后做一些事情(通过调用ContinueWith())。

您想要表示的最常见的工作是与当前代码并行执行某些计算。 Task为您提供了一种简单的方法。代码实际运行的方式和时间由TaskScheduler定义。默认值使用ThreadPool:一组可以运行任何代码的线程。这样做是因为创建和切换低效的线程。

Task不必与某些代码直接关联。您可以使用TaskCompletionSource创建Task,然后随时设置其结果。例如,您可以创建Task并在用户单击按钮时将其标记为已完成。其他一些代码可以等待Task,等待它时,Task没有代码执行。

如果您想知道何时使用Task以及何时使用ThreadTask使用起来更简单,创建自己的Thread更有效率。但有时,您需要比Task提供的控制更多的控制权。在这些情况下,直接使用Thread是有意义的。

答案 4 :(得分:1)

任务实际上只是手动启动线程的样板代码的包装器。从根本上说,没有区别。任务只是简化了线程的管理,并且由于样板噪声的减少,它们通常更具表现力。