热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

同步锁同步代码块同步_同步是神话

同步锁同步代码块同步同步是一个神话。没有任何瞬间发生。一切都需要时间。计算系统和编程环境的某些特征从根本上建立在这样一个事实之上,即计算发生在一个三维的物理世界中&#

同步锁同步代码块同步

同步是一个神话。 没有任何瞬间发生。 一切都需要时间。

计算系统和编程环境的某些特征从根本上建立在这样一个事实之上,即计算发生在一个三维的物理世界中,该三维世界由光速和热力学定律强加。

物理世界的这种基础意味着,即使具有新性能点和功能的新技术可用,某些方面仍然保持相关性。 这些原则是正确的,因为它们不仅是“设计选择”。 它们是由物理宇宙的基本现实驱动的。

语言和系统设计中的同步与异步之间的区别是具有深厚物理基础的设计领域的一个示例。 最初,大多数程序员都使用假定有同步行为的基本程序和语言。 实际上,它是如此自然,以至于甚至都没有明确地命名或描述它。 在此上下文中,术语“同步”的含义是,计算是按一系列连续步骤立即进行的,直到计算完成后才进行其他操作。 我执行“ c = a + b”或“ x = f(y)”,直到语句执行完成,才发生其他情况。

当然,在物理宇宙中,什么也不会立即发生。 一切都涉及一些延迟,以导航内存层次结构,执行处理器周期,从磁盘驱动器读取数据或以一定的延迟在某些通信网络上进行通信。 这是光速和三维的基本结果。

一切都涉及一些延迟,消耗一些时间。 如果我们将某些事物定义为同步的,则实际上是在说我们将忽略该延迟,并将其描述为瞬时发生。 实际上,计算机系统经常分配大量的基础结构来继续利用底层硬件,即使它们试图通过将行为视为同步来公开更方便的编程接口。

同步涉及机制和开销的想法对于程序员来说似乎是违反直觉的,因为程序员更习惯于将异步视为需要大量显式机制。 实际上,公开异步接口时实际上发生的是,程序员将更多真正的基础异步信息公开给程序员,以手动进行处理,而不是让系统自动处理。 直接暴露异步给程序员带来了更多的开销,但也允许自定义成本和权衡问题领域,而不是让系统平衡这些成本并进行权衡。 异步接口通常更直接地映射到底层系统中实际发生的事情,并提供其他优化机会。

例如,处理器和内存系统具有适当的基础架构,可以处理通过内存层次结构读取或写入数据。 一级(L1)缓存内存引用可能需要几纳秒,而需要一直导航到L2,L3和主内存的内存引用可能需要100纳秒。 简单地等待内存引用解析将使处理器大部分时间处于闲置状态。

优化这一点的机制很重要; 通过在指令流中向前看并同时进行多个内存获取和存储来进行流水线化,分支预测以尝试继续优化该执行,即使程序跳转到新位置,也要仔细管理内存屏障以确保所有这些复杂操作机制继续将一致的内存模型公开给更高级别的编程环境。 所有这些都试图优化性能并最大程度地利用硬件,同时在内存层次结构中隐藏这10–100 ns纳秒的延迟,从而有可能公开看起来像同步执行的内容,并且仍然可以从核心处理引擎中获得良好的性能。

这些优化对于特定的代码是否有效尚不明确,并且往往需要高度专业的性能工具进行分析。 此类分析工作仅用于有限类型的高价值代码(例如,Excel重新计算引擎或某些核心压缩或密码代码路径)。

从旋转磁盘读取数据等更高的延迟需要不同的机制。 在这种情况下,从磁盘读取的请求将使OS完全切换到其他线程或进程,同时未处理同步请求。 这种机制的高线程切换成本和开销是可以接受的,因为隐藏的等待时间约为毫秒,而不是纳秒。 请注意,这些成本不仅是在运行线程之间进行切换的成本,而且还包括有效闲置和冻结直到该操作完成的所有内存和其他资源的成本。 这些成本都是为了公开此同步接口而产生的。

