方法论:在不是太懂源码的情况下,我是怎么定位源码问题的?

在日常开发中,我们多多少少会遇到些问题,有时候是自己的写法有错误,这时候可能就要先检查一遍,看看文档,看看是哪里的问题。

但有时候也有可能是框架/工具的源码错误,虽然一般这种情况很少发生,因为一般框架/工具都会做了比较多的单元测试,经过开源社区的验证,出错的概率比较少,但也不一定所有情况都能测试到。

那么,如果真的认为是源码的 Bug,我们该怎么去定位呢?

本篇文章讲解介绍我最近遇到的一个真实例子,在不是太懂源码的情况下,通过自己的一些经验、调试技巧,去定位问题

发现问题

在我的某个项目中,当我使用 pnpm i --fix-lockfile 时,一定会报如下错误:

运行 pnpm i 的时候,不会报错,只有运行 pnpm i --fix-lockfile 会报错。在一些业务场景下,我们偏向于使用 pnpm i --fix-lockfile,当然我也可以改为用 pnpm i,那故事就结束了,全剧终hhh。

当然我还是稍微努力了一下下,准备提个 issue 看看。

既然要提 issue,那就得首先觉得它是 pnpm 自身的问题,不是我写的代码有问题。我个人主要是有以下原因:

  • 我就是安装个依赖,这能有什么错哦。。。而且它 pnpm i 是能安装的
  • --fix-lockfile 这个选项,肯定比仅仅使用 pnpm i 的场景少,那在极端场景下,可能 pnpm 的单元测试没覆盖到,有问题也是正常的
  • 我是学过英文的,错误信息很明显就说,vite@4.0.4_@types+node@17.0.45 这个版本解析不出来,个人感觉应该是要解析成 vite 4.0.4,我 package.json 也是这么写的,pnpm 自己加的其他东西,那肯定不关我的事情呀。而且 pnpm 的 lock 文件也是用 vite@4.0.4_@types+node@17.0.45,那是你的问题没错了
  • 错误信息中出现 @vitejs/plugin-basic-ssl,有可能是这个包不行,但 pnpm i 既然能正常安装,就证明人家本身没问题,是 pnpm 的问题。

因此,我提了个 issue,就贴了个截图,然后写 pnpm i --fix-lockfile 安装失败,是解析版本失败了,还贴了 pnpm 的锁文件。

我觉得我已经写得很明白了,这么一个 package 的版本解析错误问题,作者应该一看就懂。。。了吧

结果不出所料,作者也看不懂,让我提供一个最小的复现 Demo

这里补充一个知识点,一般提 issue 的时候,都要带上最小的复现 Demo,不然人家作者也没办法复现你的问题。

但是鸭,很多时候,开发者可能遇到问题了,却提供不出来,主要有以下原因:

  • 项目非常大,不知道哪里有问题,因此不知道怎么做一个最小复现的 Demo
  • 是公司的项目,不能将代码提供出去

我是两个原因都有,因此不是我不想提供 Demo,而是我也搞不出来。。。因此想碰碰运气,说不定作者一看就知道呢hhh,结果不出所料,还是得提供 Demo。

很多人提供不了最小复现 Demo,开源库作者也没办法知道问题,然后问题就不了了之。

因此,很多人也只能走到这一步,然后故事就结束了。

但其实不是完全不可能提供一个 Demo,看要不要再努力一下下。这时候人和人的差别就会显现出来了

  • 有的人可能觉得换一种方式就行了
  • 有的人可能觉得没多大影响,不折腾了
  • 有的人可能觉得,我就是要搞出来。

当我第一次遇到这个问题的时候,我也是抱着,算了不管了

后来再遇上,真烦,不如提个 issue 碰碰运气吧

再后来多遇上几次,实在不想忍了,晚上调试一下看看,就花一个晚上,不行拉倒

因此才有了接下来的一些努力。

有时候,你离开源贡献,就只有一念之差。只是,有些人选择放弃,有的人选择再努力一下。

调试代码

光有决心还是没有的,得实际行动。

但一个巨大的问题摆在面前,pnpm 的代码我也没看过鸭,调个啥玩意???

因此,第一个问题,是怎么把 pnpm 源码跑起来调试呢?

pnpm 源码调试

