线程如何节省时间?

Sum*_*dia 22 c# multithreading process

我正在学习C#中的线程.但是,我无法理解线程的哪些方面实际上正在提高性能.

考虑只存在单个核心处理器的情况.将任务拆分为多个线程使用相同的进程上下文(共享资源),并且它们同时运行.由于线程只是共享时间,为什么它们的运行时间(周转时间)小于单线程进程?

Ser*_*rvy 28

在单核CPU中,您获得的优势是通过异步.使用线程是实现这一目标的一种方式(尽管不是唯一的方法).

想象一下烹饪一顿饭的过程.您认为哪个更快:

  1. 开始浇水.等待它完成.
  2. 加一些面条.等待他们完成煮熟.
  3. 洗净/准备一些蔬菜.
  4. 搅拌炒蔬菜.
  5. 穿上盘子和服务.

或者改为:

  1. 开始浇水.
  2. 虽然水沸腾洗/准备一些蔬菜.
  3. 在煮沸的水中加入一些面条.
  4. 在煮熟面条的同时搅拌蔬菜.
  5. 穿上盘子和服务.

根据我的经验,第二个更快.

这里的一般想法是,在许多情况下,编程时您将需要一些时间的操作,但它不需要完成CPU的工作.一个常见的例子是IO.当您向数据库发送请求以获取某些信息时,在您等待该请求返回时,您可以执行其他操作.也许你可以发送几个请求,然后等待它们完成,而不是开始一个,等待它,然后开始下一个,等待,等等(尽管有时你必须做后者).

现在,如果您需要做的工作是CPU绑定工作,那么如果您的CPU上有多个内核,那么您实际上只会从线程中获益,这样工作实际上可以并行完成,而不仅仅是异步完成.例如,许多与图形相关的工作(乘以矩阵,给出一个简单的例子)通常涉及做很多基本的数学运算.如果您有多个核心,这些操作通常可以很好地扩展.如果您没有多个内核(或GPU,实际上是具有许多非常小且简单的内核的CPU ),那么使用线程没有多大意义.

  • 我想补充一点,线程是实现异步的常用方法(尽管它们的成本相对较高),因为它们往往比替代(回调)简单得多.有些语言试图将这种差异缩小,比如C#5.0或Go. (5认同)

Eri*_*ert 25

考虑只存在单个核心处理器的情况.将任务拆分为多个线程使用相同的进程上下文(共享资源),并且它们同时运行.由于线程只是共享时间,为什么它们的运行时间(周转时间)小于单线程进程?

你对任何声称的加速都持怀疑态度是完全正确的.

首先,正如Servy和其他人在他们的答案中指出的那样,如果作业不受处理器限制,那么显然可以有一些加速,因为当处理器空闲等待磁盘或网络回来时,它可能正在做另一个线程的工作.

但是假设你有两个处理器绑定的任务,一个处理器,两个线程或一个线程.在单线程场景中它是这样的:

  • 完成工作的100%工作1.假设这需要1000毫秒.
  • 完成工作的100%工作2.假设这需要1000毫秒.

总时间:两秒钟.完成的工作总数:两个.但这是重要的一点: 等待工作1的客户只需一秒即可完成工作.等待工作2的客户端必须等待两秒钟.

现在,如果我们有两个线程和一个CPU,它会像这样:

  • 完成工作1的10%工作,持续100毫秒.
  • 完成工作2的10%工作,持续100毫秒.
  • 做10%的工作1
  • 做10%的工作2 ...

同样,总时间为两秒,但这次正在等待工作1的客户端在1.9秒内完成工作,比单线程方案慢近100%!

这就是这里故事的寓意,你完全可以指出.如果满足以下条件:

  • 这些作业受CPU限制
  • 线程多于CPU
  • 这项工作仅对其最终结果有用

然后添加更多线程只会减慢你的速度.

诸如任务并行库之类的库是为这种情况设计的; 他们试图弄清楚何时添加更多线程会使事情变得更糟,并尝试只安排尽可能多的线程来为服务它们提供CPU.

现在,如果任何这些条件那么满足增加更多的线程是一个好主意.

  • 如果作业不受CPU限制,那么添加更多线程允许CPU在空闲时等待网络或磁盘时工作.

  • 如果存在空闲CPU,则添加更多线程允许调度这些CPU.

  • 如果部分计算结果很有用,那么添加更多线程可以改善这种情况,因为客户端有更多机会使用部分计算结果.例如,在我们的第二个场景中,两个作业的客户端每200毫秒获得部分结果,这是公平的.