提问人:saftargholi 提问时间:9/17/2016 最后编辑:saftargholi 更新时间:1/2/2017 访问量:1647
什么是多线程程序,它是如何工作的?
What is a multithreading program and how does it work?
问:
什么是多线程程序,它是如何工作的?我阅读了一些文件,但我很困惑。我知道代码是逐行执行的,但我无法理解程序是如何管理的。
一个简单的答案将不胜感激.c#示例请(仅动画!
答:
在厨房里可以找到一个简单的类比。
你以前可能用食谱做过饭——从指定的食材开始,按照食谱中指示的步骤,最后你(希望)有一道美味的菜可以吃。如果这样做,那么您已经执行了传统的(非多线程)程序。
但是,如果您必须做一顿丰盛的饭菜,其中包括许多不同的菜肴怎么办?简单的方法是从第一个食谱开始,做食谱所说的一切,完成后,把完成的菜(和第一个食谱)放在一边,然后从第二个食谱开始,做它所说的一切,把第二道菜(和第二个食谱)放在一边,依此类推,直到你一个接一个地完成所有的食谱。那行得通,但你最终可能会在厨房里呆上 10 个小时,当然,当最后一道菜准备好吃时,第一道菜可能会很冷,没有胃口。
因此,您可能会做大多数厨师所做的事情,即同时开始研究多个食谱。例如,您可以将烤肉放入烤箱 45 分钟,但与其坐在烤箱前等待 45 分钟让烤肉煮熟,不如花 45 分钟切蔬菜。当烤箱计时器响起时,你放下菜刀,将煮熟的烤肉从烤箱中拉出并冷却,然后回去切菜,依此类推。如果你能做到这一点,那么你就成功地多任务处理了几个配方/程序。也就是说,你并不是在同时处理多个食谱(你仍然只有两只手!),但你会在必要时从一个食谱跳到另一个食谱,从而在几项任务上取得进展,而不是经常摆弄你的拇指。做得好,你可以在更短的时间内准备好整顿饭,而且一切都会在同一时间变得热和新鲜。如果这样做,则执行的是一个简单的多线程程序。
然后,如果你想变得非常花哨,你可以雇佣其他几个厨师和你同时在厨房工作,这样你就可以在给定的时间内准备更多的食物。如果你这样做,你的团队正在进行多处理,每个厨师承担总工作的一部分,而所有厨师同时工作。请注意,如上一段所述,每个厨师很可能正在研究多个食谱(即多任务处理)。
至于计算机如何做这种事情(不再类比厨师),它通常使用准备运行的线程列表和计时器来实现它。当计时器关闭时(或者当前正在执行的线程有一段时间无事可做,例如,它正在等待从慢速硬盘驱动器或其他东西加载数据),操作系统会执行上下文切换,其中暂停当前线程(通过将其放入某处的列表中,不再执行该线程代码中的指令), 然后,从准备运行的线程列表中拉取另一个可运行的线程,并开始执行该线程代码中的指令。只要有必要,这种情况就会重复,通常每隔几毫秒就会发生一次上下文切换,给人一种错觉,即即使在单核 CPU 上,多个程序也在“同时”运行。(在多核CPU上,它在每个内核上都做同样的事情,在这种情况下,它不再只是一个幻觉;多个程序确实同时运行)
评论
multithreading
段落让我想起了更多的.正如您提到的,此线程只是从一个任务跳到另一个任务,实际上没有创建其他线程。那么称它为有效吗?asynchronicity
multithreading
什么是多线程程序,它是如何工作的?
关于这个问题的有趣部分是关于这个主题的完整书籍,但对很多人来说仍然难以捉摸。我将尝试按照下面详述的顺序进行解释。
请注意,这只是为了提供一个要点,像这样的答案永远无法公正地描述所需的深度和细节。关于视频,我遇到的最好的是付费订阅(Wintellect 和 Pluralsight)的一部分,看看您是否可以试用它们,假设您还没有订阅:
Jeffery Ritcher 的 Wintellect(摘自他的著作《CLR via C#》,其中有关于线程基础的相同章节)
解释顺序
- 什么是线程?
- 为什么要引入线程,主要目的?
- 陷阱以及如何避免它们,使用同步结构?
- 线程与 ThreadPool ?
- 多线程编程 API 的演变,如并行 API、任务 API
- 并发集合,使用情况 ?
- Async-Await,线程但没有线程,为什么它们最适合 IO
什么是线程?
它是软件实现,纯粹是 Windows 操作系统的概念 ,它是最低限度的工作单元。Windows 操作系统上的每个进程都至少有一个线程,每个方法调用都在线程上完成。每个进程可以有多个线程,以并行执行多项操作(提供硬件支持)。
其他基于操作系统的操作系统是多进程架构,实际上在 Windows 中,即使是最复杂的软件,例如具有多个线程的单个进程,用于不同的关键后台操作。(multi-threaded architecture)
Unix
Oracle.exe
为什么要引入线程,主要目的?
与并发性是主要目的的看法相反,正是健壮性导致了线程的引入,想象一下 Windows 上的每个进程都使用相同的线程运行(在最初的 16 位版本中),并且其中一个进程崩溃,这仅仅意味着在大多数情况下重新启动系统以恢复。线程用于并发操作,因为每个进程中可以调用多个线程,这在生产线上得到了体现。事实上,充分利用具有多个内核的处理器甚至很重要。
陷阱以及如何避免使用同步结构?
更多的线程意味着,更多的工作同时完成,但是当访问相同的内存时,问题就来了,特别是对于,因为这会导致:Write
- 内存损坏
- 争用条件
另外,另一个问题是线程是一个非常昂贵的资源,每个线程都有一个线程环境块,内核内存分配。此外,为了在处理器内核上调度每个线程,需要花费时间进行上下文切换。滥用很可能会造成巨大的性能损失,而不是改进。
为了避免与线程相关的损坏问题,使用同步构造(例如基于要求)非常重要。读取始终是线程安全的,但写入需要适当的同步。lock, mutex, semaphore,
线程与 ThreadPool ?
真正的线程不是我们在 C#.Net 中使用的线程,它只是调用 Win32 线程的托管包装器。挑战仍然存在于用户严重滥用的能力,例如调用远远超过所需数量的线程,分配处理器关联性,因此,我们请求一个标准池来排队工作项及其窗口,这些窗口决定何时需要新线程,当已经存在的线程可以计划工作项时,这不是更好吗?线程是一种昂贵的资源,需要在使用上进行优化,否则它可能是祸根而不是福音。
多线程编程的演变,如并行 API、任务 API
从 .Net 4.0 开始,各种用于数据并行化和任务并行化的新 API Parallel.For、Parallel.ForEach 使得在系统中引入并发变得非常简单。这些 API 再次在内部使用线程池工作。任务更像是将工作安排在未来的某个时候。现在引入并发就像轻而易举的事,尽管仍然需要同步构造来避免内存损坏,可以使用争用条件或线程安全集合。
并发集合,使用情况 ?
像 这样的实现 ,部分是固有的线程安全、使用和比显式更容易、更快捷的实现。也更容易管理和工作。还有另一个集合 API,例如 ,可通过 nuget 获得,这些 API 通过在内部创建数据结构的另一个副本来实现线程安全。ConcurrentBag, ConcurrentQueue, ConcurrentDictionary
System.Collections.Concurrent
spin-wait
Synchronization
ImmutableList
System.Collections.Immutable
Async-Await,线程但没有线程,为什么它们最适合 IO
这是用于调用(磁盘、网络)的并发性的一个重要方面,到目前为止讨论的其他 API 用于基于计算的并发性,因此线程很重要并使其更快,但对于 IO 调用,线程除了等待调用返回外没有任何用处,IO 调用在基于硬件的队列上处理IO
IO Completion ports
评论
为什么不参考 Microsoft 自己的 .net 类 System.Threading.Thread 文档呢?
它有大量用 C# 编写的简单示例程序(在页面底部),正如您要求的那样:
评论
其实多线程就是同时做多个进程在一起。并且可以并行完成进程。
它其实是多线程是同时一起做多个进程。并且可以并行完成进程。您可以从主线程中获取任务,然后以其他方式执行并完成。
评论