之前看了神光大佬的调试小册,学到了很多调试相关的知识,感兴趣的可以学习一下

一般情况下,如何知道一个开源仓库要怎么进行调试呢?

  1. 看仓库的 CONTRIBUTING.md 文档,按道理比较常见的开源仓库都会有
  2. 找别人总结过调试文章

我随便在掘金,找了一遍文章,毕竟能调试,能打断点就行。因此如何调试的问题就解决了。

这里总结一下:

  • pnpm i 先安装 pnpm 源码的依赖
  • pnpm run compile,执行源码所有包的构建(pnpm 是 monorepo 仓库)
  • 用 node 执行 pnpm 的入口脚本

下图是我在 webstorm 的调试配置,qf-tds-vue-plugins 是我的项目文件夹,下面配置的意思是,我要在这个文件夹运行以下命令(因为是在项目目录安装依赖):

# 实际上 pnpm i,也是运行全局安装的 pnpm 目录下的 bin/pnpm.cjs
node /candy/app/pnpm/pnpm/bin/pnpm.cjs i --fix-lockfile

找个地方打个断点,代码能停住(停不住可能是根本没运行这行代码,换个别的),就代表这一步已经成功了

定位问题

这一步才是最核心、但又最麻烦的步骤

如何在茫茫源码中定位问题?下面是我的一些个人经验:

从错误信息出发,找到报错的代码

我们全局搜索关键字isn't supported by any available resolver,找到是哪一行报错的,找到之后,打个断点。

这就找到了报错源头了。因为 resolution 不为真值,所以报错了,那我们的问题就变成了,为什么 resolution 不为真值。这就将很大很抽象的问题,转化成了一个更小更明确的问题

resolution 是由 resolveFromNpm 返回的,那我们就修改一下断点位置

这里有一个小经验,断点位置要改到哪里比较好?有两种方式:

  • 找到 resolveFromNpm 的函数源码实现,在函数实现里面打断点
  • 直接在 resolveFromNpm 函数调用的位置打断点。

我个人更偏向与在调用的位置打断点,因为更方便。可以看上图的例子,resolveFromNpm 是另一个函数返回的,如果你想要找到它的实现,还得进去 createNpmResolver 函数里面找,说不定里面函数比较复杂,就比较麻烦,需要找到 resolveFromNpm 函数真正的内部实现,才能打断点 。

如果是在调用位置打断点,就会在 resolveFromNpm 函数调用前停住,此时,我们按进入函数,就能直接找到源码了

因此断点会改到这里,但我们运行后会发现,每个 package 都会在这里暂停,一个项目这么多包,不行啊。

这时候就要用到条件断点如何设置条件断点呢?可以先观察一下一些变量的值

可以看到 wantedDependency.pref 的值为 4.0.4_@types+node@17.0.45,那就用这个了。断点的条件就设置为

wantedDependency.pref === '4.0.4_@types+node@17.0.45'

这就能在出错前将代码定住了,然后我们进入函数

进入 resolveFromNpm 调试,然后发现 spec 为 null,所以函数 return null 了,因此又可以将问题转化:为什么 spec 会使 null?

那就要排查 parsePref 函数了,还是用上述的思路,打断点,进入函数,

同样的,按照上述思路就是 parsePref 函数的问题了,这里就不重复了。

最后发现,是 wantedDependency.pref 这个属性,应该为 4.0.4,才能使后面的代码不报错,而不是 4.0.4_@types+node@17.0.45

那接下来的问题就转化成了: wantedDependency.pref 为什么不为 4.0.4?我们需要找到 wantedDependency.pref 被赋值的地方

下面又是一些经验:

  • 全局搜索 .pref =,是为了所有出 wantedDependency.pref = xxx 的这些代码
  • 全局搜索 pref:(注意前面有空格),这个是为了搜索 { pref: xxx } 的代码

不过很可惜,在 pnpm 中都搜不到太多有用的信息,那就只能通过调试找了。接下来该怎么办呢?

我们可以利用函数的调用栈,逐级往上找,调试方法跟之前一样,目标是,找到 wantedDependency.pref 被赋值的地方。

有较多调试经验的开发者,也可以不逐级网上找,如果觉得肯定不会在当前函数层级被赋值,可以直接跳到更深的函数调用层级中

最终,我找到了整个 wantedDependency 初始化的地方:resolveDependency 函数。