有很多根本原因,为什么系统可能想要公开真正的底层异步,以及为什么某些组件,层或应用程序更愿意使用异步接口,即使以直接管理增加的复杂性为代价。

并行性。 如果公开的资源具有真正的并行能力,则异步接口可以使客户端更自然地一次发出和管理多个未完成的请求,并可以更充分地利用基础资源。

流水线。 减少某些接口的有效等待时间的一种常用方法是一次处理多个请求(这是否真正对提高性能有用,取决于等待时间的来源)。 无论如何,如果系统适合流水线工作,则可以将有效等待时间减少等于进行中的未完成请求数的因数。 因此,单个请求可能需要10毫秒才能完成,但是用10个请求填充管道可能会看到响应每1毫秒返回一次。 总吞吐量是可用流水线的函数,而不仅仅是单个端到端请求的延迟。 发出请求并等待响应的同步接口将始终看到较长的端到端延迟。

批处理(本地和远程)。 异步接口更自然地允许在本地或在远程资源上实现用于批处理请求的系统(请注意,在这种情况下,“远程”可能位于I / O接口另一端的磁盘控制器中)。 这是因为应用程序在继续其本地处理时已经需要管理一些延迟才能获得响应。 额外的处理可能涉及提出可以自然地一起批处理的额外请求。

在本地进行批处理可以更有效地传输一系列请求,甚至可以在本地压缩和删除重复的请求。 在远程资源处,同时访问整个请求集可以允许进行重大优化。 一个典型的例子是磁盘控制器对读取和写入序列进行重新排序,以利用磁盘头在旋转盘片上的位置,从而最大程度地减少平均寻道时间。 通过将一系列读取或写入同一块的请求分批处理,任何在块级别工作的存储接口都可以看到主要的性能改进。

当然,可以通过同步接口进行本地批处理,但是要么需要掩盖事实真相,要么要求批处理是接口的显式功能,这可能会增加客户端的复杂性。 缓冲IO是“遮蔽真相”的经典示例。 应用程序调用“ write(byte)”,并且接口返回成功,但实际上直到某些缓冲区被填充并刷新后,实际的写操作(以及是否成功完成的事实)才发生,显式刷新了缓冲区或在文件关闭时刷新。 许多应用程序可以忽略这些细节,只有当应用程序需要保证某些交互操作序列并且需要底层的真相时,它才会变得混乱。

解除阻止/解除绑定。 在图形用户界面的上下文中,异步的最常见角色之一是保持核心UI线程不受阻塞,以便应用程序可以继续与用户进行交互。 长时间运行的操作(例如与网络交互)的延迟不能隐藏在同步接口后面。 在这种情况下,UI线程需要显式管理这些异步操作并处理它带来的其他复杂性。

UI只是一个示例,其中组件需要保持对其他请求的响应,因此不能轻易使用隐藏延迟的某种通用机制来简化编程体验。 接收新套接字连接的Web服务器组件通常会将其快速移交给实际上管理套接字上的交互的其他一些异步组件,以便它可以返回到接收和处理新请求。

通常,同步设计倾向于将组件及其处理模型紧密地锁定在一起。 异步交互通常是一种控制耦合并允许松散绑定的机制。

减少和管理开销。 如上所述, 隐藏异步的任何机制都涉及一些资源分配和开销。 对于给定的应用程序来说,这种开销可能是不可接受的,并且将促使应用程序设计人员直接管理固有的异步性。

Web服务器的历史就是一个有趣的例子。 早期的Web服务器(基于Unix构建)会分叉一个单独的进程来管理传入的请求。 然后,该过程可以以大体上同步的方式读取和写入该连接。 该设计的改进减少了开销,但通过使用线程而不是进程来维护交互的总体同步模型。 当前的设计认识到设计的主要重点不是处理模型,而是由在制定响应时读写网络,数据库和文件系统所涉及的IO所主导。 他们通常使用工作队列,并限制在一些固定的线程集中,在这些线程集中可以更明确地管理资源使用情况。

