什么是多线程程序,它是如何工作的?

What is a multithreading program and how does it work?

提问人:saftargholi 提问时间:9/17/2016 最后编辑:saftargholi 更新时间:1/2/2017 访问量:1647

问:

什么是多线程程序,它是如何工作的?我阅读了一些文件,但我很困惑。我知道代码是逐行执行的,但我无法理解程序是如何管理的。
一个简单的答案将不胜感激.c#示例请(仅动画!

C# 多线程并 行处理与 语言无关

评论

2赞 Shannon Holsinger 9/17/2016
如果你把程序执行想象成一个小精灵在你的电脑里跑来跑去,做你分配的任务,那么想象一下两三个精灵同时跑来跑去做事。这就是多线程。对于任务和线程,它们通常彼此分开做事。使用 Parallel,他们都在一个循环中工作,看看谁能先完成。作为一名程序员,你需要确保精灵们都有事可做,并且有一个精灵没有出现在午餐约会中,却发现另一个精灵们在WHILE循环中徘徊。当这种情况发生时,他们会生气。
0赞 guest271314 9/18/2016
@arashzgh 请参阅使用 Web Worker “Web Worker 为 Web 内容提供了一种在后台线程中运行脚本的简单方法。工作线程可以在不干扰用户界面的情况下执行任务。你想达到什么目的?
0赞 Mellow 9/20/2016
Stackoverflow 文档有一个关于这个主题(线程),有很多例子: stackoverflow.com/documentation/c%23/51/threading
0赞 saftargholi 9/21/2016
我需要图片和动画

答:

6赞 Jeremy Friesner 9/18/2016 #1

在厨房里可以找到一个简单的类比。

你以前可能用食谱做过饭——从指定的食材开始,按照食谱中指示的步骤,最后你(希望)有一道美味的菜可以吃。如果这样做,那么您已经执行了传统的(非多线程)程序

但是,如果您必须做一顿丰盛的饭菜,其中包括许多不同的菜肴怎么办?简单的方法是从第一个食谱开始,做食谱所说的一切,完成后,把完成的菜(和第一个食谱)放在一边,然后从第二个食谱开始,做它所说的一切,把第二道菜(和第二个食谱)放在一边,依此类推,直到你一个接一个地完成所有的食谱。那行得通,但你最终可能会在厨房里呆上 10 个小时,当然,当最后一道菜准备好吃时,第一道菜可能会很冷,没有胃口。

因此,您可能会做大多数厨师所做的事情,即同时开始研究多个食谱。例如,您可以将烤肉放入烤箱 45 分钟,但与其坐在烤箱前等待 45 分钟让烤肉煮熟,不如花 45 分钟切蔬菜。当烤箱计时器响起时,你放下菜刀,将煮熟的烤肉从烤箱中拉出并冷却,然后回去切菜,依此类推。如果你能做到这一点,那么你就成功地多任务处理了几个配方/程序。也就是说,你并不是在同时处理多个食谱(你仍然只有两只手!),但你会在必要时从一个食谱跳到另一个食谱,从而在几项任务上取得进展,而不是经常摆弄你的拇指。做得好,你可以在更短的时间内准备好整顿饭,而且一切都会在同一时间变得热和新鲜。如果这样做,则执行的是一个简单的多线程程序

然后,如果你想变得非常花哨,你可以雇佣其他几个厨师和你同时在厨房工作,这样你就可以在给定的时间内准备更多的食物。如果你这样做,你的团队正在进行多处理,每个厨师承担总工作的一部分,而所有厨师同时工作。请注意,如上一段所述,每个厨师很可能正在研究多个食谱(即多任务处理)。

至于计算机如何做这种事情(不再类比厨师),它通常使用准备运行的线程列表和计时器来实现它。当计时器关闭时(或者当前正在执行的线程有一段时间无事可做,例如,它正在等待从慢速硬盘驱动器或其他东西加载数据),操作系统会执行上下文切换,其中暂停当前线程(通过将其放入某处的列表中,不再执行该线程代码中的指令), 然后,从准备运行的线程列表中拉取另一个可运行的线程,并开始执行该线程代码中的指令。只要有必要,这种情况就会重复,通常每隔几毫秒就会发生一次上下文切换,给人一种错觉,即即使在单核 CPU 上,多个程序也在“同时”运行。(在多核CPU上,它在每个内核上都做同样的事情,在这种情况下,它不再只是一个幻觉;多个程序确实同时运行)

评论

0赞 Gabrielius 9/20/2016
multithreading段落让我想起了更多的.正如您提到的,此线程只是从一个任务跳到另一个任务,实际上没有创建其他线程。那么称它为有效吗?asynchronicitymultithreading
2赞 Jeremy Friesner 9/20/2016
线程不会从一个任务跳到另一个任务;线程(根据定义)是相关指令的单个序列。它是 CPU(即类比中的厨师,而不是食谱)从一个任务跳到另一个任务,即从线程 A 执行一些指令,然后从 B 执行一些指令,然后从 C 执行一些指令,然后再次从 A 执行一些指令。
0赞 Jeremy Friesner 9/21/2016
@Gabrielius(当然,你可以编写一个单线程程序来做同样的事情,但这样你基本上就是在该单线程中实现你自己的原始任务调度程序)
0赞 Gabrielius 9/21/2016
杰里米,是的,我明白。我错误地认为厨师主线,而实际上它是食谱。因此,不是线程在做某事,而是 CPU 在切换线程配方)并从中执行指令。在不了解基础知识的情况下编写了所有这些多线程应用程序后,我有点羞愧!谢谢,学到了一些新东西!
7赞 Mrinal Kamboj 9/21/2016 #2

什么是多线程程序,它是如何工作的?

