虾皮二面:为什么数据库连接池不采用 IO 多路复用?

Java面试指南网站:javaguide.cn

今天我们聊一个不常见的 Java 面试题:为什么数据库连接池不采用 IO 多路复用?

这是一个非常好的问题。IO多路复用被视为是非常好的性能助力器。但是一般我们在使用 DB 时,还是经常性采用c3p0tomcat connection pool等技术来与 DB 连接,哪怕整个程序已经变成以Netty为核心。这到底是为什么?

首先纠正一个常见的误解。IO 多路复用听上去好像是多个数据可以共享一个 IO(socket 连接),实际上并非如此。IO 多路复用不是指多个服务共享一个连接,而仅仅是指多个连接的管理可以在同一进程。在网络服务中,IO 多路复用起的作用是一次性把多个连接的事件通知业务代码处理。至于这些事件的处理方式,到底是业务代码循环着处理、丢到队列里,还是交给线程池处理,由业务代码决定。

对于使用 DB 的程序来讲,不管使用多路复用,还是连接池,都要维护一组网络连接,支持并发的查询。

为什么并发查询一定要使用多个连接才能完成呢?因为 DB 一般是使用连接作为 Session 管理的基本单元。在一个连接中,SQL 语句的执行必须是串行、同步的。这是由于对于每一个 Session,DB 都要维护一组状态来支持查询,比如事务隔离级别,当前 Session 的变量等。只有单 Session 内串行执行,才能维护查询的正确性(试想一下一组 sql 在不断的增减变量,然后这组 sql 乱序执行会发生什么)。维护这些状态需要耗费内存,同时也会消耗 CPU 和磁盘 IO。这样,限制对 DB 的连接数,就是在限制对 DB 资源的消耗。

因此,对 DB 来说,关键是要限制连接的数目。这个要求无论是 DB 连接池还是 NIO 的连接管理都能做到。

这样问题就绕回来了,为什么 DB 连接不能放到 IO 多路复用里一并执行吗?为啥大家都用连接池?

答案是,可以用 IO 多路复用——但是使用 JDBC 不行。JDBC 是一个出现了近 20 年的标准,它的设计核心是 BIO(因为 199X 年时还没有别的 IO 可以用):调用者在通过 JDBC 时执行比如query这样的API,在没有执行完成之前,整个调用线程被卡住。而类似于Mysql Connector/J这样的driver完备的实现了这套语义。

当然如果 DB Client 的协议的连接处理和解析稍微改一下:

  1. 将 IO 模式调整为 Non-Blocking,这样就可以挂到 IO 多路复用的内核上(select、epoll、kqueue……)
  2. 在 Non-Blocking 实现的基础之上实现数据库协议的编码和解析

就可以实现用 IO 多路复用来访问 DB。实际上很多其他语言/框架里都是这么干的。比如 Nodejs,see https://github.com/sidorares/node-mysql2;或者 Vert.X 的 db 客户端https://github.com/mauricio/postgresql-async,不要在意这个名字,它实际上同时支持 mysql 和 postgres)。只不过对于 IO 多路复用,数据库官方似乎都没做这种支持——他们只支持 JDBC、ODBC 等等这些标准协议。

那么为什么基于 IO 多路复用的实现不能成为默认的,官方的,而要成为偏门呢?