NodeJS在后端开发中的成功不仅仅是因为它利用了成长为构建前端Web界面的大量Javascript开发人员。 像基于浏览器的脚本一样,NodeJS高度关注异步设计,该设计很好地映射到以IO而非处理为主的典型服务器资源负载。

这里另一个有趣的方面是,这些折衷方案更加明确,并且可以由应用程序设计人员使用异步设计进行调整。 在内存层次结构中的延迟示例中,有效延迟(以每个主内存请求的处理器周期为单位)在过去数十年中一直在急剧上升。 处理器设计人员疯狂地争先恐后地添加了额外的缓存层和其他机制,以扩展处理器公开的内存模型,以保持同步处理的功能。

同步IO边界处的上下文切换也是有效权衡随着时间而发生巨大变化的一个示例。 与处理器周期时间相比,IO延迟的改进要慢得多,这意味着当应用程序处于等待IO完成状态时,它放弃了更多的计算机会。 相同的相对成本权衡问题已促使OS设计人员转向内存管理设计,该设计看起来更像是早期的流程交换方法(在此流程开始执行之前,将整个流程内存映像加载到内存中),而不是按需分页。 隐藏每个页面边界可能发生的延迟变得非常困难。 通过较大的串行IO请求与随机请求相比,更好的聚合带宽也推动了这一特定变化。

其他话题

消除

取消是一个复杂的话题。 从历史上看,同步设计在处理取消方面做得很差,包括完全不支持取消。 它固有地必须建模为带外模型,并由单独的执行线程调用。 或者,异步设计更自然地支持取消,包括简单的方法,即简单地决定忽略最终(或不返回)任何响应。 取消随着延迟和实际错误率差异的增加而变得越来越重要-这说明了我们的网络环境随着时间的推移发展得相当不错。

节流/资源管理

同步设计通过在当前请求完成之前不允许应用程序发出其他请求,从而固有地实施了某些限制。 异步设计不会免费节流,可能需要显式解决。 这篇文章描述了Word Web App中的一个示例,其中从同步设计过渡到异步设计引入了重大的资源管理问题。 对于使用某些同步接口的应用程序来说,通常不会在代码中隐含节流,这是很正常的。 消除隐式节流可以(或强制)进行更明确的资源管理。

在将文档编辑器应用程序从Sun的同步图形API移植到X Windows时,我在职业生涯的早期就经历了这一过程。 使用Sun的API,绘图操作是同步执行的,因此客户端直到完成才获得控制权。 在X Windows中,图形请求是通过网络连接异步调度的,然后由窗口服务器(可能在同一台或不同的计算机上)执行。

为了提供良好的交互性能,我们的应用程序将进行一些绘制(例如,确保已更新并绘制了带有光标的当前行),然后检查是否还有更多键盘输入需要读取。 如果有更多输入,它将放弃绘制当前屏幕(在任何情况下,在处理未决输入后通常都会过时),以便读取和处理输入并以最新更改重绘。 调整它可以与同步图形API一起很好地工作。 异步接口接受绘图请求的速度比执行请求的速度快,从而使屏幕滞后于用户输入。 在提供图像的交互式拉伸时,这非常糟糕,因为发出请求的相对成本比实际执行请求的成本低得多。 UI将严重滞后于执行针对每个更新的鼠标位置发出的一系列不必要的重新绘制。

30多年后,这仍然是一个棘手的设计问题(Facebook的iPhone应用程序似乎在某些情况下正遭受此问题的困扰)。 一种替代设计是使屏幕刷新代码(它知道屏幕能够刷新的速度)作为驱动程序,并明确地回调给客户端以绘制区域,而不是由客户端来驱动交互。 这对客户端代码提出了严格的时间要求,以使其有效并且并不总是切合实际。

Windows历史记录

Windows做出了一个早期决定,即主要使用同步接口,并随着时间的推移将该核心方法扩展到数千个API中的100个。 用于访问本地PC资源的早期API通常可能会很快成功或失败,特别是相对于那些早期处理器的速度而言。 同步进程间API的确使Windows程序容易受到包装上较差的书面应用程序的攻击。 随着API扩展到网络和处理器的改进,隐藏在同步接口后面的延迟可能变得很大且变化很大,使得同步方法所涉及的权衡越来越不吸引人。

