精华内容
下载资源
问答
  • 关于微服务架构的描述

    千次阅读 2019-06-18 17:47:54
    过去几年中出现了“微服务架构”这一术语,它描述了将软件应用程序设计为若干个可独立部署服务套件特定方法。尽管这种架构风格尚未有精确定义,但围绕业务能力、自动部署、端点智能以及语言和数据分散控制等...

    微服务


    过去几年中出现了“微服务架构”这一术语,它描述了将软件应用程序设计为若干个可独立部署的服务套件的特定方法。尽管这种架构风格尚未有精确的定义,但围绕业务能力、自动部署、端点智能以及语言和数据的分散控制等组织来说,它们还是存在着某些共同特征。

    “微服务”——在拥挤的软件架构街道上又一个新名词。虽然我们的自然倾向是对它轻蔑一瞥,但这一术语描述了一种越来越具有吸引力的软件系统风格。在过去几年中,我们已经看到许多项目使用了这种风格,到目前为止其结果都是正向的,以至于它变成了我们 ThoughtWorks 许多同事构建企业应用程序的默认风格。然而遗憾的是,并没有太多信息可以概述微服务的风格以及如何实现。

    简而言之,微服务架构风格[1]是一种将单个应用程序开发为一套小型服务的方法,每个小型服务都在自己的进程中运行,并以轻量级机制(通常是 HTTP 资源 API)进行通信。这些服务围绕业务功能构建,可通过全自动部署机制来独立部署。这些服务共用一个最小型的集中式管理,它们可以使用不同的编程语言编写,并使用不同的数据存储技术。

    在开始解释微服务风格之前,将它与单片(monolithic)风格进行比较是有用的:单片应用程序被构建为单一单元。企业应用程序通常由三个部分构成:客户端用户界面(由用户机器上的浏览器中运行的 HTML 页面和 Javascript 组成)、数据库(由许多表组成,通常是在关系型数据库中管理)系统、服务器端应用程序。服务器端应用程序处理 HTTP 请求,执行一些逻辑处理,从数据库检索和更新数据,选择数据并填充到要发送到浏览器的 HTML 视图中。这个服务器端应用程序是一个整体——一个逻辑可执行文件[2]。对系统的任何更改都涉及构建和部署新版本的服务器端应用程序。

    这种单片服务器是构建这种系统的自然方式。处理一个请求的所有逻辑都在一个进程中运行,允许你使用语言的基本功能将应用程序划分为类、函数和命名空间。需要注意的是,你可以在开发人员的笔记本电脑上运行和测试应用程序,并使用部署管道确保对程序做出的改动被适当测试并部署到生产环境中。你可以通过在负载均衡器后面运行许多实例来水平扩展整体块。

    单片应用程序可以取得成功,但越来越多的人对它们感到不满——尤其是在将更多应用程序部署到云的时候。变更周期被捆绑在一起——即使只是对应用程序的一小部分进行了更改,也需要重建和部署整个单片应用。随着时间的推移,通常很难保持良好的模块化结构,也更难以保持应该只影响该模块中的一个模块的更改。对系统进行扩展时,不得不扩展整个应用系统,而不能仅扩展该系统中需要更多资源的那些部分。

    这些不满催生了微服务架构风格:将应用程序构建为服务套件。除了服务可独立部署、独立扩展的事实之外,每个服务还提供了一个牢固的模块边界,甚至允许以不同的编程语言编写不同的服务。他们也可以由不同的团队管理。

    我们并不认为微服务风格是新颖的或创新的,其根源至少可以追溯到 Unix 的设计原则。但我们认为没有足够多的人考虑微服务架构,如果使用它,许多软件的开发会变得更好。

    微服务架构的特征

    虽然不能说微服务架构风格有正式的定义,但我们可以尝试描述一下我们认为的在符合这个标签的架构中,它们所具有的一些共同特征。与概述共同特征的任何定义一样,并非所有微服务架构都具有所有特征,但我们确实期望大多数微服务架构都具有大多数特征。虽然我们的作者一直是这个相当宽松的社区的活跃成员,但我们的本意还是尝试描述我们两人在自己和自己所了解的团队的工作中所看到的情况。特别要说明的是,我们没有制定一些相关的定义。

    通过服务进行组件化

    只要我们参与软件行业,就一直希望通过将组件集成在一起来构建系统,就像我们在物理世界中看到的事物的构建方式一样。在过去的几十年中,我们已经看到了大多数语言平台的公共软件库都取得了极大的进展。

    在谈论组件时,就会碰到一个有关定义的难题,即什么是组件?我们的定义是,组件是可独立更换和升级的软件单元。

    微服务架构也会使用软件库,但组件化软件的主要方式是拆分为多个服务。我们把库定义为链接到程序并使用内存函数调用来调用的组件,而服务是一种进程外组件,通过 Web 服务请求或远程过程调用等机制进行通信。(这与许多面向对象程序中的服务对象的概念是不同的[3]。)

    将服务作为组件(而不是库)的一个主要原因是服务可以独立部署。如果你有一个应用程序[4]是由单一进程里的多个库组成,任何一个组件的更改都会导致整个应用程序的重新部署。但如果应用程序可拆分为多个服务,那么单个服务的变更只需要重新部署该服务即可。当然这也不是绝对的,一些服务接口的修改可能会导致多个服务之间的协同修改,但一个好的微服务架构的目的是通过内聚服务边界和服务协议的演进机制来最小化这些协同修改。

    将服务用作组件的另一个结果是更明确的组件接口。大多数语言没有一个良好的机制来定义显式发布的接口。通常,它只是文档和规则来阻止客户端破坏组件的封装,这会导致组件之间过于紧耦合。通过使用显式远程调用机制,服务可以更轻松地避免这种情况。

    像这样使用服务确实存在一些不好的地方。远程调用比进程内调用更昂贵,远程 API 需要设计成较粗的粒度,这通常更难以使用。如果你需要更改组件之间的职责分配,那么当你跨越进程边界时,这种组件行为的改动会更加难以实现。

    近似地,我们可以把一个个服务映射为一个个运行时进程,但这仅仅是一个近似而已。一个服务可能包括多个始终一起开发和部署的进程,比如一个应用系统的进程和仅由该服务使用的数据库。

    围绕业务能力进行组织

    在将大型应用程序拆分为多个部分时,管理层往往侧重于技术层面,从而导致 UI 团队、服务器端逻辑团队、数据库团队的划分。当团队按照这些方式分开时,即便是简单的更改也可能导致跨团队项目的时间和预算批准。一个聪明的团队将围绕这个进行优化,“两害相权取其轻”——只需将逻辑强制应用到他们可以访问的任何应用程序中。换句话说,逻辑无处不在。这是康威定律[5]的一个例子。

    任何设计系统(广义上的)的组织都会产生一种设计,其结构是组织通信结构的副本。
    —— 梅尔文•康威,1967年

    微服务采用不同的划分方式,它是围绕业务功能将系统拆分为多个服务 。这些服务为该业务领域采用广泛的软件实现,包括用户界面、持久化存储和任何外部协作。因此,团队是跨职能的,包括开发所需的全部技能:用户体验、数据库和项目管理。

    以这种方式组建的一家公司是 www.comparethemarket.com。跨职能团队负责构建和运营每个产品,每个产品拆分为多个独立的服务,彼此通过消息总线来通信。

    大型单片应用程序也可以围绕业务功能进行模块化,尽管这不是常见的情况。当然,我们会敦促构建单块应用系统的大型团队根据业务线来将自己分解为若干小团队。我们在这里看到的主要问题是,它们往往围绕太多的上下文进行组织。如果单体跨越了模块边界,对团队的个体成员来说,很难将它们装入短期的记忆中。此外,我们看到模块化生产线需要大量的规则来执行。服务组件所要求的更加明确的分离,使得它更容易保持团队边界清晰。

    是产品不是项目

    我们看到的大多数应用程序开发工作都使用这样一个项目模式:目标是交付一些软件,然后就完工了。一旦完成后,软件将移交给维护组织,然后构建它的项目团队也随之解散了。

    微服务支持者倾向于避免这种模式,而是认为团队应该负责产品的整个生命周期。对此一个共同的启示是亚马逊的 “you build, you run it” 的概念,开发团队对生产中的软件负全部责任。这使开发者经常接触他们的软件在生产环境如何工作,并增加与他们的用户联系,因为他们必须承担至少部分的支持工作。

    产品心态与业务能力的联系紧密相连。要持续关注软件如何帮助用户提升业务能力,而不是把软件看成是将要完成的一组功能。

    没有理由说为什么这种方法不能用在单一应用程序上,但较小的服务粒度,使得它更容易在服务开发者和用户之间建立个人关系。

    智能端点和哑管

    在不同进程之间建立通信时,我们已经看到许多产品和方法,都强调将大量的智能特性放入通信机制本身。一个很好的例子是企业服务总线(ESB),其中 ESB 产品通常包括用于消息路由、编排、转换和应用业务规则的复杂工具。

    微服务社区倾向于采用另一种方法:智能端点和哑管。基于微服务构建的应用程序的目标是尽可能的解耦和尽可能的内聚——他们拥有自己的领域逻辑,他们的行为更像经典 UNIX 理念中的过滤器——接收请求,应用适当的逻辑并产生响应。使用简单的 REST 风格的协议来编排它们,而不是使用像 WS-Choreography 或者 BPEL 或者通过中心工具编制(orchestration)等复杂的协议。

    最常用的两种协议是带有资源 API 的 HTTP 请求-响应和轻量级消息传递[8]。对第一种协议最好的表述是

    本身就是 web,而不是隐藏在 web 的后面。
    ——Ian Robinson

    微服务团队使用的规则和协议,正是构建万维网的规则和协议(在更大程度上是 UNIX 的)。从开发者和运营人员的角度讲,通常使用的资源可以很容易的缓存。

    第二种常用方法是在轻量级消息总线上传递消息。选择的基础设施是典型的哑的(哑在这里只充当消息路由器)——像 RabbitMQ 或 ZeroMQ 这样简单的实现仅仅提供一个可靠的异步交换结构 ——在服务里,智能特性仍旧存在于那些生产和消费诸多消息的各个端点中,即存在于各个服务中。

    单体应用中,组件都在同一进程内执行,它们之间通过方法调用或函数调用通信。把单体变成微服务最大的问题在于通信模式的改变。一种幼稚的转换是从内存方法调用转变成 RPC,这导致频繁通信且性能不好。相反,你需要用粗粒度通信代替细粒度通信。

    去中心化的治理

    集中治理的一个后果是单一技术平台的标准化发展趋势。经验表明,这种方法正在收缩 ——不是每个问题都是钉子,不是每个问题都是锤子。我们更喜欢使用正确的工具来完成工作,而单体应用程序在一定程度上可以利用语言的优势,这是不常见的。

    把单体的组件分裂成服务,在构建这些服务时可以有自己的选择。你想使用 Node.js 开发一个简单的报告页面?去吧。用 C++ 实现一个特别粗糙的近乎实时的组件?好极了。你想换用一个更适合组件读操作数据的不同风格的数据库?我们有技术来重建它。

    当然,仅仅因为你可以做些什么,而不意味着你应该这样做——但用这种方式划分系统意味着你可以选择。

    团队在构建微服务时也更喜欢用不同的方法来达标。他们更喜欢生产有用的工具这种想法,而不是写在纸上的标准,这样其他开发者可以用这些工具解决他们所面临的相似的问题。有时,这些工具通常在实施中收获并与更广泛的群体共享,但不完全使用一个内部开源模型。现在 git 和 github 已经成为事实上的版本控制系统的选择,在内部开放源代码的实践也正变得越来越常见。

    Netflix 是遵循这一理念的一个很好的例子。尤其是,以库的形式分享有用的且经过市场检验的代码,这激励其他开发者用类似的方式解决相似的问题,同时还为采用不同方法敞开了大门。共享库倾向于聚焦在数据存储、进程间通信和我们接下来要深入讨论的基础设施自动化的共性问题。

    对于微服务社区来说,开销特别缺乏吸引力。这并不是说社区不重视服务合约。恰恰相反,因为他们有更多的合约。只是他们正在寻找不同的方式来管理这些合约。像 Tolerant Reader 和 Consumer-Driven Contracts 这样的模式通常被用于微服务。这些援助服务合约在独立进化。执行消费者驱动的合约作为构建的一部分,增加了信心并对服务是否在运作提供了更快的反馈。事实上,我们知道澳大利亚的一个团队用消费者驱动的合约这种模式来驱动新业务的构建。他们使用简单的工具定义服务的合约。这已变成自动构建的一部分,即使新服务的代码还没写。服务仅在满足合约的时候才被创建出来 - 这是在构建新软件时避免 "YAGNI"[9] 困境的一个优雅的方法。围绕这些成长起来的技术和工具,通过减少服务间的临时耦合,限制了中心合约管理的需要。

    也许去中心化治理的最高境界就是亚马逊广为流传的 build it/run it 理念。团队要对他们构建的软件的各方面负责,包括 7*24 小时的运营。这一级别的责任下放绝对是不规范的,但我们看到越来越多的公司让开发团队负起更多责任。Netflix 是采用这一理念的另一家公司[11]。每天凌晨 3 点被传呼机叫醒无疑是一个强有力的激励,使你在写代码时关注质量。这是关于尽可能远离传统的集中治理模式的一些想法。

    分散数据管理

    数据管理的去中心化有许多不同的呈现方式。在最抽象的层面上,这意味着使系统间存在差异的世界概念模型。在整合一个大型企业时,客户的销售视图将不同于支持视图,这是一个常见的问题。客户的销售视图中的一些事情可能不会出现在支持视图中。它们确实可能有不同的属性和(更坏的)共同属性,这些共同属性在语义上有微妙的不同。

    这个问题常见于应用程序之间,但也可能发生在应用程序内部,尤其当应用程序被划分成分离的组件时。一个有用的思维方式是有界上下文(Bounded Context)内的领域驱动设计(Domain-Driven Design, DDD)理念。DDD 把一个复杂域划分成多个有界的上下文,并且映射出它们之间的关系。这个过程对单体架构和微服务架构都是有用的,但在服务和上下文边界间有天然的相关性,边界有助于澄清和加强分离,就像业务能力部分描述的那样。

    和概念模型的去中心化决策一样,微服务也去中心化数据存储决策。虽然单体应用程序更喜欢单一的逻辑数据库做持久化存储,但企业往往倾向于一系列应用程序共用一个单一的数据库——这些决定是供应商授权许可的商业模式驱动的。微服务更倾向于让每个服务管理自己的数据库,或者同一数据库技术的不同实例,或完全不同的数据库系统 - 这就是所谓的混合持久化(Polyglot Persistence)。你可以在单体应用程序中使用混合持久化,但它更常出现在为服务里。

    对跨微服务的数据来说,去中心化责任对管理升级有影响。处理更新的常用方法是在更新多个资源时使用事务来保证一致性。这个方法通常用在单体中。

    像这样使用事务有助于一致性,但会产生显著地临时耦合,这在横跨多个服务时是有问题的。分布式事务是出了名的难以实现,因此微服务架构强调服务间的无事务协作,对一致性可能只是最后一致性和通过补偿操作处理问题有明确的认知。

    对很多开发团队来说,选择用这样的方式管理不一致性是一个新的挑战,但这通常与业务实践相匹配。通常业务处理一定程度的不一致,以快速响应需求,同时有某些类型的逆转过程来处理错误。这种权衡是值得的,只要修复错误的代价小于更大一致性下损失业务的代价。

    基建自动化

    基础设施自动化技术在过去几年中发生了巨大变化——特别是云和 AWS 的发展降低了构建、部署和运行微服务的操作复杂性。

    许多使用微服务构建的产品或系统都是由具有丰富的持续交付和持续集成经验的团队构建的。以这种方式构建软件的团队广泛使用基础设施自动化技术。如下面显示的构建管道所示。

    由于这并不是一篇关于持续交付的文章,我们在这里只关注持续交付的几个关键特性。我们希望有尽可能多的信心确保我们的软件正常运行,因此我们进行了大量的自动化测试。想让软件达到“晋级”(Promotion)状态从而“推上”流水线,就意味着要在每一个新的环境中,对软件进行自动化部署

    一个单块应用程序可以非常愉快地通过这些环境构建、测试和推动。事实证明,一旦你为单体投入了自动化整体生产,那么部署更多的应用程序似乎不再那么可怕了。请记住,持续交付的目标之一就是让“部署”工作变得“枯燥”,所以无论是一个还是三个应用程序,只要部署工作依旧很“枯燥”,那么就没什么可担心的了[12]。

    我们看到团队大量的基础设施自动化的另一个领域是在管理生产环境中的微服务。与我们上面的断言(只要部署很无聊)相比,单块和微服务之间没有太大的区别,但是每个部署的运行环境可能会截然不同。

    设计时为故障做好准备

    使用服务作为组件的结果是,需要设计应用程序以便它们能够容忍服务的失败。如果服务提供者商不可用,任何服务呼叫都可能失败,客户必须尽可能优雅地对此做出响应。与单片设计相比,这是一个缺点,因为它这会引入额外的复杂性来处理它。结果是微服务团队不断反思服务失败是如何影响用户体验的。Netflix 的 Simian Army 能够引发服务甚至数据中心的故障在工作日发生故障,从而来测试应用程序的弹性和监控能力。

    生产中的这种自动化测试足以让大多数运维团队兴奋得浑身颤栗,就像在一周的长假即将到来前一样。这并不是说单块架构风格不能构建先进的监控系统——只是根据我们的经验,这在单块系统中并不常见罢了。

    由于服务可能随时发生故障,因此能够快速检测故障并在可能的情况下自动恢复服务就显得至关重要。微服务应用程序非常重视应用程序的实时监控,比如检查架构元素(数据库每秒获得多少请求)和业务相关度量(例如每分钟收到多少订单)。语义监控可以提供出现问题的早期预警系统,从而触发开发团队跟进和调查。

    这对于微服务架构来说尤为重要,因为微服务偏好编排和事件写作,这会导致一些紧急状况。虽然许多权威人士对于偶然事件的价值持积极态度,但事实是,“突发行为”有时可能是一件坏事。监控至关重要,它能够快速发现不良紧急行为并进行修复。

    单块系统也可以像微服务一样实现透明的监控——事实上,它们也应该如此。不同之处在于你必须能够知道在不同进程中运行的服务在何时断开了连接。对于同一过程中的库,这种透明性用处并不大。

    微服务团队希望看到针对每个服务的复杂监控和日志记录,例如显示“运行/宕机”状态的仪表盘以及各种运维和业务相关的指标。有关断路器状态,当前吞吐量和延迟的详细信息也是我们在工作中经常遇到的其他例子。

    演化设计

    微服务从业者通常有进化设计的背景,并把服务分解视为进一步的工具,使应用程序开发人员能够控制应用程序中的更改,而不会降低变更速度。变更控制并不一定意味着变更的减少——在正确的态度和工具的帮助下,你可以对软件进行频繁,快速且有良好控制的更改。

    每当要试图将软件系统分解为组件时,你就会面临这样的决策,即如何进行拆分——我们决定拆分应用程序的原则是什么?组件的关键属性具有独立替换和可升级性的特点[13]——这意味着我们寻找这些点,想象如何在不影响其协作者的情况下重写组件。实际上,许多微服务组通过明确地期望许多服务被废弃而不是长期演变来进一步考虑这一点。

    Guardian 网站是设计和构建成单块应用程序的一个很好的例子,但是它也在微服务方向上不断发展演化。原先的单块系统仍然是网站的核心,但他们更喜欢通过构建一些微服务 API 的方式来添加新的功能。这种方法对于本质上是临时的功能尤其方便,例如处理体育赛事的专用页面。网站的这一部分可以使用快速开发语言快速组合在一起,在赛事结束后立即删除。我们在金融机构看到过类似的方法,为市场机会增加新服务,并在几个月甚至几周后丢弃。

    这种强调可替换性的特点,是模块化设计一般性原则的一个特例,即通过变化模式来驱动模块化的实现[14]。大家都愿意将那些同时发生变化的东西放在同一个模块,很少变化的系统模块应该与目前正在经历大量变动的系统处于不同的服务中。如果你发现自己反复更改两项服务,那就表明它们应该合并了。

    将组件放入服务中可以为更细粒度的发布计划添加机会。对于单体来说,任何更改都需要完整构建和部署整个应用程序。但是,使用微服务,你只需要重新部署你修改的服务。这可以简化并加快发布过程。缺点是你必须担心一项服务的变化会打破其消费者。传统的集成方法是尝试使用版本控制来解决这个问题,但微服务世界中的偏好是仅仅把使用版本控制作为最后的手段。我们可以通过设计服务尽可能容忍服务提供者的变化来避免大量的版本控制。

    微服务是未来吗?

    我们写这篇文章的主要目的是解释微服务的主要思想和原则。通过花时间来做到这一点,我们清楚地认为微服务架构风格是一个重要的想法——在研发企业系统时,值得对它进行认真考虑。我们最近使用这种方式构建了几个系统,并且了解到其它团队也赞同这种风格。

    我们了解到那些在某种程度上开创这种架构风格的先驱,包括亚马逊、Netflix、英国卫报、英国政府数字化服务中心、realestate.com.au、Forward 和 comparethemarket.com。2013 年的技术会议上充满了一些公司的例子,这些公司正在转向可以归类为微服务的公司,包括 Travis CI。此外,有很多组织长期以来一直在做我们称之为微服务的东西,但没有使用过这个名字。(通常这被标记为 SOA——尽管如我们所说,SOA 有许多相互矛盾的形式。[15])

    然而,尽管有这些积极的经验,但并不是说我们确信微服务是软件架构的未来发展方向。虽然到目前为止我们的经验与整体应用相比是积极的,但我们意识到没有足够的时间让我们做出充分完整的判断。

    通常,架构决策所产生的真正效果,只有在该决策做出若干年后才能真正显现。我们已经看到由带着强烈的模块化愿望的优秀团队所做的一些项目,最终却构建出一个单块架构,并在几年之内不断腐化。许多人认为,如果使用微服务就不大可能出现这种腐化,因为服务的边界是明确的,而且难以随意搞乱。然而,对于那些开发时间足够长的各种系统,除非我们已经见识得足够多,否则我们无法真正评价微服务架构是如何成熟的。

    有人觉得微服务或许很难成熟起来,这当然是有原因的。在组件化上所做的任何工作的成功与否,取决于软件与组件的匹配程度。准确地搞清楚某个组件的边界的位置应该出现在哪里,是一项困难的工作。进化设计承认难以对边界进行正确定位,所以它将工作的重点放到了易于对边界进行重构之上。但是当各个组件成为各个进行远程通信的服务后,比起在单一进程内进行各个软件库之间的调用,此时的重构就变得更加困难。跨越服务边界的代码移动就变得困难起来。接口的任何变化,都需要在其各个参与者之间进行协调。向后兼容的层次也需要被添加进来。测试也会变得更加复杂。

    另一个问题是,如果这些组件不能干净利落地组合成一个系统,那么所做的一切工作,仅仅是将组件内的复杂性转移到组件之间的连接之上。这样做的后果,不仅仅是将复杂性搬了家,它还将复杂性转移到那些不再明确且难以控制的边界之上。当在观察一个小型且简单的组件内部时,人们很容易觉得事情已经变得更好了,然而他们却忽视了服务之间杂乱的连接。

    最后,还有一个团队技能的因素。新技术往往会被技术更加过硬的团队所采用。对于技术更加过硬的团队而更有效的一项技术,不一定适用于一个技术略逊一筹的团队。我们已经看到大量这样的案例,那些技术略逊一筹的团队构建出了杂乱的单块架构。当这种杂乱发生到微服务身上时,会出现什么情况?这需要花时间来观察。一个糟糕的团队,总会构建一个糟糕的系统——在这种情况下,很难讲微服务究竟是减少了杂乱,还是让事情变得更糟。

    我们听到的一个合理的论点是,你不应该从微服务架构开始,而是从整体开始,保持模块化,并在整体出现问题时将其拆分为微服务。(这个建议并不理想,因为好的进程内接口通常不是一个好的服务接口。)

    所以我们谨慎乐观地写下这个。到目前为止,我们已经看到了足够多的微服务风格,觉得它可能是一条值得走的路。我们无法确定最终会在哪里结束,但软件开发的挑战之一是你只能根据你当前必须拥有的不完善信息做出决策。

    脚注

    1: The term "microservice" was discussed at a workshop of software architects near Venice in May, 2011 to describe what the participants saw as a common architectural style that many of them had been recently exploring. In May 2012, the same group decided on "microservices" as the most appropriate name. James presented some of these ideas as a case study in March 2012 at 33rd Degree in Krakow in Microservices - Java, the Unix Way as did Fred George about the same time. Adrian Cockcroft at Netflix, describing this approach as "fine grained SOA" was pioneering the style at web scale as were many of the others mentioned in this article - Joe Walnes, Dan North, Evan Botcher and Graham Tackley.

    2: The term monolith has been in use by the Unix community for some time. It appears in The Art of Unix Programming to describe systems that get too big.

    3: Many object-oriented designers, including ourselves, use the term service object in the Domain-Driven Design sense for an object that carries out a significant process that isn't tied to an entity. This is a different concept to how we're using "service" in this article. Sadly the term service has both meanings and we have to live with the polyseme.

    4: We consider an application to be a social construction that binds together a code base, group of functionality, and body of funding.

    5: The original paper can be found on Melvyn Conway's website here.

    6: We can't resist mentioning Jim Webber's statement that ESB stands for "Egregious Spaghetti Box".

    7: Netflix makes the link explicit - until recently referring to their architectural style as fine-grained SOA.

    8: At extremes of scale, organisations often move to binary protocols - protobufs for example. Systems using these still exhibit the characteristic of smart endpoints, dumb pipes - and trade off transparency for scale. Most web properties and certainly the vast majority of enterprises don't need to make this tradeoff - transparency can be a big win.

    9: "YAGNI" or "You Aren't Going To Need It" is an XP principle and exhortation to not add features until you know you need them.

    10: It's a little disengenuous of us to claim that monoliths are single language - in order to build systems on todays web, you probably need to know JavaScript and XHTML, CSS, your server side language of choice, SQL and an ORM dialect. Hardly single language, but you know what we mean.

    11: Adrian Cockcroft specifically mentions "developer self-service" and "Developers run what they wrote"(sic) in this excellent presentation delivered at Flowcon in November, 2013.

    12: We are being a little disengenuous here. Obviously deploying more services, in more complex topologies is more difficult than deploying a single monolith. Fortunately, patterns reduce this complexity - investment in tooling is still a must though.

    13: In fact, Dan North refers to this style as Replaceable Component Architecture rather than microservices. Since this seems to talk to a subset of the characteristics we prefer the latter.

    14: Kent Beck highlights this as one his design principles in Implementation Patterns.

    15: And SOA is hardly the root of this history. I remember people saying "we've been doing this for years" when the SOA term appeared at the beginning of the century. One argument was that this style sees its roots as the way COBOL programs communicated via data files in the earliest days of enterprise computing. In another direction, one could argue that microservices are the same thing as the Erlang programming model, but applied to an enterprise application context.

     

    展开全文
  • 抽象指对现实世界问题和实体本质表现,行为和特征建模,建立一个相关子集,可以用于 绘程序结构,从而实现这种模型。抽象不仅包括这种模型数据属性,还定义了这些数据接口。对某种抽象实现就是对此数据及与之...

    抽象指对现实世界问题和实体的本质表现,行为和特征建模,建立一个相关的子集,可以用于 绘程序结构,从而实现这种模型。抽象不仅包括这种模型的数据属性,还定义了这些数据的接口。

    对某种抽象的实现就是对此数据及与之相关接口的现实化(realization)。现实化这个过程对于客户 程序应当是透明而且无关的。

    封装/接口

    封装描述了对数据/信息进行隐藏的观念,它对数据属性提供接口和访问函数。通过任何客户端直接对数据的访问,无视接口,与封装性都是背道而驰的,除非程序员允许这些操作。作为实现的 一部分,客户端根本就不需要知道在封装之后,数据属性是如何组织的。在Python中,所有的类属性都是公开的,但名字可能被“混淆”了,以阻止未经授权的访问,但仅此而已,再没有其他预防措施了。这就需要在设计时,对数据提供相应的接口,以免客户程序通过不规范的操作来存取封装的数据属性。

    注意:封装绝不是等于“把不想让别人看到、以后可能修改的东西用private隐藏起来”

    真正的封装是,经过深入的思考,做出良好的抽象,给出“完整且最小”的接口,并使得内部细节可以对外透明

    (注意:对外透明的意思是,外部调用者可以顺利的得到自己想要的任何功能,完全意识不到内部细节的存在)

    合成

    合成扩充了对类的 述,使得多个不同的类合成为一个大的类,来解决现实问题。合成 述了 一个异常复杂的系统,比如一个类由其它类组成,更小的组件也可能是其它的类,数据属性及行为, 所有这些合在一起,彼此是“有一个”的关系。

    派生/继承/继承结构

    派生描述了子类衍生出新的特性,新类保留已存类类型中所有需要的数据和行为,但允许修改或者其它的自定义操作,都不会修改原类的定义。

    继承描述了子类属性从祖先类继承这样一种方式

    继承结构表示多“代”派生,可以述成一个“族谱”,连续的子类,与祖先类都有关系。

    泛化/特化

    基于继承

    泛化表示所有子类与其父类及祖先类有一样的特点。

    特化描述所有子类的自定义,也就是,什么属性让它与其祖先类不同。

    多态与多态性

    多态指的是同一种事物的多种状态:水这种事物有多种不同的状态:冰,水蒸气

    多态性的概念指出了对象如何通过他们共同的属性和动作来操作及访问,而不需考虑他们具体的类。

    冰,水蒸气,都继承于水,它们都有一个同名的方法就是变成云,但是冰.变云(),与水蒸气.变云()是截然不同的过程,虽然调用的方法都一样

    自省/反射

    自省也称作反射,这个性质展示了某对象是如何在运行期取得自身信息的。如果传一个对象给你,你可以查出它有什么能力,这是一项强大的特性。如果Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工作。还有那些特殊属性,像__dict__,__name__及__doc__

    四、类

    类有两种作用:属性引用和实例化

    属性引用(类名.属性)

    classGaren:

    camp='Demacia'

    defattack(self):print('attack')

    #引用类的特征(类的变量)和技能(类的函数)

    print(Garen.camp)print(Garen.attack)

    Garen.attack(1231231)

    实例化(__init__与self)

    x=int(10)print(x)

    obj=Garen() #实例化

    print(obj)

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    1 classGaren:2 camp='Demacia'

    3

    4 def __init__(self,nickname):5 self.nick=nickname #g1.nick='草丛伦'

    6 defattack(self,enemy):7 #print('---------->',self.nick) #g1.nick

    8 print('%s attack %s' %(self.nick,enemy))9

    10

    11 g1=Garen('草丛伦') #Garen.__init___(g1,'草丛伦')

    12 g2=Garen('猥琐轮')13 print(g1.nick)14 g1.attack('alex')15

    16 print(g1.nick)17 print(g1.camp)18 print(g1.attack)19 print(Garen.attack)20

    21 Garen.attack() #调用的是函数

    22 g1.attack() #self=g1

    23 Garen.attack(g1)24

    25 print(g2.nick)26 print(g2.camp)27

    28 如何使用实例

    如何使用实例

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    1 #总结:

    2 #类:一:实例化,二:引用名字(类名.变量名,类名.函数名)

    3 #实例:引用名字(实例名.类的变量,实例名.绑定方法,实例名.实例自己的变量名)

    4

    5 classGaren:6 camp='Demacia'

    7

    8 def __init__(self,nickname):9 self.nick=nickname #g1.nick='草丛伦'

    10 defattack(self,enemy):11 #print('---------->',self.nick) #g1.nick

    12 print('%s attack %s' %(self.nick,enemy))13

    14 #print(Garen.camp) #查

    15 #Garen.camp='aaaaaa' #改

    16 #print(Garen.camp)

    17 #18 ## del Garen.camp #删除

    19 ## print(Garen.camp)

    20 #21 #Garen.x=1

    22 #print(Garen.x)

    23

    24

    25 g1=Garen('alex')26 #print(g1.nick)

    27 #g1.nick='asb'

    28 #print(g1.nick)

    29 #del g1.nick

    30 #print(g1.nick)

    31

    32 #g1.sex='female'

    33 #print(g1.sex)

    34

    35 总结

    总结

    类特殊成员:

    1. __doc__

    表示类的描述信息

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    classFoo:"""描述类信息,这是用于看片的神奇"""

    deffunc(self):pass

    print Foo.__doc__

    #输出:类的描述信息

    View Code

    2. __module__ 和  __class__

    __module__ 表示当前操作的对象在那个模块

    __class__     表示当前操作的对象的类是什么

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    #!/usr/bin/env python#-*- coding:utf-8 -*-

    classC:def __init__(self):

    self.name= 'wupeiqi'lib/aa.py

    View Code

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    from lib.aa importC

    obj=C()print obj.__module__ #输出 lib.aa,即:输出模块

    print obj.__class__ #输出 lib.aa.C,即:输出类

    View Code

    3. __init__

    构造方法,通过类创建对象时,自动触发执行。

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    classFoo:def __init__(self, name):

    self.name=name

    self.age= 18obj= Foo('wupeiqi') #自动执行类中的 __init__ 方法

    View Code

    4. __del__

    析构方法,当对象在内存中被释放时,自动触发执行。

    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

    classFoo:def __del__(self):pass

    5. __call__

    对象后面加括号,触发执行。

    注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    classFoo:def __init__(self):pass

    def __call__(self, *args, **kwargs):print '__call__'obj= Foo() #执行 __init__

    obj() #执行 __call__

    View Code

    6. __dict__

    类或对象中的所有成员

    上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:

    ec250bd1726549af66c32067422ea7e6.png

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    classProvince:

    country= 'China'

    def __init__(self, name, count):

    self.name=name

    self.count=countdef func(self, *args, **kwargs):print 'func'

    #获取类的成员,即:静态字段、方法、

    print Province.__dict__

    #输出:{'country': 'China', '__module__': '__main__', 'func': , '__init__': , '__doc__': None}

    obj1= Province('HeBei',10000)print obj1.__dict__

    #获取 对象obj1 的成员#输出:{'count': 10000, 'name': 'HeBei'}

    obj2= Province('HeNan', 3888)print obj2.__dict__

    #获取 对象obj1 的成员#输出:{'count': 3888, 'name': 'HeNan'}

    View Code

    7. __str__

    如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    classFoo:def __str__(self):return 'wupeiqi'obj=Foo()printobj#输出:wupeiqi

    View Code

    8、__getitem__、__setitem__、__delitem__

    用于索引操作,如字典。以上分别表示获取、设置、删除数据

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    #!/usr/bin/env python#-*- coding:utf-8 -*-

    classFoo(object):def __getitem__(self, key):print '__getitem__',keydef __setitem__(self, key, value):print '__setitem__',key,valuedef __delitem__(self, key):print '__delitem__',key

    obj=Foo()

    result= obj['k1'] #自动触发执行 __getitem__

    obj['k2'] = 'wupeiqi' #自动触发执行 __setitem__

    del obj['k1'] #自动触发执行 __delitem__

    View Code

    9、__getslice__、__setslice__、__delslice__

    该三个方法用于分片操作,如:列表

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    #!/usr/bin/env python#-*- coding:utf-8 -*-

    classFoo(object):def __getslice__(self, i, j):print '__getslice__',i,jdef __setslice__(self, i, j, sequence):print '__setslice__',i,jdef __delslice__(self, i, j):print '__delslice__',i,j

    obj=Foo()

    obj[-1:1] #自动触发执行 __getslice__

    obj[0:1] = [11,22,33,44] #自动触发执行 __setslice__

    del obj[0:2] #自动触发执行 __delslice__

    View Code

    10. __iter__

    用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    classFoo(object):passobj=Foo()for i inobj:printi#报错:TypeError: 'Foo' object is not iterable

    第一步

    第一步

    第一步

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    #!/usr/bin/env python#-*- coding:utf-8 -*-

    classFoo(object):def __iter__(self):passobj=Foo()for i inobj:printi#报错:TypeError: iter() returned non-iterator of type 'NoneType'

    第二步

    第二步

    第二步

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    #!/usr/bin/env python#-*- coding:utf-8 -*-

    classFoo(object):def __init__(self, sq):

    self.sq=sqdef __iter__(self):returniter(self.sq)

    obj= Foo([11,22,33,44])for i inobj:printi

    第三步

    第三步

    第三步

    以上步骤可以看出,for循环迭代的其实是  iter([11,22,33,44]) ,所以执行流程可以变更为:

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    #!/usr/bin/env python#-*- coding:utf-8 -*-

    obj= iter([11,22,33,44])for i inobj:print i

    View Code

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    #!/usr/bin/env python#-*- coding:utf-8 -*-

    obj= iter([11,22,33,44])whileTrue:

    val=obj.next()printval

    For循环语法内部

    For循环语法内部

    for循环语法内部

    11. __new__ 和 __metaclass__

    阅读以下代码:

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    classFoo(object):def __init__(self):passobj= Foo() #obj是通过Foo类实例化的对象

    View Code

    上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。

    如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    print type(obj) #输出: 表示,obj 对象由Foo类创建

    print type(Foo) #输出: 表示,Foo类对象由 type 类创建

    View Code

    所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

    那么,创建类就可以有两种方式:

    a). 普通方式

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    classFoo(object):deffunc(self):print 'hello wupeiqi'

    View Code

    b).特殊方式(type类的构造函数)

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    deffunc(self):print 'hello wupeiqi'Foo= type('Foo',(object,), {'func': func})#type第一个参数:类名#type第二个参数:当前类的基类#type第三个参数:类的成员

    View Code

    ==》 类 是由 type 类实例化产生

    那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

    答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

    8e5bbf06d569869f9c988bac29f3f989.png

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    classMyType(type):def __init__(self, what, bases=None, dict=None):

    super(MyType, self).__init__(what, bases, dict)def __call__(self, *args, **kwargs):

    obj= self.__new__(self, *args, **kwargs)

    self.__init__(obj)classFoo(object):__metaclass__ =MyTypedef __init__(self, name):

    self.name=namedef __new__(cls, *args, **kwargs):return object.__new__(cls, *args, **kwargs)#第一阶段:解释器从上到下执行代码创建Foo类#第二阶段:通过Foo类创建obj对象

    obj = Foo()

    View Code

    五、对象

    面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。

    优点是:极大的降低了程序的复杂度

    缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。

    应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。

    面向对象的程序设计的核心是对象,要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的数据属性和方法属性),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙交互着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取。♥♥♥♥♥。◕‿◕。♥♥♥♥♥ (举例很形象,看懂你就明白了)

    展开全文
  • 【单选题】下列所有者权益类科目...【单选题】下列选项中,哪一项不是面向对象程序设计基本特征:【单选题】关于大括号 {} ,以下描述正确是:【多选题】亲权主要因以下原因消灭: ( )【单选题】自顶向下设计主要由下...

    【单选题】下列所有者权益类科目中,可以用来反映留存收益的科目是( )。

    【单选题】按照罗马法的亲等计算方法,王某与其侄子之间的亲等数为 ( )

    【单选题】下列各项中,能同时影响资产和负债发生变化的是( )。

    【单选题】下列选项中,哪一项不是面向对象程序设计的基本特征:

    【单选题】关于大括号 {} ,以下描述正确的是:

    【多选题】亲权主要因以下原因消灭: ( )

    【单选题】自顶向下设计主要由下列哪个语法元素实现? ‪‪‪‪‪‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪

    【单选题】关于文件关闭的 close() 方法,哪个选项的描述是正确的? ‪‪‪‪‪‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪

    【填空题】________________,_____________,______________,无以成江海。

    【单选题】根据我国《继承法》的规定,祖父母、外祖父母与孙子女、外孙子女是 ( )

    【单选题】欲将两数中较小的数返回,应定义的匿名函数为:

    【多选题】关于婚姻成立的形式要件,当代各国有不同的立法例,其种类主要有 ( )

    【单选题】下面不属于Python保留字的是:

    【单选题】以下关于Python语言中“缩进”说法正确的是: ‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‪‪‪

    【多选题】当事人请求返还按照习俗给付的彩礼的,人民法院应当予以支持的情形有 ( )

    【多选题】根据我国《婚姻法》的规定,弟、妹对兄、姐承担扶养义务应当具备的条件包括 ( )

    【多选题】最高人民法院《关于适用 若干问题的解释(二)》,在规定因离婚如何分割夫妻在股份有限公司、有限责任公司、合伙企业和独资企业的财产份额时,坚持了( )

    【单选题】小王 6周岁时父母离婚,小王随母亲生活,1年后其母亲再婚。小王由其母亲和继父一起抚养长大。小王22周岁时其生父和继父相继去世。依据我国法律的规定,小王( )

    【多选题】夫妻关系包括夫妻的 ( )

    【多选题】我国《婚姻法》规定夫妻人身关系的内容包括 ( )

    【单选题】要设置单选按钮,应使用的控件是:

    【单选题】李军于 1990年与孙静结婚,1991年李军以个人名义向其弟借款10万元购买商品房一套,夫妻共同居住。2003年,李军与孙静离婚。李军向其弟所借的钱,离婚时应如何处理?( )

    【单选题】字符串s是一个字符序列,以下表示s从右侧向左第三个字符的是: ‪‪‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪

    【单选题】短期借款利息数额不大,可以直接支付,不预提,在实际支付时直接记入的账户是( )。

    【单选题】在我国,与婚姻家庭有关的成文法始于 ( )

    【单选题】关于 Python 第三方库安装方法,以下选项描述错误的是: ‪‪‪‪‪‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪

    【填空题】浩浩乎如冯虚御风,______________,______________,_________________。

    【单选题】当代许多国家在法律上对亲属关系的基本分类以亲属关系的发生原因为依据,将其分为 ( )

    【单选题】哪个选项不能改变 turtle 画笔的运行方向? ‪‪‪‪‪‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪

    【单选题】关于 Python 文件的 ‘+’ 打开模式,哪个选项的描述是正确的? ‪‪‪‪‪‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪

    【单选题】根据我国《婚姻法》的规定,请求变更抚育费的权利主体是 ( )

    【单选题】对于需要几个单位共同负担的一张原始凭证上的支出,应根据其他单位负担部分为其提高( )。

    【单选题】赵某 (男)和钱某(女)办理结婚登记后并未举办结婚仪式,二人登记后不久赵某在出差途中遇车祸死亡,则钱某( )

    【填空题】锲而舍之,____________; ______________;______________。

    【填空题】积土成山,________;____________,______________。

    【单选题】k = 10 while k > 1 : print (k) k -=1 哪个选项给出了上述程序的循环次数? ‪‪‪‪‪‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪

    【多选题】我国《婚姻法》规定的婚姻成立的实质要件包括( )。

    【单选题】I simply believe that killing animals _______ is wrong.

    【单选题】数学表达式xy/(0.5z),表示成Python表达式应该是:

    【单选题】The couple wanted to adopt the black boy they had been _______.

    【单选题】She never _______ the death of her son.

    【单选题】利用print()格式化输出,哪个选项用于控制浮点数的小数点后两位输出? ‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪

    【单选题】描述对象静态特性的数据元素称为:

    【多选题】我国《婚姻法》第 48条规定,对拒不执行有关探望子女的判决和裁定的,可由人民法院依法强制执 行。对拒不履行协助另一方行使探望权的有关个人和单位,人民法院可采取的强制措施包括 ( )

    【单选题】以下关于 Python 函数说法错误的是: ‪‪‪‪‪‪‫‪‪‪‪‪‪‫‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪ def func(a,b): c=a**2+b b=a return c a=10 b=100 c=func(a,b)+a

    【单选题】下列哪个函数用于将数字传换成字符:

    【填空题】清风徐来,___________。举酒属客,____________,____________.

    【单选题】外国法律中,对婚生子女的否认请求均规定有时效限制,日本法律规定的时效期限是 ( )

    【单选题】根据我国《收养法》的规定,收养解除后,已经成年并已独立生活的被收养人,同其生父母之间的权利和义务关系 ( )

    【填空题】白露横江

    展开全文
  • 进程的描述

    2020-02-29 21:22:25
    (1)进程是程序关于某个数据集合一次执行过程。(2)行为一个规则叫做程序程序在处理机上执行时所发生活动称为进程。(3)进程是这样计算部分,它是可以和其它计算并行一个计算。(4)进程(有时称为...

    进程的特征和定义

    进程的定义有很多种,我们可以通过这些定义全面的了解进程。(1)进程是程序关于某个数据集合的一次执行过程。(2)行为的一个规则叫做程序,程序在处理机上执行时所发生的活动称为进程。(3)进程是这样的计算部分,它是可以和其它计算并行的一个计算。(4)进程(有时称为任务)是一个程序与其数据一道通过处理机的执行所发生的活动。(5)进程是执行中的程序。

    综合来看,进程是数据、程序、硬件之间的关系。通过任务管理器可以看多很多的进程,打开电脑上的软件就会产生与之对应的进程,数据在程序的执行下被cpu计算,这样一个动态过程就是进程。也可以说正在执行的一个程序段就是一个进程,一个程序有若干程序段,也就是一个程序会有多个进程。

    进程的特征:(1)结构特征(2)动态性(3)并发性(4)独立性(5)异步性

    结构特征:进程控制块(PCB)+ 程序 + 数据 = 进程实体,进程控制块是一个结构体代码,其中存放着许多属性,用来记录线程的优先级,线程执行时间等多种信息。

    动态性是最基本的特征,进程是实体的执行过程,有生命周期。程序是指令的集合,是静态概念。

    并发性是多个进程同时执行。独立性是站在单个线程的角度,可看作独立使用资源。异步性是进程各自独立,各自的速度不可预知。

    进程的三种基本状态

    就绪、阻塞、运行。就绪态是万事俱备只欠cpu,已经获得除cpu外的所有资源,一旦获得cpu控制权,就立即执行。运行态是进程正在处理机上执行。阻塞态是正在执行的进程由于某时间暂停执行,放弃处理及而处于暂停状态。

    挂起状态

    比如当前进程在就绪态等待执行,并且内存空间已满,这时外部有一个非常紧急的任务要先执行,那么操作系统会优先调度紧急任务,但是内存已满,所以处于就绪态的进程会被调出内存到外存上,该进程就处于了挂起状态。

    引起挂起状态的原因:(1)终端用户的请求(2)父进程请求(3)负荷调节的需要(4)操作系统的需要

    引入挂起后,进程状态图有所改变:

    一段程序段要被执行,送入内存,处于就绪态,操作系统会把所有等待cpu的进程整合成一个就绪队列。现在程序段得到cpu资源,进入执行态,但程序段中要申请使用打印机,那么该进程就被阻塞,进入阻塞态,所有阻塞状态的进程也会整合成阻塞队列。如果进程得到打印机资源,那么进程就在使用完打印机后重新进入就绪状态。

    如果进程还未得到打印机资源,这时外部又出现紧急任务,需要腾出内存空间,由于就绪队列和阻塞队列都存放在内存,就都有可能被调出内存成为挂起态。假如在阻塞态程序段的程序段被调出内存,那么就成为静止阻塞状态,等紧急任务完成,被调入内存的阻塞队列,就是被激活成阻塞状态。阻塞状态不只是申请打印机,也可能是休眠一段时间,那么可以直接转为静止就绪,被激活后直接转为就绪态。

    同理,就绪队列的程序段被调出,被挂起成为静止就绪态,被激活回到就绪态。

    执行过程中的程序段也可以被调出内存,挂起成为静止就绪态,紧急任务执行完,激活为就绪态。

    进程控制块

    进程控制块(PCB)的作用

    PCB在进程创建的时候创建,伴随进程运行的全过程,存放进程管理和控制信息。PCB是进程存在的唯一标志。系统所有的PCB组织成链表或队列,常常存在内存的PCB区。

    进程控制块中的信息

    (1)进程标示符。每个进程都必须有一个唯一的标示符,就好比进程的名称,用来和其他的进程区分。而进程标示符又分为内部标示符和外部标示符。

    (2)处理机状态。处理机状态信息主要由处理机的各种寄存器中的内容组成。处理机运行时的信息存放在寄存器中,当被中断时这些信息要存放在PCB中。比如进程的执行时间达到时间片,这个时候的数据保存在寄存器中,为了该进程下一次的调用必须保护现场,把中断数据存放在PCB中。(通用寄存器、指针计数器、程序状态字psw、用户栈指针)

    (3)进程调度信息。包括进程状态、进程优先级、进程调度所需要的其他信息、事件。

    (4)进程控制信息。包括程序和数据的地址、进程通信和同步机制、资源清单、链接指针。

    进程控制块的组织方式

    (1)线性方式,基本不用

    (2)链接方式:把同一状态的PCB连接成一个队列,比如就绪队列、阻塞队列。

    (3)索引方式:系统根据所有进程的状态建立几张索引表,把各表的内存首地址记录在内存的专用单元中。索引表的表目中记录了                                       相应状态的某个PCB在PCB表中的地址。

     

    展开全文
  • 程序通过调用EigenvalueDLL.dll提供类求解矩阵特征值问题,你只要将所要 求解矩阵按照文件"矩阵特征值问题实例.txt"中数据格式描述即可显示在程序MatrixEigenvalue.exe列表中4. 注:由于作者所做数值...
  • 它解决问题基本思想是,首先建立与描述该问题有相似性概率模型,然后对模型进行随机模拟或统计抽样,再利用所得结果求出特征统计值作为原问题近似解,并对解精度作出某些估计。Monte Carlo仿真方法...
  • 本节主要介绍一些基本概念,有关于面向对象程序的基本特点~~ Markdown和扩展Markdown简洁语法 抽象 对某一类对象共同属性和行为进行概括,形成类 首先注意问题本质和描述,其次是实现过程或细节 数据...
  • 二级Python语言程序设计模拟2 一单项选择题 1关于算法的描述以下选项中错误的是 ? ?A算法是指解题方案的准确而完整的描述 ? ?B算法具有可行性确定性有穷性的基本特征 ? ?C算法的复杂度主要包括时间复杂度和数据...
  • 2-2 进程的描述

    2019-04-12 15:13:16
    1.进程:程序关于某个数据集合一次执行过程 2.进程的特征(与程序比较): (1) 结构特征 进程控制块(PCB) + 程序 + 数据 = 进程实体 (2) 动态性——最基本特征 进程:进程实体一次执行过程,有生命周期。 ...
  • 使用开发环境是visual studio 2017,opencv版本是4.2,关于Haar特征分类器资料网上很多就不描述了,这里只是通过以上搭建开发环境来实现一个简单人脸和眼睛检测功能,参考代码如下: // TODO: 在此添加...
  • 关于opencv调试

    2019-03-04 23:38:38
    本人很菜,也没怎么学习过C++,opencv程序运行时经常出错,所以把问题和解决方案都记下来以免再犯。...其中局部图像特征包括了常用几种局部图像特征检测与描述算子,如FAST、SURF、SIFT、以及ORB。对于高...
  • 进程是具有独立功能的程序关于某个数据集合上一次运行活动,是系统进行资源管理分配和调度独立单位。 2、进程组成 进程=程序+数据+PCB 程序部分:描述了进程所要完成功能; 相关数据:是程序在执行时...
  • 更准确地说,实验确定溶质描述符(或参数)已与简化分子拓扑分子特征精确相关。 在本研究中,在溶剂方面达到了等效结果。 在先前气相色谱研究中,通过原始乘法矩阵分析,同时获得了121种挥发性有机化合物...
  • 关于内存学习

    2019-03-06 17:04:59
    好多书上都有描述程序是在外存(例如硬盘等)中存放要执行时候CPU将程序拷贝内存中去执行。内存其实也是一种存储设备不过他有几个特点:掉电丢失数据、可以随机存储与CPU直间是总线访问(速度要比时序访问要快...
  • 为了能使计算机程序并发执行,并且可以对并发执行的程序加以描述和控制,引入了“进程”概念。从其它角度来看,进程还有以下三种解释: 进程是计算机程序的一次执行过程。 进程是一个程序及其数据在处理机上顺序...
  • 还包括用于关于数据特征的一组功能数据的有监督或无监督分类的方法。 它可以执行功能方差分析,假设检验,功能响应模型等。 安装 您可以使用以下命令从CRAN安装当前的fda.usc版本: install.packages( " fda.usc ...
  • 关于鸭子类型理解

    千次阅读 2019-02-28 16:57:39
    要想学习python,就得明白面向对象(oop)。... 维基百科中对鸭子类型是这样描述:在程序设计中,鸭子类型(英语:duck typing)是动态类型一种风格。在这种风格中,一个对象有效语义,不是由继承自特定类或...
  • 文章目录[有限元方法阶段汇总篇] 有限元入门简单 1D 示例程序(Helmholtz 方程)前言一些链接动机问题描述关于特征值问题亥姆霍兹方程程序与结果问题一问题二写在后面话 前言 一些链接 之前写过三篇基础有限元...
  • Hi All, 第一次写有关LabVIEW 相关文章,关于OOP一些基础概念以及在LabVIEW中应用案例,此文章是基于个人一些...名字: 用于区别不同实体属性/状态: 属性用于描述不同实体的特征;状态由这个对象属性和这...
  • 一、python中关于OOP常用术语1.1抽象/实现抽象指对现实世界问题和实体本质表现,行为和特征建模,建立一个相关子集,可以用于描绘程序结构,从而实现这种模型。抽象不仅包括这种模型数据属性,还定义了这些...
  • 进程、程序与线程

    2021-01-01 15:01:40
    关于进程 1、什么是进程? 进程是进程实体运行过程,是系统进行资源分配和调度一个独立单位 2、什么是进程实体 ...4、相对于程序,进程哪些特征程序是静态,进程 是动态) 1、动态性 : 进程是程序的
  • SOP是对一个过程的描述,不是一个结果的描述。同时,SOP又不是制度,也不是表单,是流程下面某个程序关于控制点如何来规范的程序。  SOP是一种作业程序。标准作业指导。SOP是一种操作层面的程序,是实实在...
  • 抽象指对现实世界问题和实体本质表现,行为和特征建模,建立一个相关子集,可以用于 绘程序结构,从而实现这种模型。抽象不仅包括这种模型数据属性,还定义了这些数据接口。 对某种抽象实现就是对此数据及与之...
  • 程序特征:顺序性,封闭性,可再现性. 定义:一个正在执行程序;一个正在计算机上执行程序实例;能分配给处理器并由处理器执行实体;由一组执行指令、一个当前状态和一组相关系统资源表征活动单元[进程...
  • 很多刚学习新手小伙伴可能还不知道,下面是学习啦小编带来关于如何用cad绘制完整流程图内容,希望可以让大家有所收获!用cad绘制完整流程图方法流程图分成两类:一类是表示算法或内部逻辑,像这张图:...
  • 之前下载了图像分类识别猫狗的程序,想照着这个程序去建一个txt文件存放图片名字然后去识别txt文件里描述的图片,但是用imread指令却提示无法打开要读取文件,请问一下各位大佬这个报错该怎么解决啊 1. 完整...
  • 关于exe或dll文件中字符串资源

    千次阅读 2015-11-18 13:59:48
    所谓的资源就是一些用于描述界面或其他特征的说明性字符,它们有固定的格式。这点与HTML有相似之处。而微软提供了处理这些资源描述字符的函数,并上升到Win32API的高度。资源有两种存在形式,一是编译之前,此时的...
  • 1、对象:对象是对客观世界中实体的程序描述,是具体2、类:类是对具有同样特征与行为对象概括和抽象,是抽象3、将对象高度概括和抽象后,形成具有同样属性和行为对象统称,这是创建类,创建类以后,...
  • ------- Windows Phone 7手机开发、.Net培训、期待与您交流...通过程序代码来描述真实世界万物; 在程序员世界里,万物皆对象;  属性(特征):对象所具有各种特点,没个对象属性都拥有特定值。 描述对象
  • opencv 自带两个版本的训练程序,分别是haartraining.exe和train_cascades.exe,前者是老版本,只能训练Haar特征的分类器,后者是新版本,能够训练Haar特作、HOG特征和LBP特征。以下为一些技术要点:①--nneg 负样本...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 242
精华内容 96
关键字:

关于程序特征的描述