这里我直接回顾一下整个错误的相关信息:

  1. @vitejs/plugin-basic-ssl 在安装 vite 的时候,遇到了版本解析错误,4.0.4_@types+node@17.0.45
  2. resolveDependency 函数中,会解析 @vitejs/plugin-basic-ssl 的 package.json。直接注意的是,它的 package.json 没有 dependencies 字段
  3. pkg 对象根据 package.json 生成,这一句代码中,由于 pkg.dependencies 不存在,因此会导致使用了锁文件的 dependencies 字段,这是不应该的,导致取了锁文件的 vite 版本号4.0.4_@types+node@17.0.45

  1. 装了多个 Vite,有的 Vite 版本号是 4.0.4,有的是 4.0.4_@types+node@17.0.45 ,出现多个 Vite 的原因,是因为 peerDependencies,感兴趣可以查看官网的说明文档
  2. @vitejs/plugin-basic-ssldependencies 字段不存在(不是为空,是不存在)

只有同时满足以上条件才会报错,因此很多非 monorepo 仓库,都不会有这个问题,因为它们只装了一个 Vite。

当我知道了以上信息之后,我就可以提供一个最小的可复现 Demo 了

不过,我觉得既然都看到这里了,不如尝试一下自己修复

直觉告诉我,只要加一点代码就行了,判断 pkg.dependencies是否为空,为空就设置为 {}

if (!pkg.dependencies) {
    pkg.dependencies = {}
}

然后我把出错原因写到了 issue 中,顺便提了个 pull request 给开源作者,然后被告知需要补一下单元测试(这也的确是正常且稳妥的做法),至于后续单元测试怎么补,就不是本文该关心的问题了,以后有机会再聊。

总结

本文用我个人的例子,从发现问题,到调试代码,一步步地深入,直到最终找到问题。里面用到了很多调试相关的技巧,这些技巧可以帮助我们,即使在不熟悉源码的情况下,也能深入源码进行定位问题

这些技巧主要包括以下这些:

  • 全局搜索查找关键词/错误信息,找到相关的源码
  • 转化问题,将大的抽象问题,变小变具体
  • 在合理的位置打断点
  • 巧用条件断点,巧妙的设置断点条件
  • 利用函数调用栈

当然,仅仅有技巧也不行,你需要有解决问题的决心。那么,当你遇到问题时,是选择避开它,还是选择解决它呢?

如果这篇文章对您有所帮助,可以点赞加收藏?,您的鼓励是我创作路上的最大的动力。也可以关注我的公众号订阅后续的文章:Candy 的修仙秘籍(点击可跳转)

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