在API周围“包装线程”实际上可以使此同步接口变为异步状态,而这将占用大量资源,并且无法解决整个大型交互API集中更广泛的跨线程问题。 这是一种特别痛苦的方法,因为线程所做的唯一一件事就是有效地等待一个API完成,而该API本身只是坐在等待来自它所调用的较低级API的一些异步响应。 人们可能会看到具有数百个分配线程的应用程序,其中只有少数实际上正在执行任何实际工作-尽管事实上,线程本质上是处理的抽象,而不是等待。

随着时间的推移,使用线程池和其他技术已有一些改进。 Windows 8和Windows RunTime旨在清除大部分此类遗留物,但实际上已基于较旧的Win32 API的遗留持久性以及在其之上构建的大量代码而无效。

复杂

整个主题最终围绕使用异步设计来构建应用程序的相对挑战和复杂性。 在高级内部Microsoft技术研讨会上的第一次演讲中,我认为异步API是构建无法像当时的PC应用程序那样挂起的应用程序的关键。 在房间的后面,图灵奖得主,个人计算机之父之一巴特勒·兰普森大喊:“但是后来他们也不起作用”! 在接下来的几年中,我与Butler进行了许多富有成果的讨论,他仍然非常关注如何大规模管理异步。

异步设计引入了两个关键问题。 第一个是如何描述异步响应到达后如何重新启动计算。 特别是,关注点在于如何以一种可组合的方式做到这一点,以支持构建由独立组件组成的大型复杂应用程序所需的信息隐藏。 显式的事件驱动状态机很常见。 诸如异步/等待和诺言之类的语言技术适用于问题的这一部分。 更多“原始”方法(如使用回调)在Javascript代码中非常常见。 这些挑战在于,长期存在的程序状态会被埋在黑盒回调中,而黑盒回调通常实际上无法管理和管理。 Async / await允许将异步计算本质上描述为串行,同步代码。 在封面之下,这转化为一组闭包和延续功能。 该技术还提供了异步计算的标准包装器,而不是许多原始的基于回调的代码所采用的即席和不一致的方法。

这些方法都无法解决第二个关键问题。 本质上,问题在于如何隔离中间状态。 在同步设计中,计算过程中使用的任何中间状态都将消失,因此一旦同步计算返回,则将不可用。 异步设计与具有多个线程对共享数据进行操作的设计存在相同的问题(请注意,请注意)。 中间状态被(潜在地)暴露,从而以指数方式增加了总程序状态的有效数量以进行推理。

实际上,状态泄漏在两个方向上都发生。 内部状态可能会暴露给程序的其余部分,而不断变化的外部状态可能会在异步计算内部被引用。 诸如async / await之类的机制有意使代码看起来像串行同步代码,这无助于澄清此处的风险。 实际上,它们掩盖了风险。

与管理复杂性的一般设计挑战一样,隔离(尤其是数据隔离)是应用的关键策略。 图形应用程序的一个挑战是该应用程序很可能希望公开并提供有关这些中间状态的用户反馈。 一个共同的要求是证明在某些计算上取得了进展,或者中断并重新启动受到后续用户活动影响的计算(Word页面布局或Excel重新计算是这两个类别中的经典示例)。 多年来,在许多情况下,我试图确定这些附加程序状态应如何呈现给用户,而不是简单地放置一个等待光标,从而带来了许多额外的复杂性。 当然,对于可能花费很短时间或容易失败的操作,用户想知道到底发生了什么。

无论采用何种策略,纪律严明和始终如一最终都会随着时间的流逝而获得大笔红利。 临时方法很快变得复杂。

结论

世界是异步的。 同步是一个神话,也是一个昂贵的神话。 拥抱异步通常可以允许对系统的基础现实进行更明确的建模,并可以明确管理资源和成本。 复杂性来自不断扩展的程序状态以进行推理; 通过隔离状态并限制特定代码段可以看到的状态数来控制复杂性。

