• 关于

    C#多态性

    的搜索结果

回答

面向对象的特征主要有以下几个方面: 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。 封装 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。 继承 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。 关于继承如下 3 点请记住: 子类拥有父类非 private 的属性和方法。 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。 子类可以用自己的方式实现父类的方法。(以后介绍)。 多态 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。 在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。 其中Java 面向对象编程三大特性:封装 继承 多态 封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。 继承:继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承可以提高代码复用性。继承是多态的前提。 关于继承如下 3 点请记住: 子类拥有父类非 private 的属性和方法。 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。 子类可以用自己的方式实现父类的方法。 多态性:父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。 在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。 方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。 一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事: 方法重写(子类继承父类并重写父类中已有的或抽象的方法); 对象造型(用父类型引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

问问小秘 2020-03-27 17:36:33 0 浏览量 回答数 0

回答

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。 多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。

问问小秘 2020-03-27 17:37:57 0 浏览量 回答数 0

回答

new 是动态分配的, 都是动态绑定的,只是绑定的对象,有虚函数表的时候,虚函数表的函数指针指向的是具体动态创建的子类的函数而已。 编译器多态值得一般是是函数重载,泛型编程等。是代码层面的多态。######写得挺好######不错!######mark######个人感觉:在没用支持多态的话,所有的函数都是在编译器就进行了绑定,此时仅仅是根据指针的类型进行函数的绑定。也就是指针声明为什么类型,就在相应的类中绑定这个函数。但是当出现了多态性之后,因为 这个函数是虚函数,这时的函数绑定就不应该以指针或引用的声明为准,而应该在运行时,通过对象的vptr查找虚函数表,进而再确定应该调用那个函数。######挺好的

kun坤 2020-06-06 13:42:32 0 浏览量 回答数 0

回答

多态是面向对象的最后一个主要特征,它本身主要分为两个方面: ·方法的多态性:重载与覆写 |-重载:同一个方法名称,根据不同的参数类型及个数可以完成不同的功能; |-覆写:同一个方法,根据操作的子类不同,所完成的功能也不同。 ·对象的多态性:父子类对象的转换。 |-向上转型:子类对象变为父类对象,格式:父类父类对象=子类实例,自动; |-向下转型:父类对象变为子类对象,格式:子类子类对象=(子类)父类实例,强制;

游客pklijor6gytpx 2019-12-02 03:19:07 0 浏览量 回答数 0

问题

求java大神戳入,关于java多态的问题~求指导!:报错

kun坤 2020-06-10 09:25:06 0 浏览量 回答数 1

回答

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。 重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分 重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写。

剑曼红尘 2020-03-27 16:06:32 0 浏览量 回答数 0

回答

随着业务诉求的变化,节点管理已不再局限于安装 docker / kubelet 等组件,我们需要实现如等待日志采集 DaemonSet 部署完成才可以开启调度的需求,而且这类需求变得越来越多。 如果将终态统一交由 Machine-Operator 管理,势必会增加 Machine-Operator 与其它组件的耦合性,而且系统的扩展性会受到影响。因此,我们设计了一套节点终态管理的机制,来协调 Machine-Operator 和其它节点运维 Operators。 设计如下图所示: 全量 ReadinessGates: 记录节点可调度需要检查的 Condition 列表;Condition ConfigMap: 各节点运维 Operators 终态状态上报 ConfigMap; 协作关系: 外部节点运维 Operators 检测并上报与自己相关的子终态数据至对应的 Condition ConfigMap; 2.Machine-Operator 根据标签获取节点相关的所有子终态 Condition ConfigMap,并同步至 Machine status 的 conditions 中; 3.Machine-Operator 根据全量 ReadinessGates 中记录的 Condition 列表,检查节点是否达到终态,未达到终态的节点不开启调度。

问问小秘 2019-12-02 03:14:54 0 浏览量 回答数 0

回答

重载(Overloading)和重写(Overriding)是Java中两个比较重要的概念。但是对于新手来说也比较容易混淆。本文通过两个简单的例子说明了他们之间的区别。 定义 重载 简单说,就是函数或者方法有同样的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。 重写 重写指的是在Java的子类与父类中有两个名称、参数列表都相同的方法的情况。由于他们具有相同的方法签名,所以子类中的新方法将覆盖父类中原有的方法。 重载 VS 重写 关于重载和重写,你应该知道以下几点: 1、重载是一个编译期概念、重写是一个运行期间概念。 2、重载遵循所谓“编译期绑定”,即在编译时根据参数变量的类型判断应该调用哪个方法。 3、重写遵循所谓“运行期绑定”,即在运行的时候,根据引用变量所指向的实际对象的类型来调用方法 4、因为在编译期已经确定调用哪个方法,所以重载并不是多态。而重写是多态。重载只是一种语言特性,是一种语法规则,与多态无关,与面向对象也无关。(注:严格来说,重载是编译时多态,即静态多态。但是,Java中提到的多态,在不特别说明的情况下都指动态多态) 重写的例子 下面是一个重写的例子,看完代码之后不妨猜测一下输出结果: class Dog{ public void bark(){ System.out.println("woof "); } } class Hound extends Dog{ public void sniff(){ System.out.println("sniff "); } public void bark(){ System.out.println("bowl"); } } public class OverridingTest{ public static void main(String [] args){ Dog dog = new Hound(); dog.bark(); } } 输出结果: bowl 上面的例子中,dog对象被定义为Dog类型。在编译期,编译器会检查Dog类中是否有可访问的bark()方法,只要其中包含bark()方法,那么就可以编译通过。在运行期,Hound对象被new出来,并赋值给dog变量,这时,JVM是明确的知道dog变量指向的其实是Hound对象的引用。所以,当dog调用bark()方法的时候,就会调用Hound类中定义的bark()方法。这就是所谓的动态多态性。 重写的条件 参数列表必须完全与被重写方法的相同; 返回类型必须完全与被重写方法的返回类型相同; 访问级别的限制性一定不能比被重写方法的强; 访问级别的限制性可以比被重写方法的弱; 重写方法一定不能抛出新的检查异常或比被重写的方法声明的检查异常更广泛的检查异常 重写的方法能够抛出更少或更有限的异常(也就是说,被重写的方法声明了异常,但重写的方法可以什么也不声明) 不能重写被标示为final的方法; 如果不能继承一个方法,则不能重写这个方法。 重载的例子 class Dog{ public void bark(){ System.out.println("woof "); } //overloading method public void bark(int num){ for(int i=0; i<num; i++) System.out.println("woof "); } } 上面的代码中,定义了两个bark方法,一个是没有参数的bark方法,另外一个是包含一个int类型参数的bark方法。在编译期,编译期可以根据方法签名(方法名和参数情况)情况确定哪个方法被调用。 重载的条件 被重载的方法必须改变参数列表; 被重载的方法可以改变返回类型; 被重载的方法可以改变访问修饰符; 被重载的方法可以声明新的或更广的检查异常; 方法能够在同一个类中或者在一个子类中被重载。 参考资料 Overriding vs. Overloading in Java

montos 2020-06-01 15:49:27 0 浏览量 回答数 0

回答

简单易学(Java语言的语法与C语言和C++语言很接近) 面向对象(封装,继承,多态) 平台无关性(Java虚拟机实现平台无关性) 支持网络编程并且很方便(Java语言诞生本身就是为简化网络编程设计的) 支持多线程(多线程机制使应用程序在同一时间并行执行多项任) 健壮性(Java语言的强类型机制、异常处理、垃圾的自动收集等) 安全性

问问小秘 2020-03-27 18:22:05 0 浏览量 回答数 0

回答

方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。 作者:Python编程社区 链接:https://www.jianshu.com/p/c60c86a16579 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

YDYK 2020-04-25 08:28:22 0 浏览量 回答数 0

回答

Java也支持面向对象的三大特征:封装、继承和多态,Java提供了private、protected和public三个访问控制修饰符来实现良好的封装,提供了extends关键字来让子类继承父类,子类继承父类就可以继承到父类的Field和方法,如果访问控制允许,子类实例可以直接调用父类里定义的方法。继承是实现类复用的重要手段,除此之外,也可通过组合关系来实现这种复用,从某种程度上来看,继承和组合具有相同的功能。使用继承关系来实现复用时,子类对象可以直接赋给父类变量,这个变量具有多态性,编程更加灵活;而利用组合关系来实现复用时,则不具备这种灵活性。

星尘linger 2020-04-07 12:03:07 0 浏览量 回答数 0

回答

使用 inotifywait 配合 rsync 是一种常见的准实时数据备份/同步方案,但在NAS文件系统上 inotifywait 无法正常工作,这是由于 inotify 本身的实现机制导致的。 inotifywait 原理简介 inotifywait 是Linux 内核子模块 inotify 的用户态接口实现,inotify 实现在 VFS 层,当文件操作到达 VFS 层时,inotify 模块会将操作类型(创建/删除/属性改变等)和操作对象(文件名)反馈给用户态,用户态的 inotifywait 即可将本次操作信息输出给用户。 NAS 上使用 inotifywait 存在的问题 由于 inotify 是在 kernel 的 VFS 层实现的,因此在 NFS 文件系统上,远程客户端对 NFS 文件系统的操作无法被本地 kernel 所感知,inotify 也就无法感知远程客户端的文件修改操作。 因此,在 NAS 上使用 inotifywait 会出现以下现象: 在客户端 A 和 B 同时挂载一个 NAS 文件系统,在客户端 A 启动 inotifywait 监听挂载目录。 在客户端 A 上操作挂载目录中的文件,可以被 inotifywait 感知。 在客户端 B 上操作挂载目录中的文件,inotifywait 无法感知任何文件操作。 替代方案 一个可行的替代方案是使用 FAM, FAM 是一个用来监听文件或目录的库,全部在用户态实现,原理是在后台运行一个 daemon,定时扫描目录,获取文件变化情况。 但是使用 FAM 存在以下几个缺陷: 需要自己写程序调用 FAM 接口实现功能。 对于文件数目很多的场景,使用该方案性能会较差,可能消耗大量资源,无法做到很好的实时性

1934890530796658 2020-03-31 22:17:05 0 浏览量 回答数 0

回答

使用 inotifywait 配合 rsync 是一种常见的准实时数据备份/同步方案,但在NAS文件系统上 inotifywait 无法正常工作,这是由于 inotify 本身的实现机制导致的。 inotifywait 原理简介 inotifywait 是Linux 内核子模块 inotify 的用户态接口实现,inotify 实现在 VFS 层,当文件操作到达 VFS 层时,inotify 模块会将操作类型(创建/删除/属性改变等)和操作对象(文件名)反馈给用户态,用户态的 inotifywait 即可将本次操作信息输出给用户。 NAS 上使用 inotifywait 存在的问题 由于 inotify 是在 kernel 的 VFS 层实现的,因此在 NFS 文件系统上,远程客户端对 NFS 文件系统的操作无法被本地 kernel 所感知,inotify 也就无法感知远程客户端的文件修改操作。 因此,在 NAS 上使用 inotifywait 会出现以下现象: 在客户端 A 和 B 同时挂载一个 NAS 文件系统,在客户端 A 启动 inotifywait 监听挂载目录。 在客户端 A 上操作挂载目录中的文件,可以被 inotifywait 感知。 在客户端 B 上操作挂载目录中的文件,inotifywait 无法感知任何文件操作。 替代方案 一个可行的替代方案是使用 FAM, FAM 是一个用来监听文件或目录的库,全部在用户态实现,原理是在后台运行一个 daemon,定时扫描目录,获取文件变化情况。 但是使用 FAM 存在以下几个缺陷: 需要自己写程序调用 FAM 接口实现功能。 对于文件数目很多的场景,使用该方案性能会较差,可能消耗大量资源,无法做到很好的实时性。

景凌凯 2020-03-31 22:11:56 0 浏览量 回答数 0

问题

文件存储NAS是否支持inotify?

云栖大讲堂 2019-12-01 20:53:48 1625 浏览量 回答数 1

回答

对于Windows而言,大部分系统资源(例如,进程数、线程数)不像Linux一样有固定的上限,而是受限于各类系统核心资源的使用,例如物理内存(physical memory), 虚拟内存(virutal memory),页面缓冲池(paged pool), 非页面缓冲池(non paged pool) 等。 在一个Windows机器上,创建进程或者线程的上限受限于上述核心资源的情况,对于不同内存大小,不同操作系统(32位,64位)而言,其创建的上限也不同。 微软专家 Mark Russinovich (Windows Internals作者) 在微软官方Blog的上文章Pushing the Limits of Windows: Processes and Threads介绍了Windows 操作系统支持的最大进程数和线程数。 根据该文章,我们总结了如下要点,请参考: 进程 进程是操作系统结构的基础,Windows进程是一个具有一定独立功能的可执行文件关于某个数据集合的一次运行活动。在WIndows内核中有对应的进程对象(Object), 操作系统使用该内核进程对象及其关联的数据结构来存储和跟踪该可执行程序的运行情况。 线程 线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,它可与同属一个进程的其它线程共享进程所拥有的全部资源。在Windows内核中有对应的线程Object来跟踪线程的运行情况。 线程上限 简单的说,线程创建的上限主要与线程用户态Stack大小,进程用户态虚拟内存大小,Kernel Stack分配大小,系统Resident available memory大小有关。 Windows进程创建时,会分配虚拟内存空间,一般而言,32位操作系统为4G(2G用户空间+2G内核空间),而64位操作系统,虚拟内存寻址则大的多(8 TB用户空间+8TB内核空间)。WIndows线程创建时,会分配用户态Stack(栈)来传递函数参数(function parameters), 管理本地变量(local variables), 保存函数返回地址(function return addresses). 一般而言,线程用户态的stack默认保留大小为1 MB。 系统Resident available memory是可以用来分配给代码和数据的物理内存。对于线程而言,其用户态Stack的作用上面已经介绍,而内核态Stack是内核中用来处理系统调用等使用,其属于系统Resident available memory,进程创建时线程的内核kernel stack的大小在32位Windows上为12K,在64位Windows上为24K. 理论上来说,一个进程所创建的线程数量为 min(进程用户态虚拟内存大小/线程用户态分配stack大小,系统Resident avaiable memory/线程内核默认kernel stack大小)。 在不同的操作系统版本(32位,64位)以及不同类型的进程(32位,64位),最高创建的线程数量是不同的。 进程上限 在进程创建时,除了默认包含的线程的资源外,系统还需要预留最小的working set(工作集,归属于物理内存)满足进程基本需要,默认大小为200K。此外,进程还需要使用虚拟地址空间来存放初始化数据,包含数据结构、PTE,Handle,Objects等资源,在微软Blog的测试中,创建一个测试进程,基本上消耗1MB Commited virutal Space (已提交虚拟内存), 所以进程创建的上限受限于系统的Commit Limit(虚拟内存上限)。例如,下图是打开Windows 7的进程管理器中的资源界面,可以看到Committd virtual space 为1360MB, 而系统的Commit Limit上限为3583MB. 结论 进程/线程的创建上限与操作系统的核心资源有着密切的联系,我们可以通过适当的调整来系统资源增加其上限。但是根据微软官方建议,如果一个/多个应用程序从设计上需要创建大量的进程/线程,而这又成为资源瓶颈,那么设计者需要重新考虑架构。 一般而言,一个可扩展的应用程序应该让正在运行的线程正好与CPU核数相同(如果使用NUMA非一致性内存访问,则与Node上CPU的数量相同),或者使用另外一种方法,将同步IO机制修改为异步IO机制,通过IO完成机制来实现CPU与线程数的对应。 阅读须知 本文仅供用户使用 ECS Windows 时参考,文中引用的微软官方链接,版权归属微软。请注意文章适用的操作系统范围,以及微软 Windows 产品迭代或者文档未及时更新可能带来的问题,阿里云官方不对引用的微软官方链接内容负责。

KB小秘书 2019-12-02 02:07:29 0 浏览量 回答数 0

回答

fetch默认值:FetchType.EAGER。默认情况下,JPA持续性提供程序使用获取类型EAGER:这将要求持续性提供程序运行时必须迫切获取数据。如果这不适合于应用程序或特定的持久字段,请将fetch设置为FetchType.LAZY:这将提示持续性提供程序在首次访问数据(如果可以)时应不急于获取数据。 已发现问题,结合的懒加载是自动的,一定要加入注解F etch=FetchType.EAGER才可以。 引用来自“zhbsbccg”的评论 已发现问题,结合的懒加载是自动的,一定要加入注解F etch=FetchType.EAGER才可以。改成FetchType.EAGER相当于放弃了LAZY的好处,不可取。应该是在需要这个数据的方法中通过Criteria参数或者hibernate.initialize操作取到你需要的LAZY数据。 我又发现问题了,发现hibernate与json序列化相当不兼容。 首先@ahyyux22说的对,eager确实不能解决我的问题,治标不治本,多了很多冗余数据。 然后lazy的话,有问题无法解决,就是json序列化时,依旧会把所有数据查询出来,我试了fastjson和jackson都是这样,因为序列化时会询问那些manytoone和onetomany的属性,是否存在,导致hibernate进行这部分数据的查询,从而查询出了整个树的数据。查询网络上的办法,大部分是建议将这些数据配置忽略,这样的话,就等于废了使用Hibernate的意义了,不知道有没有大神能解决这个问题的? 我想了一下,应该是让hibernate查询出来的实体,脱离他的持久态,进入游离态,但是这样做因为其中有属性lazy,所以在json序列化时就会报错。有没有办法直接把hibernate查询出来的实体,脱离hibernate的代理?

爱吃鱼的程序员 2020-06-12 10:42:43 0 浏览量 回答数 0

问题

Windows进程和线程数的上限是什么

boxti 2019-12-01 22:06:50 2125 浏览量 回答数 0

回答

下一代物联网技术的毋容置疑是低功耗广域网(LPWAN)的天下,NB-IoT与eMTC同属低功耗广域网(LPWAN)技术,两者在技术上互有优劣。NB-IoT的主要优势是成本更低、覆盖更广、小区容量预计也更大,eMTC的主要优势则是速率更高、可移动性更好、可支持语音。两者的共同点和核心可以从LPWAN这个单词即可得出,那就是低功耗,因为以下的LPWAN各类应用场景的功耗要求都非常苛刻。 NB-IOT应用场景 当然我们只知道低功耗是NB-IoT、eMTC这两种窄带LPWA技术的核心特点之一,那么他们是怎么做到低功耗的呢? PSM、eDRX可以说是NB-IoT和eMTC低功耗的左膀右臂。 什么是PSM(Power Saving Mode) PSM即低功耗模式,是3GPP R12引入的技术,其原理是允许UE在进入空闲态一段时间后,关闭信号的收发和AS(接入层)相关功能,相当于部分关机,从而减少天线、射频、信令处理等的功耗消耗。借图: PSM即低功耗模式 UE在PSM期间,不接收任何网络寻呼,对于网络侧来说,UE此时是不可达的,数据、短信、电话均进不来。只有当TAU周期请求定时器(T3412)超时,或者UE有MO业务要处理而主动退出时,UE才会退出PSM模式、进入空闲态,进而进入连接态处理上下行业务。 TAU周期请求定时器(T3412)由网络侧在ATTCH和TAU消息中指定,3GPP协议规定默认为54min,最大可达310H。那么UE处理完数据之后,什么时候进入PSM模式呢?这是由另一个定时器Activer Timer(T3324,0-255秒)决定的。UE处理完成数据之后,RRC连接会被释放、进入空闲态,与此同时启动Active Timer,此Timer超时后,UE即进入上述PSM模式。转换状态如下(借图): 模式切换状态机 eDRX(Extended DiscontinuousReception) eDRX即非连续接收,是3GPP R13引入的新技术。R13之前已经有DRX技术,从字面上即可看出,eDRX是对原DRX技术的增强:支持的寻呼周期可以更长,从而达到节电目的。继续借图: eDRX eDRX的寻呼周期由网络侧在ATTACH和TAU消息中指定(UE可以指定建议值),可为20s,40s,80s,…最大可达40min。相比以往1.28s/2.56s等DRX寻呼周期配置,eDRX耗电量显然低很多。 PSM和eDRX虽然让终端耗电量大大降低,但都是通过长时间的“罢工”来换取的,付出了实时性的代价。对于有远程不定期监控(如远程定位,电话呼入,配置管理等)需求且实时性要求很高的场景,不适合开启PSM功能;如果允许一定的时延,最好采用eDRX技术、并将eDRX寻呼周期设的尽量短些(根据可接受的时延要求,最短为20s,…)。UE可在ATTACH和TAU中请求开启PSM或(和)eDRX,但最终开启哪一种或两种均开启、以及周期是多少均由网络侧决定。 附上NB-IOT几个关键特征 1、海量连接 指能实现比GSM高20db的覆盖增益,放大了倍数,信号参透力强。 2、设备不需要持续连接,功耗低 从这个角度来说,NB-IOT确实是为设备联网而设计的,设备联网的特点: ①小包数据,或低频或高频; ②对时延不敏感; ③网络可靠性要求高; ④非长连接。 如果采用以往蜂窝网比如GPRS方式,沿用到物联网的领域,从主网或安全性来说,也是比较差的。 所以说, NB-IOT来了,才叫物联网时代来临了。 原文出处:物联网智库

问问小秘 2019-12-02 02:11:20 0 浏览量 回答数 0

回答

单一职责原则(Single-Responsibility Principle) 其核心思想为:一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。职责过多,可能引起它变化的原因就越多,这将导致职责依赖,相互之间就产生影响,从而大大损伤其内聚性和耦合度。通常意义下的单一职责,就是指只有一种单一功能,不要为类实现过多的功能点,以保证实体只有一个引起它变化的原因。 专注,是一个人优良的品质;同样的,单一也是一个类的优良设计。交杂不清的职责将使得代码看起来特别别扭牵一发而动全身,有失美感和必然导致丑陋的系统错误风险。 开放封闭原则(Open-Closed principle) 其核心思想是:软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。开放封闭原则主要体现在两个方面1、对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。2、对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对其进行任何尝试的修改。 实现开放封闭原则的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,所以修改就是封闭的;而通过面向对象的继承和多态机制,又可以实现对抽象类的继承,通过覆写其方法来改变固有行为,实现新的拓展方法,所以就是开放的。 “需求总是变化”没有不变的软件,所以就需要用封闭开放原则来封闭变化满足需求,同时还能保持软件内部的封装体系稳定,不被需求的变化影响。 Liskov替换原则(Liskov-Substitution Principle) 其核心思想是:子类必须能够替换其基类。这一思想体现为对继承机制的约束规范,只有子类能够替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。在父类和子类的具体行为中,必须严格把握继承层次中的关系和特征,将基类替换为子类,程序的行为不会发生任何变化。同时,这一约束反过来则是不成立的,子类可以替换基类,但是基类不一定能替换子类。 Liskov替换原则,主要着眼于对抽象和多态建立在继承的基础上,因此只有遵循了Liskov替换原则,才能保证继承复用是可靠地。实现的方法是面向接口编程:将公共部分抽象为基类接口或抽象类,通过Extract Abstract Class,在子类中通过覆写父类的方法实现新的方式支持同样的职责。 Liskov替换原则是关于继承机制的设计原则,违反了Liskov替换原则就必然导致违反开放封闭原则。 Liskov替换原则能够保证系统具有良好的拓展性,同时实现基于多态的抽象机制,能够减少代码冗余,避免运行期的类型判别。 依赖倒置原则(Dependecy-Inversion Principle) 其核心思想是:依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。 我们知道,依赖一定会存在于类与类、模块与模块之间。当两个模块之间存在紧密的耦合关系时,最好的方法就是分离接口和实现:在依赖之间定义一个抽象的接口使得高层模块调用接口,而底层模块实现接口的定义,以此来有效控制耦合关系,达到依赖于抽象的设计目标。 抽象的稳定性决定了系统的稳定性,因为抽象是不变的,依赖于抽象是面向对象设计的精髓,也是依赖倒置原则的核心。 依赖于抽象是一个通用的原则,而某些时候依赖于细节则是在所难免的,必须权衡在抽象和具体之间的取舍,方法不是一层不变的。依赖于抽象,就是对接口编程,不要对实现编程。 接口隔离原则(Interface-Segregation Principle) 其核心思想是:使用多个小的专门的接口,而不要使用一个大的总接口。 具体而言,接口隔离原则体现在:接口应该是内聚的,应该避免“胖”接口。一个类对另外一个类的依赖应该建立在最小的接口上,不要强迫依赖不用的方法,这是一种接口污染。 接口有效地将细节和抽象隔离,体现了对抽象编程的一切好处,接口隔离强调接口的单一性。而胖接口存在明显的弊端,会导致实现的类型必须完全实现接口的所有方法、属性等;而某些时候,实现类型并非需要所有的接口定义,在设计上这是“浪费”,而且在实施上这会带来潜在的问题,对胖接口的修改将导致一连串的客户端程序需要修改,有时候这是一种灾难。在这种情况下,将胖接口分解为多个特点的定制化方法,使得客户端仅仅依赖于它们的实际调用的方法,从而解除了客户端不会依赖于它们不用的方法。 分离的手段主要有以下两种:1、委托分离,通过增加一个新的类型来委托客户的请求,隔离客户和接口的直接依赖,但是会增加系统的开销。2、多重继承分离,通过接口多继承来实现客户的需求,这种方式是较好的。 以上就是5个基本的面向对象设计原则,它们就像面向对象程序设计中的金科玉律,遵守它们可以使我们的代码更加鲜活,易于复用,易于拓展,灵活优雅。不同的设计模式对应不同的需求,而设计原则则代表永恒的灵魂,需要在实践中时时刻刻地遵守。就如ARTHUR J.RIEL在那边《OOD启示录》中所说的:“你并不必严格遵守这些原则,违背它们也不会被处以宗教刑罚。但你应当把这些原则看做警铃,若违背了其中的一条,那么警铃就会响起。”

montos 2020-06-01 17:04:26 0 浏览量 回答数 0

问题

《云计算》学习笔记2——Google的云计算原理与应用(GFS和MapReduce)

佳剑 2019-12-01 21:47:24 7043 浏览量 回答数 0

回答

JDK1.6对锁的实现引入了大量的优化,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。 自旋锁,就是让该线程等待一段时间,不会被立即挂起(就是不让前来获取该锁(已被占用)的线程立即阻塞),看持有锁的线程是否会很快释放锁。 适应自旋锁就意味着自旋的次数不再是固定的,它是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。 在有些情况下,JVM检测到不可能存在共享数据竞争,这是JVM会对这些同步锁进行锁消除。锁消除的依据是逃逸分析的数据支持。 锁粗化就是将多个连续的加锁、解锁操作连接在一起,扩展成一个范围更大的锁。 轻量级锁的主要目的是在多没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。 当关闭偏向锁功能或者多个线程竞争偏向锁导致偏向锁升级为轻量级锁,则会尝试获取轻量级锁。 重量级锁通过对象内部的监视器(monitor)实现,其中monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。

masonwang 2020-03-11 11:49:42 0 浏览量 回答数 0

问题

【大咖问答】对话阿里测试、质量和工程效能研究员,郑子颖

问问小秘 2019-12-01 19:53:39 1497 浏览量 回答数 12

回答

回顾2009年到如今,区块链技术的火热程度是逐年增加。各大行业巨头也在疯狂布局,势必要上演一场"群雄逐鹿"的商业大战。那这场好戏什么时候上演?有人说就在最近这两三年,还有人甚至说就在今年,2018年区块链将会出现井喷。当然,我们现在还无法做出准确的判断,但是我们可以先做好充足的准备。那么,问题又来了,区块链技术到底要怎么去弄?要用到哪些开发语言?在现在看来,这也许是很多从事区块链程序员的心声。下面整理了四种区块链技术比较主要的开发言语,希望对大家有所帮助。 JAVA开发语言(未来币) 定义:Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。 Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点 .Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。 C++开发语言(比特币、公正通、瑞波ripple) 定义:C++是C语言的继承,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。C++擅长面向对象程序设计的同时,还可以进行基于过程的程序设计,因而C++就适应的问题规模而论,大小由之。 GO开发语言(以太坊、IBM) 定义:Go是一种新的语言,一种并发的、带垃圾回收的、快速编译的语言。它具有以下特点: 它可以在一台计算机上用几秒钟的时间编译一个大型的Go程序。Go为软件构造提供了一种模型,它使依赖分析更加容易,且避免了大部分C风格include文件与库的开头。Go是静态类型的语言,它的类型系统没有层级。因此用户不需要在定义类型之间的关系上花费时间,这样感觉起来比典型的面向对象语言更轻量级。Go完全是垃圾回收型的语言,并为并发执行与通信提供了基本的支持。按照其设计,Go打算为多核机器上系统软件的构造提供一种方法。 Go是一种编译型语言,它结合了解释型语言的游刃有余,动态类型语言的开发效率,以及静态类型的安全性。它也打算成为现代的,支持网络与多核计算的语言。要满足这些目标,需要解决一些语言上的问题:一个富有表达能力但轻量级的类型系统,并发与垃圾回收机制,严格的依赖规范等等。这些无法通过库或工具解决好,因此Go也就应运而生了。 Solidity开发语言(以太坊) 定义:Solidity是一种智能合约高级语言,运行在Ethereum虚拟机(EVM)之上。它的语法接近于Javascript,是一种面向对象的语言。但作为一种真正意义上运行在网络上的去中心合约,它又有很多的不同。 特别说明:以太坊具有四种专用语言:Serpent(Python启发),Solidity(javaScript启发),Mutan(GO启发)和LLL(Lisp启发),都是为面向合约编程而从底层开始设计的语言。Solidity是以太坊的首选语言,正处于紧张开发中,它内置了Serpent的所有特性,但是语法类似于JavaScript,JavaScript是web开发的常用语言。

问问小秘 2019-12-02 03:07:11 0 浏览量 回答数 0

回答

面向对象有三个特征:封装、继承、多态。 其中继承和实现都体现了传递性。而且明确定义如下: 继承:如果多个类的某个部分的功能相同,那么可以抽象出一个类出来,把他们的相同部分都放到父类里,让他们都继承这个类。 实现:如果多个类处理的目标是一样的,但是处理的方法方式不同,那么就定义一个接口,也就是一个标准,让他们的实现这个接口,各自实现自己具体的处理方法来处理那个目标 所以,继承的根本原因是因为要复用,而实现的根本原因是需要定义一个标准。 在Java中,继承使用extends关键字实现,而实现通过implements关键字。 Java中支持一个类同时实现多个借口,但是不支持同时继承多个类。 简单点说,就是同样是一台汽车,既可以是电动车,也可以是汽油车,也可以是油电混合的,只要实现不同的标准就行了,但是一台车只能属于一个品牌,一个厂商。 class Car extends Benz implements GasolineCar, ElectroCar{ } 在接口中只能定义全局常量(static final)和无实现的方法(Java 8以后可以有defult方法);而在继承中可以定义属性方法,变量,常量等。

montos 2020-06-01 15:50:19 0 浏览量 回答数 0

回答

一、OOP三大基本特性 OOP 面向对象程序设计(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事物的一切具体特征,只能对事物特征和变化规律的一种抽象,且在它所涉及的范围内更普遍、更集中、更深刻地描述客体的特征。通过建立模型而达到的抽象是人们对客体认识的深化。 封装 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的属性和方法只让可信的类操作,对不可信的进行信息隐藏。 继承 继承是指这样一种能力,它可以使用现有的类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展。 多态 多态指一个类实例的相同方法在不同情形有不同的表现形式。具体来说就是不同实现类对公共接口有不同的实现方式,但这些操作可以通过相同的方式(公共接口)予以调用。 二、OOD七大原则 面向对象设计(OOD)有七大原则,它们互相补充 开-闭原则 Open-Close Principle(OCP),即开-闭原则。开,指的是对扩展开放,即要支持方便地扩展;闭,指的是对修改关闭,即要严格限制对已有内容的修改。开-闭原则是最抽象也是最重要的OOD原则。简单工厂模式、工厂方法模式、抽象工厂模式中都提到了如何通过良好的设计遵循开-闭原则。 里氏替换原则 Liskov Substitution Principle(LSP),即里氏替换原则。该原则规定“子类必须能够替换其父类,否则不应当设计为其子类”。换句话说,父类出现的地方,都应该能由其子类代替。所以,子类只能去扩展基类,而不是隐藏或者覆盖基类。 依赖倒置原则 Dependence Inversion Principle(DIP),依赖倒置原则。它讲的是“设计和实现要依赖于抽象而非具体”。一方面抽象化更符合人的思维习惯;另一方面,根据里氏替换原则,可以很容易将原来的抽象替换为扩展后的具体,这样可以很好的支持开-闭原则。 接口隔离原则 Interface Segration Principle(ISP),接口隔离原则,“将大的接口打散成多个小的独立的接口”。由于Java类支持实现多个接口,可以很容易的让类具有多种接口的特征,同时每个类可以选择性地只实现目标接口。 单一职责原则 Single Responsibility Principle(SRP),单一职责原则。它讲的是,不要存在多于一个导致类变更的原因,是高内聚低耦合的一个体现。 迪米特法则/最少知道原则 Law of Demeter or Least Knowledge Principle(LoD or LKP),迪米特法则或最少知道原则。它讲的是“一个对象就尽可能少的去了解其它对象”,从而实现松耦合。如果一个类的职责过多,由于多个职责耦合在了一起,任何一个职责的变更都可能引起其它职责的问题,严重影响了代码的可维护性和可重用性。 合成/聚合复用原则 Composite/Aggregate Reuse Principle(CARP / CRP),合成/聚合复用原则。如果新对象的某些功能在别的已经创建好的对象里面已经实现,那么应当尽量使用别的对象提供的功能,使之成为新对象的一部分,而不要再重新创建。新对象可通过向这些对象的委派达到复用已有功能的效果。简而言之,要尽量使用合成/聚合,而非使用继承。

景凌凯 2020-03-19 23:49:30 0 浏览量 回答数 0

回答

str = c.toString() 在Java中c数组也是一个对象,该对象继承了Object,但是没有重写(override)Object类中的toString方法,所以根据对象的多态性,c.toString()调用的是Object类中的toString方法,参考源码如下: JDK源码中的Object类的toString方法 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }

DM。 2020-05-31 17:31:55 0 浏览量 回答数 0

回答

在Web+控制台部署环境的概览页面可以对部署环境进行配置管理。您可以查看部署环境详情,启停、部署、重启、重建、释放或删除部署环境,还可将当前部署环境生成配置模板,升降级当前部署环境的技术栈和下载部署环境的Wpfile。 访问部署环境的概览页面 登录Web+控制台,并在页面左上角选择所属地域。 在概览页最近更新的部署环境区域的右上角单击查看全部。 在应用及部署环境页面找到需要查看的应用,单击其左侧的 + 图标,查看应用所管理的环境列表。 在部署环境ID/名称列,单击目标部署环境ID进入部署环境详情页面。 查看部署环境的详情信息 部署环境详情的概览页面展示了部署环境的部署包版本、运行状态、技术栈、负责人和操作时间以及该部署环境最近生成的事件列表等信息。 部署包版本 部署环境上运行的应用的部署包版本,单击具体的部署包版本可以下载当前部署环境内的部署包。 运行状态 部署环境的运行状况,将光标移动至环境名称左侧的圆点上即可看到环境的运行状态。目前环境状态可分为两类,终态与过渡态,过渡态会伴随一个进行中的变更单,终态代表一个稳定的状态。 终态:已释放、运行中、已停止和异常。 过渡态:释放中、变更中、重启中、停止中和启动中。 部署环境的各个运行状态之间的关系图如下所示:部署环境运行状态说明 技术栈 显示部署环境上运行的操作系统版本、平台和架构版本。 公网访问地址 如果该部署环境内没有绑定SLB时,此处显示的地址是ECS的IP地址;如果环境内绑定了SLB,此处显示的是SLB实例的地址。 近期事件 近期事件页签内会显示该部署环境最近发生的事件流。在进行环境配置管理时,Web+会输出事件消息方便查看环境的变更信息。可以单击查看全部进入事件页面查看该部署环境的所有变更信息。 资源 在资源页签会显示部署环境内所包含的资源。例如VPC、ECS实例等资源信息都将在这个页签内展示。对ECS实例,您可以在资源页进行以下操作。 单击ECS实例ID,可进入ECS实例的管控页面。 单击ECS实例的公网IP地址,可进入应用首页查看应用。 单击远程连接可远程连接到ECS实例。 单击转包年包月可进入到ECS控制台来修改ECS实例的计费方式。 部署环境 在部署环境详情的概览页右上角单击部署,然后在部署环境对话框重新选择部署包来更新应用。 部署应用 选择部署包来源: 上传本地程序:单击选择文件上传本地部署包,并重新设置部署包版本,在版本描述输入框中输入相关描述用来辨识本次部署操作。 选择历史版本:选择一个已经部署过的历史版本重新部署。 选择执行方式: 单批发布:无需额外设置。 按实例数分批:选择分批的实例数和批次间隔时间。 按百分比分批:设置每批次的实例数的百分比,并设置批次间隔时间。 单击确定完成部署设置。 启停环境 停止环境 当部署环境处于运行状态时,在部署环境概览页面右上角单击停止,可以停止该部署环境。当停止部署环境后,您无需为应用服务付费,但部署环境内的ECS、SLB等资源仍会照常计费。 启动环境 当环境处于停止状态时,在部署环境概览页面右上角单击启动,可以启动环境重新运行。当启动环境后,环境设置中的应用模块的配置项会重新运行。 重启环境 在部署环境概览页面右上角单击重启,可以重启部署环境。重启部署环境实质是重启了应用的运行,不会终止或重启应用的部署环境内的任何资源。如果部署环境在响应一些错误请求时出现异常,重启可能会恢复功能,同时可能排查出故障原因。 重建环境 当部署环境运行状态异常时,在部署环境页面概览右上角单击重建可以重新构建环境,应用的部署环境内的所有资源都将重新构建,从而恢复环境的异常功能,同时可能排查出故障原因。 释放环境 在部署环境概览页面右上角单击释放,可以释放环境中的所有资源,然后从应用中删除环境。释放环境后,环境中的ECS、SLB等资源都将被释放从而终止计费,您只需支付存储产生的费用。 删除环境 在部署环境概览页面右上角单击删除,可以从应用中删除这个环境。Web+将物理删除该应用下所有的实例、负载均衡设备、以及环境的基本创建信息。 生成配置模板 在部署环境概览页面右上角单击更多选项 ,然后在下拉列表中单击生成配置模板。 在生成配置模板对话框中输入配置模板的名称和描述,然后单击确定。 Web+将基于此环境新建一个配置模板,该配置模板可用于发布新的部署环境。 说明 在生成配置模板对话框中单击查看已生成的配置模板,可跳转至配置模板管理页面。 生成配置模板 升降级技术栈 升降级技术栈会更新本部署环境的技术栈,并重新部署应用。在升降级技术栈前,请务必评估新的技术栈与您的应用的兼容性。 在部署环境概览页面右上角选择 更多选项 > 技术栈升降级。 在技术栈升降级对话框中选择要升级或降级的技术栈版本,然后单击确定。 下载Wpfile Wpfile包含了部署环境的配置信息,下载Wpfile后,可以更改文件然后重新在CLI中使用apply命令来更新或者创建环境。 在部署环境概览页面右上角单击 更多选项,然后在下拉列表中单击下载Wpfile。 在本地打开Wpfile文件可以查看和更改部署环境配置信息。

1934890530796658 2020-03-23 13:51:59 0 浏览量 回答数 0

回答

通过维基百科: Java和C#的早期版本不包含泛型(又称参数多态性)。 在这种情况下,使数组不变会排除有用的多态程序。例如,考虑编写一个对数组进行混洗的函数,或者使用Object.equals元素上的方法测试两个数组是否相等的函数。实现方式不依赖于存储在数组中的元素的确切类型,因此应该可以编写一个可在所有类型的数组上使用的函数。实现类型的功能很容易 boolean equalArrays (Object[] a1, Object[] a2); void shuffleArray(Object[] a); 但是,如果将数组类型视为不变的,则只能在类型完全相同的数组上调用这些函数Object[]。例如,无法将一组字符串混排。 因此,Java和C#都会协变地对待数组类型。例如,在C#中string[]是的子类型object[],在Java中String[]是的子类型Object[]。 这回答了问题:“为什么是数组协变的?”,或者更准确的说,“为什么是由协阵列的时候?” 当引入泛型时,出于Jon Skeet在此答案中指出的原因,有意地使它们无协变: 不,a List 不是List 。考虑一下您可以做什么List -您可以向其中添加任何动物...包括猫。现在,您可以在逻辑上将猫添加到一窝小狗中吗?绝对不。 // Illegal code - because otherwise life would be Bad List dogs = new List (); List animals = dogs; // Awooga awooga animals.add(new Cat()); Dog dog = dogs.get(0); // This should be safe, right? 突然,你有一只非常困惑的猫。 Wikipedia文章中描述的使数组协变的原始动机不适用于泛型,因为通配符使协方差(和相反方差)的表达成为可能,例如: boolean equalLists(List l1, List l2); void shuffleList(List<?> l); 问题来源于stack overflow

保持可爱mmm 2020-02-07 13:18:56 0 浏览量 回答数 0

回答

方案一:Hook 到文件系统内部的事务机制 方案 1 的问题是功能有限,而且很多文件系统没有直接对用户暴露事务。功能有限例如没有回滚机制等。Btrfs 提供了一对系统调用使得内部的事务机制可以对用户暴露。基于 Btrfs 的 FileStore 第一版是依赖于这些系统调用的,但是它没有回滚机制导致很痛苦——具体来说,如果 Ceph OSD 在事务过程中遇到了一个 fatal 事件,例如软件崩溃或者 kill 信号,Btrfs 会提交一个部分(partial)事务,留给存储后端一个不一致状态。 Ceph 团队和 Btrfs 团队都接受的解决方法包括提供一个 entire transaction 系统调用,或者基于快照实现回滚,但这两个方案都有很高的成本。最近 Btrfs 废弃掉了事务系统调用,和微软对 NTFS 的决定类似。 方案二:在用户态实现 WAL 方案二是可行的,但是受三个主要问题的影响: 读取-修改-写入速度 一个用户态 WAL 实现每个事务需要三步:第一步、先对事务序列化,写入到日志;第二步、通过 fsync 持久化日志;第三步、执行事务内的操作 这样最终导致整个 WAL 的延迟很高,无法实现高效的 pipeline 非幂等操作 FileStore 中对象通过文件表示,对象集合会映射到目录。 在这种数据模型下,crash 之后重放 WAL 因为一些操作非幂等会导致很有难度。在 WAL 定时 trim 时,总会有一个时间窗口事务日志已经提交到文件系统但事务还没有完成(a window of time when a committed transaction that is still in the WAL has already been applied to the file system)。举个例子,考虑一个事务包含三个操作:①克隆a到b②更新a③更新c如果在第二步之后发生 crash 了,replay WAL 会破坏 b在考虑另一个例子,事务有四个操作:①更新b②将b重命名为c③将a重命名为b④更新d如果在第三个操作之后发生了 crash,重放 WAL 会破坏 a(也就是现在的 b),然后因为 a 已经不存在而失败。 基于 Btrfs 的 FileStore 通过对文件系统做周期性快照和对 WAL 做快找时间的标记来解决这一问题。当恢复时,最近的一个快照被恢复,然后 WAL 从相应时间点那一刻开始 replay。 但因为现在已经使用 XFS 来替代 Btrfs,XFS 缺乏快照带来了两个问题。首先,XFS 上 sync 系统调用是将文件系统状态落盘的唯一选择,但对一个典型的多磁盘构成的节点来说,sync 过于昂贵因为会对所有磁盘生效。这个问题已经被增加 syncfs 调用解决——只同步指定的文件系统。 第二个问题是在 WAL replay 后,恢复文件系统到指定状态会因为上面说的缺乏幂等性而产生问题。为此 Ceph 又引入了 Guards(序列号 sequence numbers )来避免 replay 非幂等操作。但庞大的问题空间导致在复杂操作下 guards 的正确性也很难验证。Ceph 通过工具产生复杂操作的随机排列,然后加上错误注入来半自动的验证正确性,但最终结果是 FileStore 的代码很脆弱而且难以维护。 双写。最后一个问题是数据会被写两次,一份到 WAL 一份到文件系统,减半了磁盘的带宽。核心原因是大部分文件系统都只对元数据修改记录到日志,允许在 crash 后丢失数据。然而 FileStore 对文件系统的使用(namespace、state)因为一些 corner case(例如对多文件部分写 partially written files)导致 FileStore 不能像文件系统一样只在日志中记录元数据修改。 尽管可以说 FileStore 这种对文件系统的使用是有问题的,但这种选择也有技术原因的。如果不这么做就需要实现数据和元数据的内存 cache 以等待 WAL 的任何更新——而内核已经有了 page 和 inode 的缓存。 方案三:使用有事务的 KV 数据库 在 NewStore 方案中,元数据保存在 RocksDB,一个有序 KV 数据库,而对象数据继续在文件系统上以文件形式表示。这样,元数据操作直接在数据库执行;数据的覆盖写被记录到 RocksDB 然后延迟执行。下面介绍 NewStore 如何解决前面说到的用户态 WAL 的三个问题,然后介绍后面因为在一个日志文件系统上运行带来的极高的一致性成本。 首先,因为 KV 数据库的接口允许我们直接读取对象状态而不需要等待上一个事务完成,从而避免了缓慢的“读取-修改-写入”。 其次 replay 非幂等操作的问题通过在准备事务时在读取侧解决。举个例子,克隆 a 到 b,如果对象比较小,那么就复制一份并插入到事务,如果对象比较大,那么就用 COW 机制,将 a 和 b 指向到同一数据,并把数据标记为只读。 最后,双写的问题也解决了,因为对象的命名空间已经和目录结构解耦,新对象的数据都会先写到文件系统然后自动添加引用到数据库。 尽管上面说了许多好处,但与 journal on journal 类似,日志文件系统与 RocksDB 的组合会带来很高的一致性开销。在 NewStore 上创建对象需要两步: 写入一个文件并执行 fsync 同步将对象元数据写入到 RocksDB,也会导致一次 fsync 理想状态下,每次 fsync会导致一次昂贵的 FLUSH CACHE 操作到磁盘。但实际上在日志文件系统上每次 fsync会带来两次 flush command:一次是写数据,一次是文件系统提交元数据日志。这样导致在 NewStore 上创建对象会产生四次昂贵的 flush操作。 下面用一个模拟测试来展示这一开销,测试方法是模拟存储后端创建大量对象,每轮会先写 0.5MB 数据然后插入 500Byte 的元数据到 RocksDB。先模拟 NewStore (在 XFS 上)的实现,然后模拟在裸盘上的实现。

kun坤 2020-04-23 19:49:36 0 浏览量 回答数 0

回答

类型擦除会出现在泛型方法中,程序员通常认为下述的泛型方法 public static <T extends Comparable> T min(T[] a) 是一个完整的方法族,而擦除类型之后,只剩下一个方法: public static Comparable min(Comparable[] a) 这个时候类型参数T已经被擦除了,只留下了限定类型Comparable。 但是方法的擦除会带来一些问题: class Coupling extends Couple<People> { public void setTwo(People people) { super.setTwo(people); } } 擦除后: class Coupling extends Couple { public void setTwo(People People) {...} } 这时,问题出现了,存在另一个从Couple类继承的setTwo方法,即: public void setTwo(Object two) 这显然是一个不同的方法,因为它有一个不同类型的参数(Object),而不是People。 Coupling coupling = new Coupling(...); Couple<People> cp = interval; cp.setTwo(people); 这里,希望对setTwo的调用具有多态性,并调用最合适的那个方法。由于cp引用Coupling对象,所以应该调用Coupling.setTwo。问题在于类型擦除与多态发生了冲突。要解决这个问题,就需要编译器在Coupling类中生成一个桥方法: public void setTwo(Object second) { setTwo((People)second); } 变量cp已经声明为类型Couple,并且这个类型只有一个简单的方法叫setTwo,即setTwo(Object)。虚拟机用cp引用的对象调用这个方法。这个对象是Coupling类型的,所以会调用Coupling.setTwo(Object)方法。这个方法是合成的桥方法。它会调用Coupling.setTwo(Date),这也正是我们所期望的结果。

问问小秘 2020-06-23 14:47:34 0 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 企业建站模板