multithreading async - 如何阐明异步和并行编程之间的区别?




overview (9)

这篇文章解释得非常好: http://urda.cc/blog/2010/10/04/asynchronous-versus-parallel-programming : http://urda.cc/blog/2010/10/04/asynchronous-versus-parallel-programming

它有关于异步编程的内容:

异步调用用于防止应用程序中的“阻塞”。 [这样的]调用将在已经存在的线程(如I / O线程)中分离出来,并在可能时执行其任务。

这关于并行编程:

在并行编程中,您仍然会分解工作或任务,但主要区别在于您为每个工作块启动新线程

总结如下:

异步调用将使用系统已在使用的线程并行编程需要开发人员打破所需的工作,启动和拆卸线程

许多平台都提高了异步性和并行性,作为提高响应速度的手段。 我通常理解差异,但经常发现很难在我自己的脑海中以及在其他人身上表达。

我是一个workaday程序员,经常使用异步和回调。 平行主义感觉异乎寻常。

但我觉得他们很容易混淆,特别是在语言设计层面。 会喜欢清楚描述它们如何相关(或不相关),以及哪些程序类别最适用。


我倾向于考虑这些术语的差异:

异步:离开并完成这项任务,当你完成回来并告诉我并带来结果时。 与此同时,我将继续努力。

平行:我希望你做这个任务。 如果它更容易,请让一些人帮忙。 尽管这很紧急,所以我会在这里等到你回来的结果。 直到你回来,我什么也做不了。

当然,一个异步任务可能会利用并行性,但至少在我看来,这种区别在于在操作执行时是否继续其他事情,或者直到结果是否完全停止。


异步:在后台运行方法或任务,不会阻塞。 可能不需要在单独的线程上运行。 使用上下文切换/时间调度。

并行任务:每个任务并行运行。 不使用上下文切换/时间安排。


我来这里对这两个概念相当舒服,但对我来说还不清楚。

在阅读了一些答案之后,我想我有一个正确和有用的比喻来描述这种差异。

如果你认为你的各行代码是独立但有序的扑克牌(如果我正在解释老派打孔卡的工作原理,请停止我),那么对于每一个单独的程序,你都将拥有一堆独特的牌(不要复制&paste!)以及正常运行代码和异步运行时正常情况之间的区别取决于您是否在意。

当你运行代码时,你需要向操作系统提交一组单一的操作(你的编译器或解释器将你的“高级”代码打破)传递给处理器。 使用一个处理器,任何时候只能执行一行代码。 因此,为了完成同时运行多个进程的幻想,操作系统使用一种技术,在该技术中,处理器一次只能从给定进程向处理器发送几行代码,并根据它如何看待所有进程适合。 其结果是多个进程向最终用户显示进展情况,这似乎是同一时间。

对于我们的比喻来说,这种关系就是操作系统在把它们发送给处理器之前总是先洗牌。 如果你的堆栈卡不依赖于另一个堆栈,则不会注意到当另一个堆栈变为活动状态时,堆栈停止选择。 所以如果你不在乎,那并不重要。

但是,如果你真的关心了(例如,有多个进程 - 或者一堆卡片 - 这些进程确实相互依赖),那么操作系统的混洗将会使你的结果搞砸。

编写异步代码需要处理执行顺序之间的依赖关系,而不管最终的顺序如何。 这就是为什么使用类似“回叫”的结构。 他们对处理器说,“接下来要做的是告诉其他堆栈我们做了什么”。 通过使用这些工具,可以确保其他堆栈在它允许操作系统运行指令之前得到通知。 (“如果called_back == false:发送(no_operation)” - 不知道这实际上是如何实现的,但逻辑上我认为它是一致的)

对于并行进程,区别在于你有两个不关心对方的堆栈,有两个工作进程处理它们。 在一天结束时,您可能需要结合两个堆栈的结果,这将是一个同步问题,但对于执行,您不再关心。