关于这个问题的有趣部分是关于这个主题的完整书籍,但对很多人来说仍然难以捉摸。我将尝试按照下面详述的顺序进行解释。

请注意,这只是为了提供一个要点,像这样的答案永远无法公正地描述所需的深度和细节。关于视频,我遇到的最好的是付费订阅(Wintellect 和 Pluralsight)的一部分,看看您是否可以试用它们,假设您还没有订阅:

  1. Jeffery Ritcher 的 Wintellect(摘自他的著作《CLR via C#》,其中有关于线程基础的相同章节)

  2. Mike Woodring 开发的 CLR 线程

解释顺序

  • 什么是线程?
  • 为什么要引入线程,主要目的?
  • 陷阱以及如何避免它们,使用同步结构?
  • 线程与 ThreadPool ?
  • 多线程编程 API 的演变,如并行 API、任务 API
  • 并发集合,使用情况 ?
  • Async-Await,线程但没有线程,为什么它们最适合 IO

什么是线程?

它是软件实现,纯粹是 Windows 操作系统的概念 ,它是最低限度的工作单元。Windows 操作系统上的每个进程都至少有一个线程,每个方法调用都在线程上完成。每个进程可以有多个线程,以并行执行多项操作(提供硬件支持)。 其他基于操作系统的操作系统是多进程架构,实际上在 Windows 中,即使是最复杂的软件,例如具有多个线程的单个进程,用于不同的关键后台操作。(multi-threaded architecture)UnixOracle.exe

为什么要引入线程,主要目的?

与并发性是主要目的的看法相反,正是健壮性导致了线程的引入,想象一下 Windows 上的每个进程都使用相同的线程运行(在最初的 16 位版本中),并且其中一个进程崩溃,这仅仅意味着在大多数情况下重新启动系统以恢复。线程用于并发操作,因为每个进程中可以调用多个线程,这在生产线上得到了体现。事实上,充分利用具有多个内核的处理器甚至很重要。

陷阱以及如何避免使用同步结构?

更多的线程意味着,更多的工作同时完成,但是当访问相同的内存时,问题就来了,特别是对于,因为这会导致:Write

  1. 内存损坏
  2. 争用条件

另外,另一个问题是线程是一个非常昂贵的资源,每个线程都有一个线程环境块,内核内存分配。此外,为了在处理器内核上调度每个线程,需要花费时间进行上下文切换。滥用很可能会造成巨大的性能损失,而不是改进。 为了避免与线程相关的损坏问题,使用同步构造(例如基于要求)非常重要。读取始终是线程安全的,但写入需要适当的同步。lock, mutex, semaphore,

线程与 ThreadPool ?

真正的线程不是我们在 C#.Net 中使用的线程,它只是调用 Win32 线程的托管包装器。挑战仍然存在于用户严重滥用的能力,例如调用远远超过所需数量的线程,分配处理器关联性,因此,我们请求一个标准池来排队工作项及其窗口,这些窗口决定何时需要新线程,当已经存在的线程可以计划工作项时,这不是更好吗?线程是一种昂贵的资源,需要在使用上进行优化,否则它可能是祸根而不是福音。

多线程编程的演变,如并行 API、任务 API

从 .Net 4.0 开始,各种用于数据并行化和任务并行化的新 API Parallel.For、Parallel.ForEach 使得在系统中引入并发变得非常简单。这些 API 再次在内部使用线程池工作。任务更像是将工作安排在未来的某个时候。现在引入并发就像轻而易举的事,尽管仍然需要同步构造来避免内存损坏,可以使用争用条件或线程安全集合。

并发集合,使用情况 ?

像 这样的实现 ,部分是固有的线程安全、使用和比显式更容易、更快捷的实现。也更容易管理和工作。还有另一个集合 API,例如 ,可通过 nuget 获得,这些 API 通过在内部创建数据结构的另一个副本来实现线程安全。ConcurrentBag, ConcurrentQueue, ConcurrentDictionarySystem.Collections.Concurrentspin-waitSynchronizationImmutableListSystem.Collections.Immutable

Async-Await,线程但没有线程,为什么它们最适合 IO

这是用于调用(磁盘、网络)的并发性的一个重要方面,到目前为止讨论的其他 API 用于基于计算的并发性,因此线程很重要并使其更快,但对于 IO 调用,线程除了等待调用返回外没有任何用处,IO 调用在基于硬件的队列上处理IOIO Completion ports

评论

0赞 Mrinal Kamboj 9/24/2016
欢迎,请通过视频链接,他们有很多有用的信息
0赞 Georg Bisseling 9/21/2016 #3

为什么不参考 Microsoft 自己的 .net 类 System.Threading.Thread 文档呢?

它有大量用 C# 编写的简单示例程序(在页面底部),正如您要求的那样:

线程示例

评论

0赞 Mrinal Kamboj 9/22/2016
任何只是一个参考的东西,请添加为评论而不是答案,因为这里没有附加值
0赞 saftargholi 9/22/2016
这应该是 comment first .你能看到我的问题吗?我的问题问动画.
0赞 Georg Bisseling 9/22/2016
@arashzgh:明天你会在你的问题中补充你只想要使用 WPF 的例子吗?
0赞 Georg Bisseling 9/22/2016
@Mrinal Kamboj:对不起,我刚刚获得了发表评论的特权,所以我被迫回答而不是评论。
0赞 user7160191 11/15/2016 #4

其实多线程就是同时做多个进程在一起。并且可以并行完成进程。

-1赞 user7364476 1/2/2017 #5

它其实是多线程是同时一起做多个进程。并且可以并行完成进程。您可以从主线程中获取任务,然后以其他方式执行并完成。

评论

0赞 Rucha Bhatt Joshi 1/2/2017
请使用评论部分..!