翻译自: https://hackernoon.com/synchrony-is-a-myth-708acaf479f

同步锁同步代码块同步



推荐阅读
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 在Java分层设计模式中,典型的三层架构(3-tier application)将业务应用细分为表现层(UI)、业务逻辑层(BLL)和数据访问层(DAL)。这种分层结构不仅有助于提高代码的可维护性和可扩展性,还能有效分离关注点,使各层职责更加明确。通过合理的设计和实现,三层架构能够显著提升系统的整体性能和稳定性。 ... [详细]
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • Maven Web项目创建时JSP文件常见错误及解决方案
    Maven Web项目创建时JSP文件常见错误及解决方案 ... [详细]
  • V8不仅是一款著名的八缸发动机,广泛应用于道奇Charger、宾利Continental GT和BossHoss摩托车中。自2008年以来,作为Chromium项目的一部分,V8 JavaScript引擎在性能优化和技术创新方面取得了显著进展。该引擎通过先进的编译技术和高效的垃圾回收机制,显著提升了JavaScript的执行效率,为现代Web应用提供了强大的支持。持续的优化和创新使得V8在处理复杂计算和大规模数据时表现更加出色,成为众多开发者和企业的首选。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限
    小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限 ... [详细]
  • SSAS入门指南:基础知识与核心概念解析
    ### SSAS入门指南:基础知识与核心概念解析Analysis Services 是一种专为决策支持和商业智能(BI)解决方案设计的数据引擎。该引擎能够为报告和客户端应用提供高效的分析数据,并支持在多维数据模型中构建高性能的分析应用。通过其强大的数据处理能力和灵活的数据建模功能,Analysis Services 成为了现代 BI 系统的重要组成部分。 ... [详细]
  • 本文详细探讨了几种常用的Java后端开发框架组合及其具体应用场景。通过对比分析Spring Boot、MyBatis、Hibernate等框架的特点和优势,结合实际项目需求,为开发者提供了选择合适框架组合的参考依据。同时,文章还介绍了这些框架在微服务架构中的应用,帮助读者更好地理解和运用这些技术。 ... [详细]
  • 帝国CMS中的信息归档功能详解及其重要性
    本文详细解析了帝国CMS中的信息归档功能,并探讨了其在内容管理中的重要性。通过归档功能,用户可以有效地管理和组织大量内容,提高网站的运行效率和用户体验。此外,文章还介绍了如何利用该功能进行数据备份和恢复,确保网站数据的安全性和完整性。 ... [详细]
  • 本文深入探讨了NoSQL数据库的四大主要类型:键值对存储、文档存储、列式存储和图数据库。NoSQL(Not Only SQL)是指一系列非关系型数据库系统,它们不依赖于固定模式的数据存储方式,能够灵活处理大规模、高并发的数据需求。键值对存储适用于简单的数据结构;文档存储支持复杂的数据对象;列式存储优化了大数据量的读写性能;而图数据库则擅长处理复杂的关系网络。每种类型的NoSQL数据库都有其独特的优势和应用场景,本文将详细分析它们的特点及应用实例。 ... [详细]
  • 如何撰写适应变化的高效代码:策略与实践
    编写高质量且适应变化的代码是每位程序员的追求。优质代码的关键在于其可维护性和可扩展性。本文将从面向对象编程的角度出发,探讨实现这一目标的具体策略与实践方法,帮助开发者提升代码效率和灵活性。 ... [详细]
  • 如何撰写初级和高级前端开发者的专业简历
    如何撰写初级和高级前端开发者的专业简历 ... [详细]
  • 本文深入解析了Django框架中的MVT(Model-View-Template)设计模式,详细阐述了其工作原理和应用流程。通过分析URL模式、视图、模型和模板等关键组件,读者将全面理解Django应用程序的架构体系,掌握如何高效地构建和管理Web应用。 ... [详细]
author-avatar
老6李家小宝
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有