任务和线程有什么区别?

366 c# multithreading terminology task-parallel-library c#-4.0

在C#4.0中,我们已经TaskSystem.Threading.Tasks命名空间.之间有什么真正的改变ThreadTask.我为了学习而做了一些示例程序(帮助从MSDN获取)

Parallel.Invoke 
Parallel.For 
Parallel.ForEach 
Run Code Online (Sandbox Code Playgroud)

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

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

Jör*_*tag 436

在计算机科学术语中,a Task未来承诺.(有些人同意使用这两个术语,有些人使用不同的术语,没有人可以就精确的定义达成一致.)基本上,Task<T>"承诺"会让你回归T,但现在不是蜂蜜,我有点忙,为什么不你晚点回来?

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

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

  • 有趣的是,在TPL(任务并行库)的早期预览版中,有Task和Future <T>.然后将Future <T>重命名为Task <T>.:) (28认同)
  • 你是如何为.NET计算1 MB的? (22认同)
  • @RIPUNJAYTRIPATHI当然,但它不需要是*另一个*线程,它可能是首先请求工作的线程. (9认同)
  • .NET只在Windows上使用Windows线程,因此大小相同 - 默认情况下,两者的虚拟内存通常为1 MiB.在页面大小的块(通常为64 kiB)中根据需要使用物理内存,与本机代码相同.最小线程堆栈大小取决于操作系统 - 例如Vista的256 kiB.在x86 Linux上,默认值通常为2 MiB - 再次以页面大小的块分配.(简化)Erlang每个进程只使用一个系统线程,这400个字节指的是类似于.NET的`Task`. (6认同)
  • @DanVallejo:在与TPL设计团队的访谈中提到了这个数字.我不能告诉你是谁说的,或者是哪次采访,我多年前就看过了. (5认同)
  • @RohitSharma,我认为他的意思是"不是每个任务都需要一个单独的线程". (3认同)
  • @DanVallejo Navan [这里](http://channel9.msdn.com/blogs/bruceky/how-to-parallelize-your-application-part-2-theads-) 发布的第二个视频开头提到了大小v-任务) (2认同)
  • @RohitSharma `Task.FromResult("Hi!")` 使用什么线程? (2认同)
  • “基本上,一个Task&lt;T&gt;“承诺”给你一个T,但现在不是,亲爱的,我有点忙,你为什么不晚点回来?” =&gt; 我找到的最好的定义。 (2认同)

Mit*_*eat 306

任务是你想要完成的.

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

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


fab*_*tto 33

线

裸机,您可能不需要使用它,您可能可以使用LongRunning任务并从TPL - 任务并行库中获益,包括在.NET Framework 4(2002年2月)及更高版本(也包括.NET)中核心).

任务

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

线程池

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

好的,但什么时候使用每一个?

简历中:始终使用任务.

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

但请注意:

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

  • 稍微修正一下,线程不是“裸机”。它是由操作系统实现的,大多数实现依赖于CPU和CS的功能,但它们不是由硬件实现的。 (4认同)

小智 7

您可以使用Task指定你想要做的,然后附上什么TaskThread.所以这Task将在新制作Thread而不是在GUI线程中执行.

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

**请注意,这Action是一个delegate.


eww*_*ink 7

我通常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;
}
Run Code Online (Sandbox Code Playgroud)

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();
}
Run Code Online (Sandbox Code Playgroud)

不同之处在于您不需要使用MethodInvoker更短的代码。


Cha*_*thJ 7

任务可以被看作是异步和并行执行某事的方便和简单的方法。

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

您可以使用线程(花费大量精力)完成与任务相同的任务。

线

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

任务

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

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

正如本文所指出的,task 提供了以下强大的线程特性。

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

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

  • 任务可以返回结果。没有直接机制可以从线程返回结果。
  • 等待一组任务,没有信号结构。

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

  • 当一项任务从另一项任务开始时,建立父/子关系。

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

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

  • 异步实现在任务中很容易,使用'async' 和'await' 关键字。


小智 6

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

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