2017-06-06 52 views
1

有一个Channel 9 Video试图解释线程和任务之间的区别。我通常喜欢9频道的视频,因为他们的技术准确性不错,但从我的理解来看,这个视频的一些关键声明是错误的。任务与线程的Channel 9解释是否正确?

下面是语句:

  1. @〜1:48至〜2:30:线程是在存储器和时间昂贵。每个线程获得1 MB的用户模式堆栈。
  2. @〜2:30到2:37:创建线程也需要时间。分配数据结构并初始化它们的时间。
  3. @〜2:38到2:45:上下文切换也需要时间。
  4. @〜2:58至3:23和3:48至:任务使用多核系统[...]因此,当您计算时,您正在使用多个核心。
  5. @〜5:02至5:30:线程运行在单个内核上,上下文切换发生很多。
  6. @〜5:40至5:51:线程有不同的执行方式。它们在多个内核上执行。如你在图中看到的那样,线程已经开销了。

这里是我的想法,我想证实或证伪:

  1. 调用堆栈的数量是可配置的。这样,线程限制不是~1300,而是32位进程的最高限制为12000。那些谁拥有可用的Sysinternals TestLimit的副本可以试试:

    D:\>testlimit -t -n 64  
    Testlimit v5.04 - test Windows limits 
    By Mark Russinovich - www.sysinternals.com 
    
    Creating threads with 64 KB stacks... 
    Created 12500 threads. Lasterror: 8 
    

    堆栈大小也被暴露在Thread Constructor for .NET

  2. 任务依靠线程作为基础。这些线程取自线程池,但是线程池的线程需要在可以使用之前创建。 AFAIK,Mark Russinovich在Windows Internals书中也解释说,内核结构(_ETHREAD)保存在内存中以供重用。这最大限度地减少了分配的开销并将其减少到初始化。

    我没有找到我一直在寻找的确切地点,但在Windows内部6,第1部分它说417页:

    [...]执行线程对象可能或不可能被释放。

  3. 由于任务依赖线程作为技术实现,因此在任何情况下都会发生上下文切换。

  4. 如果我有2个线程,它们也可以在不同的处理器上执行。恕我直言,这是它的全部想法。

  5. 这位演讲者在讨论单核心系统上的线程问题。恕我直言,任务在这种情况下也几乎没有任何好处。见4.)

  6. 见4.和5。)

  7. 该幻灯片可能是正确的,但并未显示实际原因。该幻灯片丢失导致上下文切换的〜15ms时间片。如果线程需要等待结果,则只能使用任务来减少开销。

    在这种情况下,幻灯片的下半部分也是不正确的,因为工作1的第一部分似乎是阻塞的,在这种情况下,工作2只能执行。当工作2完成时,可以完成继续工作1的条件。只有在时间片内发生所有事情,任务才有好处。

    在任何情况下,上下文切换也将随任务一起发生,迟早。

我曾试图确认我有这些问题的帮助理解上SO

上面似乎是7点个人的问题。我问他们都在同一个地方,因为

  • 所有的根源在于一个视频
  • 一些问题互相依赖
  • 它来查找信息在一个地方比继SO规则的恕我直言更重要一次提出一个问题。

回答

1

注意:没有观看视频,纯粹是基于OP中的信息。

调用堆栈的数量是可配置的。

也许,但并不真正相关,除非我们进入非常严谨的细节。

对于.NET任务依赖于线程作为基础。这些线程从线程池获取 ,但是,线程池 的线程需要在可以使用之前创建。

有点正确......虽然我们需要在抽象和实现之间保持一个非常明确的界限。任务可以使用.Net中的Threadpool执行更加正确。

任务表示代码的独立部分(通常)可以同时运行其他代码的想法。线程是类似性质的操作系统实现。

因为任务依赖于线程作为技术实现,所以在任何情况下都会发生上下文切换。

不正确。尽管任务可以在线程上运行,并且可以发生上下文切换,但任务包含一个提供更多灵活性的抽象层。

例如,要在线程之间交换执行,上下文切换必须在硬件中发生。为了在任务之间交换执行,不必发生这样的硬件上下文切换。任务可以在不同的线程之间移动,进入休眠状态并在没有单个硬件上下文切换的情况下恢复。

如果我有2个线程,它们也可以在不同的 处理器上执行。恕我直言,这是它的全部想法。

正确。

演讲者正在讨论单个核心系统上的线程。恕我直言,任务在这种情况下也几乎没有任何好处。

不正确。任务在单线程系统上运行良好,因为它们只是一个抽象。此外,您可以在单个线程中运行多个任务,而无需任何硬件上下文切换,从而提高性能。


这里的主要概念问题似乎是Task = Thread的思想。不是这种情况。任务是打破工作的概念性方式。线程是具有某些行为特征的类似想法的实现。虽然任务可以在封面(不一定)的线程上运行,但抽象允许它们以与硬件线程完全不同的方式运行。

+0

我根本不知道.net,但听起来好像'Task'是你提交给_thread pool_的东西,是吗?如果是这样,线程池的重点是_re-use_ threads。正如你所说,线程是创建和销毁昂贵的。一个不断需要在后台执行小作业的程序可以为每个线程启动一个新线程,并在作业完成时销毁该线程,或者可以使用一些长寿命的后台线程,并用“任务'对象通过一个队列。后一种策略效率更高。 –

+0

@jameslarge任务*可以*运行在线程池(例如task.run执行此IIRC),但这只是他们行为的一个方面。 Task.FromResult不使用线程池,但它仍然是一项任务。此外,可以在不使用任务库/ API的情况下使用线程池。使用线程池来处理任务是一种常见而有效的策略,这是正确的。 – NPSF3000

+0

“任务可以使用.Net中的线程池执行更为正确。” - 我同意。如果它不使用线程池,则需要从头创建一个新线程,它具有与通常线程相同的性能。 –