对于数据库开发者来说。这种用法在整体的用户里占有量非常小,所以也许不值当的花大力气。只需要把协议写清楚(比如https://dev.mysql.com/doc/internals/en/client-server-protocol.html),就可以做实现。那么社区的有兴趣的人自然就可以去做。

另外一个原因是体系的支持。简单来讲,如果没有一个大的 Reactive 的运行环境,IO 多路复用的使用会非常受限。

IO 多路复用之所以能成立,是需要整个程序要有一个 IO 多路复用的驱动代码——就是 select 那句调用——等待事件来临,一个 blocking 的 API。整个程序必须以这个驱动代码为核心。这样就对整个代码的结构产生重大的影响。这种影响是没法用简单的接口抽象的。

Java Web 容器之所以可以使用 NIO 是因为 NIO 可以被封装到容器内部。Web 容器对外暴露的还是传统的多线程形式的Java EE接口。

如果 DB 和 Web 容器同时使用 NIO,那么调用的 DB 连接库与必须与容器有一个约定描述DB 的连接管理如何接入 Web 容器的 NIO 的驱动代码。在 Java 这个大环境下,不同人,不同的容器写的代码不同;又或者,不使用任何常见的容器,而是自己用 NIO 去封装一个。这样是无法形成代码上的约定的。那么多个独立的组件就不能很好的共享 NIO 的驱动代码。

上面这个用法假设整个程序应该共享一个 NIO 驱动代码。那么 Web 和 DB 可不可以各用各的呢?也是可以的,但是为了保证这两个 NIO 驱动代码不会相互 block,最好要分开两个线程。这样一来就会打破一般 Web 服务一个请求处理用一个线程的一般做法,会让程序边的更复杂——你的业务代码和 DB 查询之间必须做跨线程数据交换。

相反,连接池的实现就相对独立的多,也简单的多。外界只要配好 DB URL,用户名密码和连接池的容量参数,就可以做到自行管理连接。

NodejsVert.X是完全不同的。他们本质就是Reactive的。他们的NIO的驱动方式是其运行时的基础——所有要在这个基础上开发的代码都必须遵守同样的NIO+异步开发规范,使用同一个NIO的驱动。这样DBNIO的协作就不成问题了。

最后,有大量场景是需要 BIO 的 DB 查询支持的。批处理数据分析代码都是这样的场景。这样的程序写成 NIO 就会得不偿失——代码不容易懂,也没有任何效率上的优势。类似于Nodejs这样的运行时在此场景下,反而要利用async或等价的语法来让代码看起来是同步的,这样才容易写。

总结一下。DB 访问一般采用连接池这种现象是生态造成的。历史上的 BIO + 连接池的做法经过多年的发展,已经解决了主要的问题。在 Java 的大环境下,这个方案是非常靠谱的,成熟的。而基于 IO 多路复用的方式尽管在性能上可能有优势,但是其对整个程序的代码结构要求过多,过于复杂。当然,如果有特定的需要,希望使用 IO 多路复用管理 DB 连接,是完全可行的。

········· END ··············

本文转载于网络 如有侵权请联系删除

相关文章

  • 宿舍(寝室)管理系统设计与实现 | 附 演示、源码地址

    点击蓝字关注wo们宿舍管理是高校管理的重要组成部分,一套优秀的管理系统不仅可以降低宿舍管理的难度,也能在一定程度上减少学校管理费用的支出,更是建设现代化高校管理体系的重要标志。本篇文章将带你从宿舍管理系统的运行环境搭建、系统设计、系统编码,再到系统的实现,对整个过程进行详细描述,特别适合作为程序员的进阶项目案列,同样也是高校学生毕业设计系统的不二之选!1、系统架构模式本宿舍管理系统采用B/S架构模式。B/S架构的全称为Browser/Server,即浏览器/服务器架构。Browser指的是Web浏览器,与C/S架构相比,B/S模式极少数业务逻辑在前端实现,它的主要逻辑在服务器端实现。B/S架构的系统无须特别安装客户端软件,只有Web浏览器即可。B/S架构的分层:与C/S架构只有两层不同的是,B/S架构有三层,分别为:第一层表现层:主要完成用户和后台的交互及最终查询结果的输出功能第二层逻辑层:主要是利用服务器完成系统的业务逻辑功能第三层数据层:主要是进行数据瞬时态和持久态两者之间的相互转化2、技术选型选择合适的技术,整个项目就已经成功了一半。经过对系统需求和系统自身特点的分析,加上现代B

  • 函数

    函数函数的定义什么是函数函数:一段封装的代码实现了某一个功能函数的定义返回值类型函数名(参数类型参数){ 函数体; return返回值; }#include<stdio.h> intAdd(inta,intb);//函数声明推荐这种先声明后定义的方法 intmain() { printf("a+b:%d",Add(5,2)); return0; } intAdd(inta,intb)//函数的定义 { returna+b; }复制返回值函数定义的时候申明函数返回值类型函数结束前返回一个值注意事项函数声明中可以只写参数类型不写形参名字(但是定义不行)函数参数名如果有要和定义保持一致(不一致可能会出现问题)void类型函数可以没有返回值函数的调用普通调用调用方式:函数名(参数)Add(5,3);//直接调用函数复制函数声明在定义的函数的时候,如果在函数定义前调用,需要在调用的前面加上一个函数声明告知这个函数存在//main函数前声明函数 intAdd(inta,intb);//函数声明复制推荐先定义后实现,这样能够人让阅读代码的时候首先看到最重要的主函数ma

  • Serverless Jenkins with Jenkins X

    Jenkins服务器最初以Hudson的形式于2004年创建。Jenkins在软件开发和交付中已成为我们许多人的家喻户晓的名字,并且是CI+CD工具的领导者。迄今为止,Jenkins的工作已超过2050万,并且正在运行近20万的Jenkins服务器。这是多么惊人的数字哇!在此增长期间,诸如云和容器化等技术取得了重大进步,这意味着詹金斯的某些职责现在有了我们应该利用的更好的实现。如今,大多数公司都有Cloud计划,我们希望Jenkins与时俱进,走自己的CloudNative历程。Jenkins应该继续发展,并提供许多人所依赖的自动化,可靠性和开发人员体验。詹金斯的巨大成功也伴随着痛点。让我们快速回顾一下我们听到的一些最大的问题:Jenkins服务器是一个单点故障,尤其是在任何维护停机期间都会错过gitwebhook事件Jenkins服务器经常用尽磁盘空间,需要人员进行脚本编写和/或手动清理以保持亮起状态插件版本不匹配可能会导致升级期间发生冲突GitHub速率限制,由多分支插件扫描引起大型JVM即使在没有构建正在运行的情况下也需要高内存,使用基于使用情况的定价时会导致不必要的成本如果:我

  • 管理后台的登录功能-重新思考

    每个网站、APP都几乎必然有其管理后台,其中管理的内容则是公司的核心技术财产。而登录模块则是这扇大门,其安全的重要性可想而知。我们知道,功能越多,安全性就会越低,所以我们有必要重新审视一下,管理后台的登录界面到底需要些什么功能。一、功能模块的取舍1、基本的账号密码登录。这个无可避免是必然需要的了。2、图片验证码。验证码的目的是为了阻止机器人暴力撞库,作为管理后台很有必要,而且是要每次登录请求都需重新验证。3、填完用户名或密码时,Ajax实时验证。这个功能常见于一些自动管理后台的注册模块,用于验证用户名是否已被占用。但此功能通常会导致不需经过验证码验证,从而使得暴力撞库有机可乘。4、记住我选项。这是一个使用cookie记住登录用户的功能,使用户下次再来时可以不需要再登录即可通过验证。但cookie必然需要记录用户ID或用户名相关的信息,存在浏览器中,有一定的CSRF攻击风险和信息泄漏风险。5、找回密码功能。这是一个高危功能,无论是逻辑疏漏还是安全不严谨,都会导致账号的失窃。参考1月份支付宝找回密码的危机。所以建议做法是,公司文档保存相关的账号密码信息,如遇实在无法登录,则找技术人员进入数

  • springboot 在idea中实现热部署

    SpringBoot的web项目,在每一次修改了java文件或者是resource的时候,都必须去重启一下项目,这样的话浪费了很多的时间,实现了热部署,在每一次作了修改之后,都会自动的重启第一步:引入热加载的插件,springboot1.3开始就有的 project中添加spring-boot-maven-plugin,主要在eclipse中起作用,idea不需要加此配置,springboot项目的话,应该是有此配置,加里面的内容即可。第二部:idea设置(14版本)1、点击:file,Settings,Build,Execution,Deplment然后记得apply,2、组合键:Shift+ALT+Ctrl+/,选择“Registry”,回车,找到“complier.automake.allow.when.app.running”注意:因为我的idea是14版本,有的15版本或者是更高的在compiler里面是这样的:然后快捷键是Ctrl+Shift+A,一样找到complier.automake.allow.when.app.running,点击勾选即可。第三部:如果你用的浏览器

  • 互联网大猜想:如果丁磊将网易股票全部套现,会发生什么事情?

    说起网易,很多中国人都很熟悉,包括网易门户、邮箱、云音乐和游戏。这几年,最吸引大家的新闻是丁磊养猪的事情,让大家都觉得很意外。在中国,网易也是仅次于BAT的互联网公司。特别是在游戏业务方面,网易可以说是中国仅次于腾讯的第二大游戏公司。截止到目前,网易的市值超过了260亿美金,相当于1776亿人民币。并且,根据媒体的报道,丁磊在网易的持股比例超过40%,是网易最大的股东。相对于BAT的创始人来说,丁磊对网易的控制力更强。如果丁磊把手上所持有的股票全部套现,会发生什么样的事情呢?腾讯和阿里可能会买下网易 如果丁磊出售股票,腾讯和阿里是最有可能“下手”的。对于腾讯来说,如果买下了网易,基本就是控制了整个中国的游戏市场。游戏行业有个经典的段子,在中国只有三家游戏公司:腾讯、网易和其他。腾讯已经占据了国内游戏行业的半壁江山,如果再拿下网易,基本就会垄断中国的游戏市场。对于阿里来说,如果能够买下网易,就能拿到国内游戏市场很大的份额。并且,可以向腾讯的现金流业务发起进攻,这么好的机会,马云一定不会放过。在腾讯和阿里双寡头竞争的情况下,网易是决胜的关键,所以谁能够拿下网易,谁就能够占据巨大的优势。网易

  • Linux下如何安装和卸载JDK

    方式一、yum安装1、安装yuminstalljava-y安装完成后无须配置直接可以使用。 2、卸载yumremovejava*方式二、rpm安装1、检测rpm-qa|grepjdk复制显示:jdk-1.7.0_71-fcs.x86_64 copy-jdk-configs-1.2-1.el7.noarch复制2、卸载:#rpm-e--nodepsjdk-1.7.0_71-fcs.x86_64复制3、下载 wget--no-check-certificate--no-cookies--header"Cookie:oraclelicense=accept-securebackup-cookie"http://download.oracle.com/otn-pub/java/jdk/7u71-b14/jdk-7u71-linux-x64.rpm4、安装 chmod+xjdk-7u67-linux-x64.rpm rpm-ivhjdk-7u67-linux-x64.rpmvim/etc/profileexportjava_HOME=/usr/java/jdk1.7.0_25

  • JavaScript实现java中的|接口|继承|抽象类|继承|多态|对象|工厂模式|重写|重载|

    //定一个接口方法, varInterface=function(name,methods){ if(arguments.length!=2){ thrownewError('thisinstanceinterfaceconstructorargumentsmustbe2length!'); } this.name=name; this.methods=[]; for(vari=0,len=methods.length;i<len;i++){ if(typeofmethods[i]!=='string'){ thrownewError('theInterfacemethodnameiserror!'); } this.methods.push(methods[i]); } } Interface.ensureImplements=function(object){ if(arguments.length<2){ thrownewError('Interface.ensureImplementsmethod

  • 图论:树链剖分-边权

    给一个数,边之间有权值,然后两种操作,第一种:求任意两点的权值和,第二,修改树上两点的权值 1#include<cstdio> 2#include<cstring> 3#include<vector> 4#include<algorithm> 5usingnamespacestd; 6#defineDel(a,b)memset(a,b,sizeof(a)) 7constintN=100005; 8 9intdep[N],siz[N],fa[N],id[N],son[N],val[N],top[N];//top最近的重链父节点 10intnum,head[N],cnt; 11structEdge 12{ 13intto,next; 14}; 15Edgev[N*2]; 16structtree 17{ 18intx,y,val; 19voidread(){ 20scanf("%d%d%d",&x,&y,&val); 21} 22}; 23voidadd_Node(intx,inty) 24{ 25v[cnt].to

  • 编写T4模板+DapperHelper(Sqlite数据库,简单更改即可适用其他数据库)==》简易ORM-简单的更有效更容易管理不容易出错

    T4模板 <#@templatedebug="false"hostspecific="false"language="C#"#> <#@outputextension=".cs"#> <#@assemblyname="System.Data"#> <#@assemblyname="System.Data.SQLite"#> <#@importnamespace="System.Data"#> <#@importnamespace="System.Data.SQLite"#> //------------------------------------------------------------------------------ //姜佳泉测试T4模板 //说明:与DapperHelper绑定使用,基础功能只有增删改,没有查询,没有分页。 //理由-->只作通用性,各数据库分页及高级查询语法各异,需要不同sql语句通过DapperHelper实现高级查询与分页 //特殊说明:id自增 //--------

  • JAVA系列-GC

    1.OOM 1)常见OOM异常类型 (1)StackOverFlowError 栈内存溢出,用于深度方法调用(循环递归); (2)OutOfMemoryError:Javaheapspace 用于变量申请的空间大于jvm的最大值; (3)OutOfMemoryError:GCoverheadlimitexceed GC回收的时间过长时会抛出OutOfMemoryError,过长的定义是,超过98%的时间用来做GC并且回收了不到2%的堆内存,连续多次GC都只回收了不到2%的极端情况下才会抛出。假如不抛出GCoverheadlimit错误会发生什么情况?那就是GC清理的这么点内存很快会再次填满,迫使GC再次执行,这样就形成恶性循环,CPU使用率一直是100%,而GC却没有任何成果. (4)OutOfMemoryError:Directbuffermemory 堆外内存溢出,主要呈现在写NIO程序经常使用ByteBuffer来读取或者写入数据,这是一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里

  • SUMS

    8.14 T1 简单贪心,照着题意模拟即可。 T2 给一棵树,有点权与边权,定义一棵子树\(f(x)\)为子树里权值为\(x\)的点两两距离和,并给定\(k_i\),求以\(i\)为根的子树里满足\(f(x)\)最大的\(x\)与\(i\)的子树里编号\(k_i\)小的\(y\)的\(f(y)\)。 那么借助转移数组,用$g(x,i)$去表示我们\(i\)子树的所有权值为\(x\)的点到点\(i\)的距离和,而$h(x,i)$为\(i\)子树里权值为\(x\)的点的数目。 随便搞个数据结构去维护所有出现过的权值的\(f,h,g\)三个数组,自底向上地启发式合并。那么就只需要考虑如何用点\(v\)去更新父节点\(u\)的信息。 我们记录$f'(x,u)$为\(v\)并入之前的$f(x,u),g',h'$同理。 就会有 \[h(x,u)=h'(x,u)+h(x,v); \\ g(x,u)=g'(x,u)+g(x,v)+h(x,v)\timesw(u,v); \\ f(x,u)=f'(x,u)+g'(x,u)\timesh(x,v)+h'(x,u)\times(g(x,v)+h(x,v)\t

  • kafka 如何保证消息不丢失

    今天我们来分析一下这个问题。 先来回忆一下kafka中消息传输的整个过程 1、kafka在producer端产生消息,调用kafkaproducerclientsend方法发送消息 2、kafkaproducerclient使用一个单独的线程,异步的将消息发送给kafkaserver 3、kafkaserver收到消息以后,保存数据,并同步至副本 4、消息保存完成以后,返回给kafkaproducerclient端【消息发送成功】 5、kafkaconsumerclient调用poll方法,循环从kafkaserver端获取消息列表 6、kafkaconsumer端从kafkaserver获取到消息以后,开始消费消息 7、kafkaconsumer消费消息完毕以后,向kafkaserver(topic为_offset_consumer的消息队列)发送偏移量 在上述的整个流程中,消息丢失的情况分为以几种可能性: 1、producer端发送消息给kafkaserver端,中间网络出现问题,消息无法送达 2、kafkaserver端在收到消息以后,保存消息时发生异常,异常分为三种 (1)

  • ubuntu opencv 安装需要注意的坑

    因为调试Python代码,要在虚拟机上安装opencv。Ubuntu上没有源,只能从源代码编译。 上网搜到一堆文章,最后参考: OpenCV闯关记——Ubuntu16.04OpenCVPython开发环境搭建 这是一篇非常好的文章,很有参考价值,基本可以一步步走下来,只是在过程中遇到几个小坑。 1、工具、依赖库和开发的应用有关,可以不按这个安装,建议参考opencv官方文件安装 2、OpenCV源码直接按官方文档git克隆即可 3、虚拟环境可以直接安装 numpy 模块,不存在文件中的问题 4、ippicv_linux_20151201.tgz下载,此处文件版本会不同,根据文件名去网上搜,自己下载。    下载后,参考文件提示的位置不对,应当放到opencv主目录下的./cache/ippicv/下,文件名改为该目录下已经有的文件名 5、编译OpenCV库遇到问题,因为我把virtualenv创建的python虚拟环境目录,从dir1移动到了dir2,造成找不到python,折腾好久,最后把build下所有文件删除就好了  

  • 十大排序方法之基数排序

    基数排序原理 基数排序(以整形为例),将整形10进制按每位拆分,然后从低位到高位依次比较各个位。主要分为两个过程: (1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如53,个位为3,则放入3号桶中) (2)收集,再将放置在0~9号桶中的数据按顺序放到数组中   基数排序二维数组实现   源代码 /******************************************************** *函数名称:GetNumInPos *参数说明:num一个整形数据 *pos表示要获得的整形的第pos位数据 *说明:找到num的从低到高的第pos位的数据 *********************************************************/ intGetNumInPos(intnum,intpos) { inttemp=1,i; for(i=0;i<pos-1;i++) temp*=10; return(num/temp)%10; } /****************************

  • CodeMirror在线代码编辑器使用以及如何取值

    目前CodeMirror在线代码编辑器在运用还蛮广泛的,支持100多种语言,高度可定制。支持语言有C、C++、C#、Java、Perl、HTML、CSS、PHP、JavaScript、Python、Lua、Go、Groovy、Ruby等。以及diff、LaTeX、SQL、wiki、Markdown等文件格式。CodeMirror为各种编程语言实现关键字、函数、变量等代码高亮显示,丰富的API和可扩展功能以及多个主题样式。如果要在页面中需要嵌入一个代码编辑区,CodeMirror是最佳的选择。 关于下载可以直接到官网上去下载 CodeMirror的官网是:http://codemirror.net/ 代码托管在Github上,下载地址:https://github.com/codemirror/CodeMirror/archive/master.zip 下面是需要引入的css <linkhref="codemirror/lib/codemirror.css"rel="stylesheet"type="text/css">//必须引入,是CodeMirror的核心样式文件 &

  • CF1203B Equal Rectangles

    题意:求n个数字的约数的个数 做法:已知x是n个数字的最大公约数,x可以分解为t个质数,216=2^3*3^3,216的约数个数4*4 #include<stdio.h> #include<string.h> #include<list> #include<algorithm> usingnamespacestd; typedeflonglongll; typedefdoubledb; constintmaxsz=10001; constintmaxn=4e5+1; //intcnt[maxsz]; lla[maxn]; boolisprime(llnum){ if(num==1)returnfalse; for(lli=2;i*i<=num;i++) if(num%i==0)returnfalse; returntrue; } intmain(){ intt; lln; scanf("%d",&t); for(inti=1;i<=t;i++)scanf("%lld",a+i); n=a[1]; for(inti=

  • STM32的优先级NVIC_PriorityGroupConfig的理解及其使用

      我自己依据此图理解,应用思维导图画了一张方便理解:(如果看不清可通过ctrl+鼠标滑轮   放大看;) 前提条件1:组别优先顺序(第0组优先级最强,第4组优先级最弱):NVIC_PriorityGroup_0>NVIC_PriorityGroup_1>NVIC_PriorityGroup_2>NVIC_PriorityGroup_3>NVIC_PriorityGroup_4前提条件2:“组”优先级别>“抢”占优先级别>“副”优先级别前提条件3:同一组优先级别中,不同的抢占级别之间,其中一抢占级别正在做事,另外抢占级别不能打断他;(即”同一组优先级下的中断源间,没有中断嵌套“)前提条件4:不同组优先级别间,依据优先级强弱,优先级别高的组的中断源可以打断优先级别低的组的正在做的事情;(即:不同组优先级间,可以中断嵌套) 下面:我们给一段优先级配置的代码进行详尽分析,方便上面的理解: 关以"前提条件一"的实例: 前提条件1:组别优先顺序(第0组优先级最强,第4组优先级最弱):NVIC_PriorityGrou

  • B进制星球

    【题目描述】 话说有一天,小Z乘坐宇宙飞船,飞到一个美丽的星球。因为历史的原因,科技在这个美丽的星球上并不很发达,星球上人们普遍采用B(2<=B<=36)进制计数。星球上的人们用美味的食物招待了小Z,作为回报,小Z希望送一个能够完成B进制加法的计算器给他们。现在小Z希望你可以帮助他,编写实现B进制加法的程序。 【输入格式】 共3行第1行:一个十进制的整数,表示进制B。第2-3行:每行一个B进制数正整数。数字的每一位属于{0,1,2,3,4,5,6,7,8,9,A,B……},每个数字长度<=2000位。 【输出格式】 一个B进制数,表示输入的两个数的和。 【样例输入】 4 123 321 【样例输出】 1110 【分析】 普通高精度加法加一些模拟,不难,但太坑。尤其是输出语句害的我一直是60分。注意三点: 一:进位时注意啦,是B进制的加法,不是10进制啦! 二:输入时注意字母,要特殊处理! 三:输出时还要注意字母,还要特殊处理! 四:字母A的ASCLL码是65,但是考虑进位10,所以在程序里要写55! var a,b:array[1..10001]ofintege

  • 剑指offer刷题记录

    记录了剑指offer的刷题过程,一共67道题,题目来源牛客网-剑指offer。 1.数组--二维数组中的查找 题目: 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 思路: 左上角为最小值,右下角为最大值,进行二维二分查找 #python classSolution: defFind(self,target,array): w=len(array) foriinrange(w): iftargetinarray[i]: returnTrue 复制 /* *C++ *参考https://www.nowcoder.com/profile/9734827/codeBookDetail?submissionId=12713594 *矩阵是有序的,从左下角来看,向上数字递减,向右数字递增, *因此从左下角开始查找,当要查找数字比左下角数字大时。右移 *要查找数字比左下角数字小时,上移 */ classSolution{ public: bool

  • 防抖和节流

    作用:防抖和节流的作用都是防止函数多次调用,如果回调函数是ajax请求或者进行复杂的计算,那么页面就会出现卡顿现象 区别:假设一个用户一直触发这个函数,且每次触发函数的间隔小于wait,防抖的情况下只会调用一次,而节流的情况会每隔一定时间(参数wait)调用函数。 防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间 你尽管触发事件,但是我一定在事件触发n秒后才执行,如果你在一个事件触发的n秒内又触发了这个事件,那我就以新的事件的时间为准,n秒后才执行,总之,就是要等你触发完事件n秒内不再触发事件,我才执行 每次触发事件时都取消之前的延时调用方法 functiondebounce(fn){ lettimeout=null;//创建一个标记用来存放定时器的返回值 returnfunction(){ clearTimeout(timeout);//每当用户输入的时候把前一个setTimeoutclear掉 timeout=setTimeout(()=>{//然后又创建一个新的setTimeout,这样就能保证输入字符后的interval

相关推荐

推荐阅读