C# 任务和线程之间的区别是什么?

C# 任务和线程之间的区别是什么?,c#,multithreading,c#-4.0,task-parallel-library,terminology,C#,Multithreading,C# 4.0,Task Parallel Library,Terminology,在C#4.0中,在System.Threading.Tasks命名空间中有Task。线程和任务之间的真正区别是什么。我做了一些示例程序(来自MSDN的帮助),以便于我自己学习 Parallel.Invoke Parallel.For Parallel.ForEach 但我有很多疑问,因为这个想法并不那么清楚 我最初在Stackoverflow中搜索过类似类型的问题,但可能是由于这个问题的标题,我无法得到相同的答案。如果有人知道之前在这里发布的相同类型的问题,请提供该链接的参考。任务是您想

在C#4.0中,在System.Threading.Tasks命名空间中有
Task
线程
任务
之间的真正区别是什么。我做了一些示例程序(来自MSDN的帮助),以便于我自己学习

Parallel.Invoke 
Parallel.For 
Parallel.ForEach 
但我有很多疑问,因为这个想法并不那么清楚


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

任务是您想要完成的事情

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


在.NET4.0术语中,表示异步操作。线程用于完成该操作,方法是将工作分解成块并分配给单独的线程。

在计算机科学术语中,
任务是未来或承诺。(有些人同义使用这两个术语,有些人使用不同的术语,没有人能就精确的定义达成一致。)基本上,
任务
“承诺”会给你一个
T
,但现在不行,亲爱的,我有点忙,你为什么不稍后再来

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


特别是,
任务
没有说明返回值花费如此长时间的原因。可能是计算需要很长时间,也可能是获取数据需要很长时间。只有在前一种情况下,您才会使用
线程
运行
任务
。(在.NET中,线程非常昂贵,因此您通常希望尽可能避免使用线程,并且仅当您希望在多个CPU上运行多个繁重的计算时才使用线程。例如,在Windows中,一个线程的重量为12 KiByte(我认为),在Linux中,一个线程的重量只有4磅 KiByte,在Erlang/BEAM中甚至只有400 在.NET中,它是1 MiByte!)

您可以使用
任务
指定要执行的操作,然后使用
线程
附加该
任务。因此,
任务
将在新创建的
线程
中执行,而不是在GUI线程上执行

任务
任务工厂.StartNew(操作操作)
一起使用。在这里,您执行一个委托,因此如果您没有使用任何线程,它将在同一个线程(GUI线程)中执行。如果您提到一个线程,您可以在另一个线程中执行此
任务
。这是一项不必要的工作,因为您可以直接执行委托,或者将该委托附加到线程,然后在该线程中执行该委托。所以不要使用它。只是没必要。如果你打算优化你的软件,这是一个很好的候选人被删除


**请注意,
操作
是一个
委托

任务就像您想要执行的操作,线程帮助您通过多个进程节点管理这些操作。任务是一个轻量级选项,因为线程可能导致复杂的代码管理
我建议您经常阅读MSDN(世界上最好的产品)

螺纹 裸机的东西,您可能不需要使用它,您可能可以使用
长时间运行
任务,并从.NETFramework 4(2002年2月)及更高版本(也包括.NETCore)中包含的TPL-任务并行库中获益

任务 线程之上的抽象。它使用线程池(除非您将任务指定为
长时间运行
操作,否则会在后台为您创建一个新线程)

线程池 顾名思义:一个线程池。是指.NET framework为您处理有限数量的线程。为什么?因为在只有8个内核的处理器上打开100个线程来执行昂贵的CPU操作肯定不是一个好主意。该框架将为您维护这个池,重用线程(而不是在每次操作中创建/杀死线程),并并行执行其中一些线程,这样您的CPU就不会烧坏

好的,但是什么时候使用每一个呢? 在简历中:始终使用任务

任务是一种抽象,因此使用起来容易得多。我建议您始终尝试使用任务,如果您遇到一些问题,需要自己处理线程(可能有1%的时间),则使用线程

但请注意:
  • I/O绑定:对于I/O绑定操作(数据库调用、读/写文件、API调用等),避免使用正常任务,请使用
    longlunning
    任务(或线程,如果需要)。因为使用任务将导致您进入一个线程池,其中有几个线程处于忙碌状态,还有许多其他任务等待轮到它使用该线程池
  • CPU绑定的:对于CPU绑定的操作,只需使用普通任务(内部将使用线程池)就可以了
除了以上几点,最好知道:

  • 默认情况下,任务是后台任务。您不能有前台任务。另一方面,线程可以是背景或前景(使用IsBackground属性更改行为)
  • 在线程池中创建的任务会回收线程,这有助于节省资源。因此,在大多数情况下,任务应该是您的默认选择
  • 如果操作很快,最好使用任务而不是线程。对于长时间运行的操作,任务没有提供太多优势
    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;
    }
    
    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();
    }
    
    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