不知道这是否有帮助,但我总是发现多个解释有帮助。 另请注意,异步执行不限于个人计算机及其处理器。 一般来说,它涉及时间,或者(更一般地说)事件顺序。 因此,如果将依赖堆栈A发送到网络节点X以及将其堆栈B耦合到Y,则正确的异步代码应该能够说明情况,就好像它在笔记本电脑上本地运行一样。


我的基本理解是:

异步编程解决了在可以执行任何其他操作之前等待昂贵操作完成的问题。 如果您在等待手术完成时可以完成其他工作,那么这是件好事。 示例:在您离开时保持UI运行并从Web服务检索更多数据。

并行编程是相关的,但更关心的是将大型任务分解为可以同时计算的更小的块。 然后可以组合小块的结果来产生总体结果。 例如:射线追踪,其中各个像素的颜色基本上是独立的。

这可能比这更复杂,但我认为这是基本的区别。


为什么是异步?

随着今天的应用程序越来越多地连接并且可能长时间运行的任务或阻塞操作(例如网络I / O或数据库操作),因此通过在后台启动它们并返回到用户界面来隐藏这些操作的延迟是非常重要的尽可能迅速。 这里是异步进入图片, 响应

为什么要并行编程

随着今天的数据集越来越大,计算越来越复杂。 因此,减少这些CPU绑定操作的执行时间非常重要,在这种情况下,将工作负载分成块并同时执行这些块。 我们可以称之为“并行”。 显然它会给我们的应用带来很高的性能


这是执行顺序的问题。

如果A与B不同步,那么我不能事先预测何时B的子部分会发生A的子部分。

如果A与B平行,则A中的事物与B中的事物同时发生。但是,仍然可以定义执行顺序。

也许困难在于异步这个词是模棱两可的。

当我告诉我的管家跑到商店买更多的葡萄酒和奶酪时,我会执行一项异步任务,然后忘掉他并在我的小说上写作,直到他再次敲门。 并行性在这里发生,但管家和我从事的是根本不同的任务和不同的社会阶层,所以我们在这里不应用这个标签。

当他们每个人都洗一个不同的窗户时,我的女佣团队正在并行工作。

我的赛车支持团队是异步并行的,因为每个团队使用不同的轮胎,他们不需要彼此沟通或在他们完成工作时管理共享资源。

我的足球队(又名足球队)负责并行工作,因为每个球员独立处理关于球场的信息并在球场上移动,但他们并不完全异步,因为他们必须沟通并回应他人的交流。

每个玩家都会读取音乐并控制他们的乐器,但我们的行进乐队也是平行的,但他们是高度同步的:他们在时间上彼此玩耍和游行。

一个凸轮式的格特林枪可以被认为是平行的,但一切都是100%同步的,所以就好像一个过程正在向前发展。


异步 :在别处执行此操作,并在完成(回调)时通知我。 当时我可以继续做我的事情。

并行 :根据需要雇佣许多人(线程),并将工作分配给他们以更快完成,并在完成时让我知道(回调)。 到时候我可能会继续做我的其他东西。

并行性的主要区别主要取决于硬件。


对于未指定内存模型的语言,您正在编写处理器体系结构指定的语言内存模型的代码。 处理器可能会选择重新排序内存访问以获得性能。 因此, 如果您的程序有数据竞争(数据竞争是指多个核心/超线程可以同时访问同一内存),那么您的程序不是跨平台的,因为它依赖于处理器内存模型。 您可以参考Intel或AMD软件手册了解处理器如何重新排序内存访问。

非常重要的是,锁(以及带锁的并发语义)通常以跨平台的方式实现......因此,如果您在没有数据竞争的多线程程序中使用标准锁,那么您不必担心跨平台内存模型

有趣的是,C ++的Microsoft编译器已经获取/释放volatile的语义,这是一个C ++扩展,用于处理C ++中缺少内存模型的问题http://msdn.microsoft.com/en-us/library/12a04hfd(v=vs.80).aspx 。 但是,鉴于Windows只能在x86 / x64上运行,这并不是说很多(英特尔和AMD内存模型使得在语言中实现获取/发布语义变得简单而高效)。





multithreading asynchronous parallel-processing