相关文章

  • centos镜像添加chrome浏览器以及中文字体原创

    业务方有一个需求是想在服务器跑一些浏览器截屏的功能,因为这个环境是在容器中进行的,因此这里记录一下如何构建这个镜像。想要完成这个需求,有两个主要依赖项需要满足:chrome环境。中文字体。#1,演示验证了解需求之后,我们应该尽可能找到能够验证的方式,以免增加与需求人员进行更多无必要的沟通的成本。冲浪时我了解到chromedp(opensnewwindow)包能够进行相关操作,而且官方也提供了简便直观的示例,因此有如下脚本://Commandscreenshotisachromedpexampledemonstratinghowtotakea //screenshotofaspecificelementandoftheentirebrowserviewport. packagemain import( "context" "io/ioutil" "log" "github.com/chromedp/chromedp" ) funcmain(){ //createcontext ctx,can

  • 利用Docker+Jenkins+Pipeline完成Android自动化测试打包服务

    阅读本文大约需要2.7分钟。前言Docker首次创造了一种简单易行并且覆盖应用全生命周期的工作流。用户可以通过简单的指令或RestfulAPI来拉取、打包、运行和维护容器。这种简化从根本上降低了应用程序部署的难度,极大地提高了应用运行时环境的部署与维护的效率。Docker提供了一种统一的实践方法,每个服务(或应用)维护一个Dockerfile文件。即便使用编排工具如DockerCompose,一个服务(或应用)也只需维护一个docker-compose.yml文件。应用程序及其运行时环境全部打包到一个简单易读的Dockerfile或Compose文件中,开发团队和运维团队都可以透明地合作维护这个文件,极大地降低了沟通成本与部署成本,满足了研发团队与DevOps团队、运维团队之间的沟通需求,清晰划分了责任边界。这对应用开发者来说也是一种福音,使用各种开发环境的用户,再也不必担心破坏主机的系统环境(如环境变量)和应用程序。今天以自动化测试过程中的Android应用每日版本构建为例,讲解如何利用Docker+Jenkins+Pipeline来简化持续集成服务的部署。下面主要还是讲实践,对于D

  • 比特元黑科技?分片节点如何突破“数据膨胀"难题?

    2020的区块链公链的发展又迈向了新的行业里程碑,包括应用创新、生态联合等多方向齐头并进发展。然而繁荣背后,限制行业发展桎梏依旧存在,资本推动一时的繁荣,但真实的价值依旧要依靠技术去实现。当下,区块链公链的主旋律依旧是创新。公链行业目前依旧存在安全、性能、生态扩展、用户体验等核心问题。比特元项目也一直致力于对于桎梏公链行业发展核心痛点领域的突破。从2018比特元项目上线便以独创的公链-平行公链架构方案,为困扰公链行业发展的不可能三角问题及跨链问题提供了一种方案。行业内,相同类型解决方案直到19年,20年才陆续提出,而落地实现则需更久。目前比特元公链又向“数据膨胀”这一痛点发起挑战,旨在解决普通用户参与公链节点中面临的数据膨胀导致的用户体验、主网安全的问题。什么是数据膨胀公链本质上一个分布式存储的账本,这个账本由公链网络中的所有用户共同维护,每个用户手中都可以拥有一份完整的账本,这个账本就是公链领域中的节点。所以,公链的安全性、去中心化性的根源来自于节点。节点数量越多整条链的安全性和去中心化性越高。但这个账本并非一成不变,随着日积月累,这个账本的数据将会一直扩大,最终大到对于普通用户来说

  • 微服务[学成在线] day14:媒资管理

    ?知识点概览为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。本章节为【学成在线】项目的day14的内容 视频上传成功后通过RabbitMQ进行消息发送,再通过视频处理服务对视频进行格式转换,以及m3u8视频文件的生成。 实现媒资信息的浏览Vue跨组件间的通讯实战,实现课程计划与已上传的媒资文件的关联一、视频处理0x01需求分析原始视频通常需要经过编码处理,生成m3u8和ts文件方可基于HLS协议播放视频。通常用户上传原始视频,系统自动处理成标准格式,系统对用户上传的视频自动编码、转换,最终生成m3u8文件和ts文件,处理流程如下:1、用户上传视频成功2、系统对上传成功的视频自动开始编码处理3、用户查看视频处理结果,没有处理成功的视频用户可在管理界面再次触发处理4、视频处理完成将视频地址及处理结果保存到数据库视频处理流程如下:视频处理进程的任务是接收视频处理消息进行视频处理,业务流程如下:1、监听MQ,接收视频处理消息。2、进行视频处理。3、向数据库写入视频处理结果。视频处理

  • centos7 如何安装与使用 Anaconda

    Anaconda介绍CentOS7安装Anaconda3conda命令使用介绍帮助目录检查conda版本升级当前版本的conda环境管理列出所有的环境安装一个不同版本的python新环境复制一个环境创建一个新环境导出环境,Anaconda支持导入导出以方便迁移导入环境信息,即根据配置文件创建一个新环境:移除环境激活进入环境,请使用停用一个活动环境,请使用包管理查看已安装包向指定环境中安装包从Anaconda.org安装一个包通过pip命令来安装包conda配置添加镜像源查看当前镜像源删除镜像源设置安装时显示源url,不想就改为no查看源全部设置,包括链接、show_channel_urls值:查看conda配置文件其他注意事项安装conda后命令行前出现的base,取消每次启动自动激活conda的基础环境Anaconda介绍 Anaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。因为包含了大量的科学包,Anaconda的下载文件比较大,如果只需要某些包,或者需要节省带宽或存储空间,也可以使用Miniconda这个较小的发行版

  • 使用Django框架开发的第一个简易web程序:计算fasta序列长度和GC含量

    Django是python写成的开放源代码的web应用框架本次使用的基础配置 python版本:3.6.3 Django:2.2 Windows10系统 如何查看Django版本importdjango django.__version__复制流程新建一个Calculate_Seq_Length_20190815_v1文件夹,使用windows下的命令行进入这个文件下,使用如下命令新建工程这里推荐cmder这个小工具。django-adminstartprojectSeqLength复制此时目录下多了一个SeqLength文件夹 然后进入这个文件夹,创建新的应用cdSeqLength pythonmanage.pystartappseqLengthapp复制image.png进入seqLengthapp文件下新建templates文件夹用来存放html模板文件这里先存放一个用来输入序列的html文件,html代码如下:<!DOCTYPEhtml> <html> <title>CalculateLengthofSequence</title>

  • 快速理解为啥这个查询使用索引,那个查询不使用索引,学会了才发现:真tm简单

    B+树结构我们说对于InnoDB存储引擎来说,表中的数据都存储在所谓的B+树中,我们每多建立一个索引,就相当于多建立一棵B+树。对于聚簇索引对应的B+树来说,叶子节点处存储了完整的用户记录(所谓完整用户记录,就是指一条聚簇索引记录中包含所有用户定义的列已经一些内建的列),并且这些聚簇索引记录按照主键值从小到大排序。对于二级索引对应的B+树来说,叶子节点处存储了不完整的用户记录(所谓不完整用户记录,就是指一条二级索引记录只包含索引列和主键),并且这些二级索引记录按照索引列的值从小到大排序。我们向表中存储了多少条记录,每一棵B+树的叶子节点中就包含多少条记录(注意是“每一棵”,包括聚簇索引对应的B+树以及二级索引对应的B+树)。示例我们举个例子:CREATETABLEt( idINTUNSIGNEDNOTNULLAUTO_INCREMENT, key1INT, common_fieldVARCHAR(100), PRIMARYKEY(id), KEYidx_key1(key1) )Engine=InnoDBCHARSET=utf8;复制这个表就包含2个索引(也就是2棵B+树):以id列为主

  • 图论碎碎念(2.3)

    本文作者:云屿Hello,狗子们大家好~(老大:小编你工资不想要了吗?)咳咳咳.......各位同学们大家好,今天的图论碎碎念来和大家聊一聊树。如何定义一棵树呢?a树是一个图b无向c无圈d连通那么问题来了:a树是一个图,b无向在上一节里已经讲到了,但c和d什么鬼?这就需要对图扩展下。其中问题c.1:图论中的圈是啥?如果图中的一条链首位相连,这条链就是一个圈。问题c.2:图论中的链是啥?在有向或无向图中,若有点边交替序列:如果可以有则称该序列为链接vi0至vik的一条链。有的同学就要问了:问题c.3:链+圈的概念与路+回路的概念有啥区别?链(黄色)可以回头指向,路(红色)只能单行指向:圈和路区别同理:问题d.1:连通图是啥?连通图中每个点都在一条链上,不存在孤立点总之,树的定义可以按下图来理解:在这棵树中可以看到,点分为两类:一类是结点(圆),一类是端点(终端结点)(三角)。本宝宝是一棵树如果忽略指向:树既然是一个图,那就也可以由图展开;图既然可以展开成树,那树就一定也可以折叠成图。从树到图:从图到树:那么问题来了:如何使用MATLAB将图展开成树呢?请听下回分解。临近期末,这是一枚短小

  • 使用宝塔面板 WordPress 伪静态的一个小坑

    作为某些知名站长说的使用宝塔面板的小白,在使用面板的时候就遇到了一个小坑不能说是坑吧,也不是面板的问题,只是一个普遍存在的问题常见的WordPress伪静态都是这样子的:location/{ if(-f$request_filename/index.html){ rewrite(.*)$1/index.htmlbreak; } if(-f$request_filename/index.php){ rewrite(.*)$1/index.php; } if(!-f$request_filename){ rewrite(.*)/index.php; } }复制宝塔面板的WordPress伪静态多了一点东西:indexindex.htmlindex.php; rewrite/wp-admin$$scheme://$host$uri/permanent;复制这个index有什么用,就是一个优先级的东西,表示index.html比index.php的优先级高一点,如果两个页面同时存在,就会优先展示index.html页面接着看宝塔站点管理中的默认文档是这样的:index.php

  • synchronized 详解

    问题那到底使用synchronized关键字是不是就是一个监视器?不懂,理解的话可以向我发邮件gaomengjie_1@163.com,我虚心求教前言之前介绍如何使用Lock和Condation详情请查看传送门 介绍一下锁和条件的关键之处锁用来保护代码片段,任何时间只有一个线程执行被保护的代码锁可以管理试图进入被保护代码段的线程锁可以拥有一个或多个相关对象每个条件对象管理已经进入代码保护片段,但不能运行的线程synchronized(内嵌到Java语言内部的简单锁)publicsynchronizedvoidmethod(){ ...... } //等价于 publicvoidmethod(){ this.initLock.lock(); try{ //method }finaly{ this.initLock.unlock(); } }复制synchronized方法中使用wait方法是添加一个线程到等待集中,notifyAll/notify方法解除等待线程的阻塞状态 将静态方法声明为synchronized也是合法的,这样会获得相关类对象的内部锁。如果Bank类有一个静态的同步

  • 资源 | 下一代PS工具:Adobe照片级图像风格转换的Torch实现

    选自arxiv作者:栾福军等机器之心编译参与:李泽南、微胖康奈尔大学与Adobe的研究者们最近发布了一项通过卷积神经网络进行照片风格迁移的研究。随后,该技术在Torch中的实现也已出炉。读者可以点击「阅读原文」下载论文。论文地址:https://arxiv.org/abs/1703.07511项目地址:https://github.com/luanfujun/deep-photo-styletransfer图像风格迁移的研究在人工智能领域层出不穷,作为图像处理软件的龙头,Adobe的努力非常引人注目。最近,康奈尔大学与Adobe的研究者们发布了一项通过卷积神经网络进行图片风格迁移的研究。在本研究的论文中,作者宣称解决了神经网络风格迁移中参考图像风格化导致输出图像「畸变」的问题,新的模型在各种图片内容的测试中表现良好,同时忠实地再现了参考图片中风格迁移的效果。它或许可以成为下一代Photoshop的功能之一。论文:DeepPhotoStyleTransfer摘要:本论文介绍了一种实现照片风格迁移的深度学习方法,这种方法可以处理很多不同种类的照片内容,同时还能如实迁移参考风格。近期,我们研

  • 只要3分钟,Python生成器原理详解

    翻译:你逗比 segmentfault.com/a/1190000011330511这篇文章是对500LinesorLess一书中高效爬虫一章的部分翻译,原文:HowPythonGeneratorsWork。建议结合《流畅的Python》食用。在掌握Python生成器之前,你必须了解常规Python函数的工作原理。通常,当一个Python函数调用子程序(subroutine)时,这个子程序将一直持有控制权,只有当子程序结束(返回或者抛出异常)后,控制权才还给调用者:>>>deffoo(): ...bar() ... >>>defbar(): ...pass标准的Python解释器是用C写的。解释器用一个叫做PyEval_EvalFrameEx的C函数来执行Python函数。它接受一个Python的堆栈帧(stackframe)对象,并在这个堆栈帧的上下文中执行Python字节码。这是foo的字节码:>>>importdis >>>dis.dis(foo) 20LOAD_GLOBAL0(bar) 3CALL_FUNC

  • 腾讯生物认证开放平台——TENCENT SOTER

    什么是SOTER现如今,生物识别作为一个新兴的认证方式,从好莱坞大片的银幕中正款款走出,进入人们的日常生活。其中,指纹识别是生物识别茫茫类目中的佼佼者,尤其是自从2011年苹果公司推出了iPhone4s这一款跨时代的智能手机之后,指纹识别模块越来越多得出现在各大智能终端上。尤其是近两年,无论是小清新iOS设备,还是Geek范的Android设备,都越来越重视生物识别在智能手机上的应用。从应用场景上来说,从之前单纯的人脸或者指纹解锁,到如今指纹支付以及授权通过各大app普及开来;而从系统层面,作为一向习惯于将设备接口能力开放出去Google,也在2015年2015年5月的GoogleI/O大会发布的AndroidM(正式版为Android6.0)中提供了官方的指纹接口以及针对指纹的增强版本密钥管理机制。然而,在这貌似明朗的生物识别的智能设备的天空中,始终漂浮着一朵乌云:目前,并没有一个能被各大手机厂商统一认可的生物识别标准流程。这就意味着虽然无论是iOS还是Android系统中虽然都提供了完备的客户端接口获取单次的指纹验证结果,但是:1、系统会告诉你这次验证结果正确与否,但是如果手机被破

  • 打造前端 Deepin Linux 工作环境——安装配置 atom 编辑器

    打造前端DeepinLinux工作环境——安装配置atom编辑器好,我个人推荐大家使用atom编辑器,第一是免费,第二是好看,第三是好用。安装atom编辑器我们输入apt-cachesearchatom|grep^atom查看安装包的名字好,我们确定了名字之后,输入下面的命令进行安装sudoapt-getinstallatom-y复制安装完成之后,我们就可以在程序列表中打开ATOM编辑器了安装atom插件Atom提供了相对比较简单的图形界面的安装插件。但是在我的实际操作过程中,发现比较难安装上,可能是因为墙的原因,又或者是因为我身处祖国的大西北,网络条件比较差的缘故。图形界面的插件安装比较简单,鼠标点点就可以了,这里不再重复。我主要说一下,如何在命令行下安装插件,这个安装,是百分百会成功的。前提,你已经安装了node.js、git。查找插件我们打开Atom的官方网站:https://atom.io/,点击Packages进入到插件搜索栏目,如下图所示:在图中红线框内,输入我们想要的插件名称,就可以进行搜索,例如,我们想要安装我们的前端神器emmet,然后按下回车键,就可以搜索到这个插件

  • Java-GUI 编程之 Swing

    Swing概述 实际使用Java开发图形界面程序时,很少使用AWT组件,绝大部分时候都是用Swing组件开发的。Swing是由100%纯Java实现的,不再依赖于本地平台的GUI,因此可以在所有平台上都保持相同的界面外观。独立于本地平台的Swing组件被称为轻量级组件;而依赖于本地平台的AWT组件被称为重量级组件。  由于Swing的所有组件完全采用Java实现,不再调用本地平台的GUI,所以导致Swing图形界面的显示速度要比AWT图形界面的显示速度慢一些,但相对于快速发展的硬件设施而言,这种微小的速度差别无妨大碍。使用Swing的优势:Swing组件不再依赖于本地平台的GUI,无须采用各种平台的GUI交集,因此Swing提供了大量图形界面组件,远远超出了AWT所提供的图形界面组件集。 Swing组件不再依赖于本地平台GUI,因此不会产生与平台相关的bug。 Swing组件在各种平台上运行时可以保证具有相同的图形界面外观。 Swing提供的这些优势,让Java图形界面程序真正实现了"WriteOnce,RunAnywhere"的目标。 Swing的特征:1.Swi

  • 通俗易懂设计模式解析——访问者模式

    前言   今天我们看的是访问者模式【VisitorPattern 】,我们理解访问者模式这个名称可能会有利于我们理解其核心代码块。我们看这么个例子:我去朋友家做客,那么朋友属于主人,我则属于访问者。这时刚好朋友在炒菜,却没得酱油了。如果朋友下去买酱油将会很麻烦而且会影响炒菜。这时就到我这个访问者出马了。一溜烟的出去打着酱油就回来了。简单理解的来说就是,访问者在主人原来的基础上帮助主人去完成主人不方便或者完不成的东西。 访问者模式介绍 一、来由   在软件系统开发中,我们经常会遇见一些层次结构完好的代码因为需求的更改而更改。你说这个时候我更改其基类吧,所有子类都要更改、这是一件很麻烦的事情。那么我能不能在不修改器层次结构完整的前提下完成新的需求的更改呢? 二、意图   表示一个作用于某对象结构中的各个元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。 三、案例图 四、访问者模式代码示例 看上面案例图可以发现访问者模式包含以下部分: 结构对象:节点的容器,包含多个类或者接口抽象节点:声明一个接收操作,接收访问者对象作为参数,声明处理接口,处理节点数据 具

  • 6 个开源的家庭自己主动化工具 | Linux 中国

    版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/F8qG7f9YD02Pe/article/details/79466841 用这些开源软件解决方式构建一个更智能的家庭。--JasonBaker实用的原文链接请訪问文末的“原文链接”获得可点击的文内链接、全尺寸原图和相关文章。致谢编译自 | https://opensource.com/life/17/12/home-automation-tools  作者 | JasonBaker 译者 | qhwdw?????共计翻译:87 篇贡献时间:124天用这些开源软件解决方式构建一个更智能的家庭。物联网[1] 不仅是一个时髦词。在现实中,自2016年我们公布了一篇关于家庭自己主动化工具的评论文章以来,它也在迅速占据着我们的生活。在2017,26.5%的美国家庭[2] 已经使用了一些智能家居技术;估计五年内。这一数字还将翻倍。随着这些数量持续添加的各种设备的使用,能够帮助你实现对家庭的自己主

  • 常见的负载均衡策略

    轮询(RoundRobin) 轮询的实现方式比较简单,就是将请求以此分发到后端服务器中,将所有的请求均匀分配,均匀分配的坏处是通常后台服务器性能有差异,有时候希望性能较好的服务器可以多承担些请求,该策略无法满足需求。这个不适合对长连接和命中率有要求的场景。 加强轮询(WeightedRoundRobin) 这种策略是对轮询策略的优化,对每个后端服务器设置一个权重值,根据权重值决定请求的分配比例,这种做法解决了轮询策略的不足,但是该权限值需要手动配置,没有办法自动动态调节,同样不适合对长连接和命中率有要求的场景。 hash算法 通过ipurl等信息计算hash值,然后对服务器的数量取模,相同的请求会请求到同一个后端服务器中。该算法无法解决热点请求,会把某个时间段的热点请求路由到某个单机上,造成雪崩效应,同时在扩中和节点宕机时发生命中率急剧降低的问题(hash算法导致),该策略适合维护长连接和提高命中率。 随机Random 根据随机算法,将请求随机分配到后端服务器中,请求的均匀请求依赖于随机算法,该实现方式较为简单,常常可以配合处理一些极端的请求,例如热点请求情况。不适合对命中率有要求的场

  • python 调用百度地图api接口获取地理详细信息行政代码等

    题目要求:根据单位名称获取具体位置(精确到区县)以及地域行政代码等信息 解决方法:利用python,调用百度地图API:        ①通过地理编码服务由得到的单位名称得到经纬度;         ②再通过逆地理编码服务,由①中得到的经纬度得到单位的具体地理信息(位置,行政代码等)       一.准备工作 认证,添加应用,百度地图API注册                  二.根据需要选取服务接口(这里选取地理编码服务API以及逆地理编码服务)  在文档中查看如何获取url,以及返回的Json数据格式;      三.代码实现 1.根据单位名称获取经纬度 #!/usr/bin/envpython #-*-coding:utf-8-*- #@File:paqu_area_info.py #@Author:田智凯 #@Date:2020/3/12 #@Desc:根据完成单位名称(取第一个)爬取得到

  • 微信小程序报错:Expecting &#39;STRING&#39;, got INVALID

    具体错误如下图:     这是因为在微信小程序的app.json 文件中是不能包含有注释的,只需要把注释去掉就可以了。

  • 一个人牛逼不如一群人一起牛逼——致我最亲爱的程序员

    穷者独善其身,达者兼济天下。——《孟子》   这句话大致意思是:不得志的时候就洁身自好修养身心,得志的时候就使得天下都这样。以前我也一直这样理解的,觉得只有自己“达”了之后才能兼济天下。今天,一拍脑门,才发现不一定非要等着达了之后才能兼济天下。   下面给大家分享一下我的三件小事,充分的证明了一点,“达”可以兼济天下,也可以先有了兼济天下的心,达就是自然而然的事情了。   第一次学音标。初高中从来没有学过音标,几乎就是零基础,后来做了一个小小的英语小组长,需要带10期的和11期的同学学音标,冒着误人子弟的风险,每天比平时早起半个小时,学音标,与此同时本期的英语大牛艾玲担当了我的义务导师,教我一些重难点音标的发音和口型。就这样,学完了就马上去教别人,感觉这一个星期进步神速,至少能给自己交差了。如果没有这样的一个我为人人的机会,我觉得我不会成长的如此迅速。人总是需要有压力的,适当的压力能带给我们动力。责任心和抗压是以后一个领导者必修的功课。   第一次软考。这是一次让我难忘的考试,考试结束后吃的那顿饭是我觉得最值得的晚餐。我们整个

相关推荐

推荐阅读