任务和线程有什么区别?

时间:2010-11-09 03:14:06

标签: c# multithreading c#-4.0 task-parallel-library

在C#4.0中,我们在 System.Threading.Tasks 命名空间中有TaskThreadTask之间的真正区别是什么?为了我自己学习

,我做了一些示例程序(帮助从MSDN获取)
Parallel.Invoke 
Parallel.For 
Parallel.ForEach 

但有很多疑问,因为这个想法并不那么明确。

我最初在Stackoverflow中搜索了类似类型的问题但可能是这个问题标题我无法得到相同的。如果有人知道之前发布的相同类型的问题,请提供链接的参考。

8 个答案:

答案 0 :(得分:426)

在计算机科学术语中,Task future promise 。 (有些人同义地使用这两个术语,有些人使用不同的术语,没有人能够就精确的定义达成一致。)基本上,Task<T>“承诺”会给你一个T ,但现在不是亲爱的,我有点忙,你为什么不晚点回来?

Thread是实现这一承诺的一种方式。但并非每个Task都需要一个全新的Thread。 (事实上​​,创建一个线程通常是不可取的,因为这样做比重新使用来自线程池的现有线程要昂贵得多。稍后会详细介绍。)如果您正在等待的值来自文件系统或者数据库或网络,当它可以为其他请求提供服务时,不需要一个线程坐下来等待数据。相反,Task可能会注册回调以在它们准备好时接收值。

特别是,Task 可能需要很长时间才能计算,或者它可能需要很长时间才能获取。只有在前一种情况下,您才会使用Thread来运行Task。 (在.NET中,线程非常昂贵,因此您通常希望尽可能地避免它们,并且如果您想在多个CPU上运行多次繁重计算,则实际上只使用它们。例如,在Windows中,线程重量为12 KiByte(我认为,在Linux中,线程重量只有4 KiByte,在Erlang / BEAM中甚至只有400字节。在.NET中,它只有1 MiByte!)

答案 1 :(得分:291)

任务是你想做的事。

线程是执行该任务的众多可能的工作者之一。

在.NET 4.0术语中,Task表示异步操作。线程用于通过将工作分解为块并分配给单独的线程来完成该操作。

答案 2 :(得分:29)

裸机,您可能不需要使用它,您可能可以使用LongRunning任务并从TPL中获益 - 任务并行库,包含在.NET Framework 4中( 2002年2月)及以上(也是.NET Core)。

任务

线程上方的抽象。 使用线程池(除非您将任务指定为LongRunning操作,如果是,则为您创建一个新线程。)

线程池

顾名思义:一个线程池。 .NET框架是否为您处理有限数量的线程。为什么?因为打开100个线程来执行昂贵的CPU操作只需8个核心的处理器绝对不是一个好主意。框架将为您维护此池,重用线程(不是在每次操作时创建/删除它们),并以CPU不会刻录的方式并行执行其中一些。

好的,但何时使用每一个?

简历中:始终使用任务。

任务是一种抽象,因此使用起来要容易得多。我建议你总是尝试使用任务,如果你面临一些问题,你需要自己处理一个线程(可能是1%的时间),然后使用线程。

但请注意:

  • I / O Bound :对于I / O绑定操作(数据库调用,读/写文件,API调用等),避免使用正常任务,使用LongRunning任务(或者线程,如果你需要)。因为使用任务会导致您进入一个线程池,其中有几个线程忙,而许多其他任务等待轮流使用该池。
  • CPU绑定:对于CPU绑定操作,只需使用正常任务(内部将使用线程池)并开心。

答案 3 :(得分:7)

您可以使用Task指定要执行的操作,然后将Task附加到Thread。这样Task将在新创建的Thread而不是GUI线程中执行。

TaskTaskFactory.StartNew(Action action)一起使用。在这里你执行一个委托,所以如果你没有使用任何线程,它将在同一个线程(GUI线程)中执行。如果你提到一个线程,你可以在另一个线程中执行这个Task。这是一项不必要的工作,因为您可以直接执行委托或将该委托附加到线程并在该线程中执行该委托。所以不要使用它。这是不必要的。如果您打算优化您的软件,这是一个很好的选择。

**请注意Actiondelegate

答案 4 :(得分:6)

除了以上几点,最好知道:

  1. 默认情况下,任务是后台任务。您无法拥有前台任务。另一方面,线程可以是后台或前台(使用IsBackground属性来更改行为)。
  2. 在线程池中创建的任务会回收有助于节省资源的线程。因此,在大多数情况下,任务应该是您的默认选择。
  3. 如果操作很快,使用任务而不是线程要好得多。对于长时间运行的操作,任务不会提供比线程更多的优势。

答案 5 :(得分:3)

可以将Task视为异步和并行执行某项操作的便捷方法。

通常您只需要一个任务,我不记得我是否曾经将线程用于实验以外的其他用途。

您可以通过线程(很费力)来完成与完成任务相同的事情。

线程

int result = 0;
Thread thread = new System.Threading.Thread(() => { 
    result = 1; 
});
thread.Start();
thread.Join();
Console.WriteLine(result); //is 1

任务

int result = await Task.Run(() => {
    return 1; 
});
Console.WriteLine(result); //is 1

默认情况下,任务将使用线程池,因为创建线程可能会很昂贵,因此可以节省资源。您可以将“任务”视为对线程的更高层次的抽象。

this article指出,任务通过线程提供了以下强大功能。

  • 调整任务以利用多核处理器。

  • 如果系统有多个任务,那么它将使用CLR线程池 在内部,因此没有创建相关的开销 使用线程的专用线程。也减少上下文 在多个线程之间切换时间。

  • 任务可以返回结果。没有直接的机制可以从线程返回结果。
  • 等待一组任务,而无需使用信号传递构造。

  • 我们可以将任务链接在一起,以一个接一个地执行。

  • 从一个任务开始时建立父子关系 另一个任务。

  • 子任务异常可以传播到父任务。

  • 任务支持通过使用取消令牌进行取消。

  • 使用“异步”和 “等待”关键字。

答案 6 :(得分:2)

任务就像您想要执行的操作,Thread有助于通过多个流程节点管理这些操作。任务是一个轻量级选项,因为线程可以导致复杂的代码管理 我建议从MSDN(世界上最好的)中读取总是
Task

Thread

答案 7 :(得分:2)

我通常使用Task与Winforms和简单的后台工作程序进行交互,以使其不会冻结UI。这是我更喜欢使用Task

的示例
private async void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    await Task.Run(() => {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
    })
    buttonDownload.Enabled = true;
}

VS

private void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    Thread t = new Thread(() =>
    {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
        this.Invoke((MethodInvoker)delegate()
        {
            buttonDownload.Enabled = true;
        });
    });
    t.IsBackground = true;
    t.Start();
}

区别在于您不需要使用MethodInvoker和较短的代码。