saf*_*oli -5 c# language-agnostic parallel-processing multithreading
什么是多线程程序,它是如何工作的?我读了一些文件,但我很困惑.我知道代码是逐行执行的,但我无法理解程序如何管理它.
一个简单的答案将被赞赏.#例子请(只有动画!)
什么是多线程程序?它是如何工作的?
关于这个问题的有趣部分是关于这个主题的完整书籍,但对许多人来说仍然是难以捉摸的.我将尝试按顺序详细说明.
请注意,这只是为了提供一个要点,这样的答案永远不能正确的深度和详细要求.关于视频,我遇到的最好的是付费订阅(Wintellect和Pluralsight)的一部分,如果您可以在试用的基础上听取它们,请假设您还没有订阅:
Jeffery Ritcher的Wintellect(来自他的书,CLR通过C#,与Thread Fundamentals有相同章节)
说明顺序
什么是线程?
它是软件实现,纯粹是Windows操作系统的概念(multi-threaded architecture),它是最小的工作单元.Windows OS上的每个进程至少有一个线程,每个方法调用都在线程上完成.每个进程可以有多个线程,并行执行多个操作(提供硬件支持).其他Unix基于操作系统的是多进程体系结构,实际上在Windows中,即使是最复杂的软件,例如Oracle.exe具有针对不同关键后台操作的多个线程的单个进程.
为什么要引入线程,主要目的?
与并发是主要目的的观点相反,它是导致线程引入的健壮性,想象一下Windows上的每个进程都使用相同的线程(在最初的16位版本中)运行,并且一个进程崩溃,表示在大多数情况下系统重启以恢复.对于并发操作使用线程,因为可以在每个进程中调用多个线程,这些都是在线下进行的.实际上,充分利用具有多个核心的处理器甚至是重要的.
陷阱以及如何避免使用Synchronization构造?
更多的线程意味着,更多的工作同时完成,但问题来自于访问相同的内存时,特别是因为Write它可以导致:
另外,另一个问题是线程是一个非常昂贵的资源,每个线程都有一个线程环境块,内核内存分配.此外,为了调度处理器核心上的每个线程,花费时间用于上下文切换.滥用可能会导致巨大的性能损失,而不是改进.为避免与线程相关的损坏问题,使用Synchronization构造很重要,例如lock, mutex, semaphore,基于要求.Read始终是线程安全的,但Write需要适当的同步.
线程与ThreadPool?
真正的线程不是那些,我们在C#.Net中使用,这只是托管包装器来调用Win32线程.挑战仍然存在于用户严重滥用的能力,比如调用超过所需线程数量,分配处理器亲和性,因此我们请求标准池对工作项及其窗口进行排队并决定何时新线程更好当现有线程可以调度工作项时,是必需的.线程是一种昂贵的资源,需要在使用中进行优化,否则它可能会受到限制.
多线程编程的演变,如Parallel API,Task API
从.Net 4.0开始,各种新的API Parallel.For,Parallel.ForEach用于数据并行化和任务并行化,使得在系统中引入并发变得非常简单.这些API在内部再次使用线程池.任务更像是将来某个时间安排工作.现在引入并发就像一件轻而易举的事情,但仍然需要同步构造来避免内存损坏,可以使用竞争条件或线程安全集合.
并发集合,用法?
实现,比如ConcurrentBag, ConcurrentQueue, ConcurrentDictionary,部分System.Collections.Concurrent是固有的线程安全,使用spin-wait,比显式更容易和更快Synchronization.管理和工作也更容易.还有另一组API ImmutableList System.Collections.Immutable,可以通过nuget获得,由于在内部创建了另一个数据结构副本,它们是线程安全的.
Async-Await,线程但没有线程,为什么它们最适合IO
这是IO调用(磁盘,网络)的并发性的一个重要方面,到目前为止讨论的其他API,都是基于计算的并发性,因此线程很重要并且使其更快,但对于IO调用线程没有用,除非等待调用要返回,IO调用将在基于硬件的队列上处理IO Completion ports
可以在厨房中找到一个简单的类比.
您可能之前使用过配方烹饪 - 从指定的食材开始,按照食谱中指示的步骤进行烹饪,最后您(希望)有一道美味的食物即可食用.如果你这样做,那么你已经执行了一个传统的(非多线程)程序.
但是,如果你必须做一顿正餐,包括许多不同的菜肴呢?这样做的简单方法是从第一个配方开始,做配方所说的一切,完成后,将完成的菜(和第一个配方)放在一边,然后开始第二个配方,做它所说的一切,将第二道菜(和第二道食谱)放在一边,依此类推,直到你一个接一个地完成所有的食谱.这样可行,但你最终可能会在厨房里待上10个小时,当然,到最后一道菜准备好吃的时候,第一道菜可能会很冷而且没有吸引力.
所以相反,你可能会做大多数厨师所做的事情,那就是同时开始研究几种食谱.例如,您可以将烤箱放入烤箱中45分钟,但不要坐在烤箱前等待45分钟烤制烹饪,您需要花45分钟切碎蔬菜.当烤箱定时器响起时,你放下你的菜刀,将煮熟的烤肉从烤箱中拉出来让它冷却,然后再回去切菜,等等.如果你能做到这一点,那么你就可以成功地多任务处理几个食谱/程序.也就是说,你不是一次只能处理多个食谱(你仍然只有两只手!),但是你必须在一个食谱之后来回跳跃,在必要时跟随另一个食谱,从而在几个任务上取得进展而不是你的拇指很辛苦.做得好,你可以在更短的时间内准备好全餐,并且大约在同一时间一切都将是热的和新鲜的.如果这样做,您正在执行一个简单的多线程程序.
然后,如果你想真正想要的话,你可能会雇佣一些其他厨师同时在厨房工作,这样你就可以在一定的时间内准备更多的食物.如果你这样做,你的团队正在进行多重处理,每个厨师都会完成整个工作的一部分,并且所有人都同时工作.请注意,每位厨师可能正在处理多个配方(即多任务处理),如前一段所述.
至于计算机如何做这种事情(不再是关于厨师的类比),它通常使用可立即运行的线程和计时器列表来实现它.当计时器熄灭时(或者当前正在执行的线程暂时无关,因为例如它正在等待从慢速硬盘或其他东西加载数据),操作系统会执行上下文切换,其中暂停当前线程(通过将其放入某个列表而不再执行该线程代码中的指令),然后从准备运行的线程列表中提取另一个可立即运行的线程,并从该线程的代码开始执行指令代替.这种情况会在必要时重复进行,通常每隔几毫秒就会发生一次上下文切换,从而产生多个程序即使在单核CPU上"同时"运行的错觉.(在多核CPU上,它在每个核心上执行相同的操作,在这种情况下,它不再仅仅是一种错觉;多个程序实际上同时运行)
| 归档时间: |
|
| 查看次数: |
801 次 |
| 最近记录: |