板块介绍
- 分享一些技术相关的知识、经验和实践
- 涵盖不同编程语言、框架和开发技巧
板块公告
- 如果在技术实践中有任何问题可以联系我一起交流
- 欢迎讨论和提出建议
说明 你会发现,Web 开发中服务器接受一个请求正常不就是走那个执行流程产生一个返回结果返回回去吗,事实也是这样 在常规的Web开发中,从控制器接收到请求命令之后可以执行一段逻辑,而在这段逻辑中我们可以设定符合相应逻辑的特定操作(其中一种常见的操作就是读写数据)之后把数据拼装成特定的形式返回给请求方 数据虽然可以存储在任何介质中,比如文本文件,可是文本文件太大了读写就会变慢,这时候我们就会想到按某种方式去分区存储(比如放在不同类型的文件夹、不同名称的文件)… 然后为了图读写方便,我们还要将文本中的每行都固定一个格式,跟咱们选的编程语言能相互搭配,快速转换成这个语言支持的变量… 你又感觉存硬盘里面读取太慢了,改成选择性保存到内存… 升级索引方式… 优化查找逻辑… 之后改改这改改那… 最后你就设计出来一个数据库 如何界定快慢 暂且认为快慢只取决于操作复杂度和传输大小。 数据库能干啥 现在已经有的成熟的数据库类型有很多种,能存储的数据也多种多样,包括表单、对象、纯文本、向量、图片… 其实有这样一种说法–“语言是逻辑的边界”,也就是说其实只要能存有序的二进制、或者文本,其实就能存一切…(如果你不理解,先想想密码学为什么存在) 之前我说过,一切能看见的功能其实都可以自己实现,一方面人类大脑具有相同或者相似的结构,别人能想到,你也能想到。另一方面,大家用的编程语言、工具啥的也是相同或相似的。 “没有最好只有最合适”,所以没必要什么都去手搓(让然手搓有时候也有自己的好处),已有的很多数据库已经做的很好了:效率高、可分离、优化好、稳定、成熟、暗病已被解决、省事、遇到问题有解决方案… 现有的数据库有:关系型数据库(通常使用 SQL作为交互指令)、缓存数据库、文档型数据库、键值型数据库、列式数据库、图数据库层次性数据库、面对对象数据库、时序数据库、向量数据库… 任何软件都有一套操作逻辑,数据库软件也一样。比如说常见的关系型数据库(PostgreSQL、MySQL、SQLServer、Oracle等),他们都是使用 SQL 去交互的(相似但不完全相同,但操作逻辑基本一致),换句话说就是这些数据库的制作者认为使用 SQL 操作(与其交互)这些种类软件是最合适的 外部运行一个软件再与其交互的好处有挺多的,比如可以分离进程、分离存储、分机器、便于灾备和负载均衡、兼容多语言… (而直接代码实现也有自己的好处),这个自己选最合适的方式就行 对于一种数据库要关注的点就是操作逻辑、增删改查、原子性保证(事务)、便捷优化方式(比如索引),如果你想非常在最大程度上优化就需要理解原理了(比如全查后过滤和同时条件查询的选择、SQL 语句嵌套顺序的选择) 快速理解一个数据库的操作逻辑的方法就是用一下,如果有可视化操作工具就更好了(例如 Navicat),一般使用不同编程语言去连接数据库的时候,我们会用数据库驱动连接(一般是官方提供的)、数据库中间件、ORM 等工具,甚至可以一句 SQL 也不写,按照编程语言的特性去调用被封装过的操作,这个杠杆加大了“理解远大于背诵” 可以通过可视化软件快速理表、字段、查询… 以SQL 的逻辑为例,基础操作可以理解为“【操作】(为操作目标服务的修饰)”,例如: insert into `user`(name, email, age) values (‘sdm’, ‘[email protected]’, 26) [修饰]; 是“【操作】(【目标】【来源】【修饰】)” select * from `user` where id < 10; 也是 “【操作】(【目标】【来源】【修饰】)” update `user` set age = 30 where name = ‘Alice’; 是“【操作】(【目标】【修饰】)“ delete from `user` where id = 5; 也是“【操作】(【目标】【修饰】)“ 整体感受上其实可以跟我们正常对语言理解中的“语言的逻辑”(主谓宾、定状补)非常相似。不过 SQL 是可以嵌套的这点有点不一样,无伤大雅。 ...
一、人类具有相同或相似的大脑,别人能想到(理解)你也能想到 这个观点来自知名UP主“底层原理/底层原理1988”的一期视频,我在考研那段时间我觉得是最宝贵的一个收获。 这个思维在开发领域也是一个有力的神器。 在调库开发的时候,我们常常见到“符合直觉”这个词。但其实我们会发现在一些比较火爆的库的使用中即便没写“符合直觉”,但用起来感觉还是会“符合直觉”,这并不是巧合,而是对这个思维的又一次认证。所以没必要畏惧任何复杂的库,都是人写的,都是人用的,库作者的理解甚至可能不如你。(看似废话)同理,如果你是编写库或者软件的那个人… 除了库,还有对开源项目复杂性的畏惧。开源项目其实五花八门的,也不一定是完全符合规范的,毕竟都是世界各地思维方式不用的网友贡献的。其实常见的问题就是俩,一个是跑起来(如果你想用还没发行版),一个是了解行文逻辑(你想改造)。不管哪方面,其实都需要相当大量的经验,可以说你的经验越多,顺利进行的概率就越大。主要是你积累这些经验的过程,而这个过程又是这个观点的利用… 如果你进入一个新的领域(或者是你牵头的领域),而又找不到一种规范(比如代码结构、操作逻辑),你可以依据在其他领域的经验(前提是你在其他方面有足够的理解和经验)直接写直接做,它将自动符合直觉… 要常常进行这样的追问,那第一个干这件事的人是怎么想的?以这个为基础问题不断追问… 二、比起死记硬背,大脑更容易记住的是逻辑 这是认知科学里非常确定的结论。这里我记得知名UP主“底层原理/底层原理1988”是通过脑科学(神经元、突触、神经网络)角度描述的,我认为人类曾经就是靠逻辑走向的自由世界。 之前我剪了一个视频”十分钟了解Web开发“,我有个朋友就跟我说没学过Python,看你视频是有门槛的。我想说–我想传播的是一种逻辑,而非某项技术本身,所以可以不基于任何编程语言,看就行了,了解了再去追问。 “摇头晃脑的念经,而不去思考”不会有任何收获。世界是物质的世界,不是说念经念咒就能变出来粮食和物品,如果可以,那资本家雇佣的将是祭司而不是工人,工厂里面将满是经文而不是生产资料。这就是一个最常见,并且最容易使用实用主义去验证的事实。那现在考虑“执念经”和“理解经文”之间差了哪些东西呢? 真理我不知道是什么,或许变或许不变,但我能掌握的只有那可以被验证的实用主义。 我举个例子,比如说让你背下来一段你不理解的话,你可能感觉这段话拗口晦涩,念一遍都费劲。但是通常一句话里面是由一个中心逻辑和一些配套的细节组成的,如果你具备这方面的知识,并理解这句话主体的意思和用词方法,你甚至可以自己编出来意思一样,用失真率很低的语言,并且是用自己的语言描述出来。 你可能不相信,我学习过三十多种的编程语言、脚本语言,接触过很多很多的框架和库,这一点你可以通过访问我的Github主页去验证。我第一次这样说的时候,很多人说你学的多但是你学的肯定不精。这里我想说的并不是我学的多,也不是学的精不精的问题。而是我在学第一种语言的时候就发现一种问题,就是不管是这门语言的原生功能还是库里带的功能,是不可能完全被”背诵“下来的,我记得十几年前我还做出种抄写语言官方文档的行为(抄写过iAPP俗语言和Ruby语言的文档),现在想来非常之愚蠢,就像是我提到过的“摇头晃脑的念经”,而不去理解其逻辑,而在学习了很多种语言以后,我发现其实他们其实是有共性的,而且这些逻辑是相通的。比如顺序执行、循环、条件判断、分包这些编程语言应有的基础功能,比如Web库应有哪些功能,文本处理库应该具备哪些功能,这些在学习一门新语言的时候主动去对应和验证是否都有其实就差不多了,拿来就用,或者说你具备了”在干中学“的能力。所以说没必要像我一下系统学习听说过的每一种编程语言,只要掌握编程的逻辑,一通百通… 逻辑虽然重要,但逻辑不是一切,这个自己悟。(如果因为过于强调逻辑而痛苦,你可以了解一下荣格,但非必要不要了解,估计也理解不了) 三、没有最好,只有最合适 在开发世界总会看见这样的论调:“xxx是最好的编程语言”、“xxx是最好的框架”。这些观点差点给我唬住。追问一下凭什么最好?是因为最合适,最合适就是最好。看似罗圈话,最合适比最好多的是”选择性“。 我说在技术选型上”没有最好,只有最合适“,这点其实是提醒各位要综合考量。我不拿编程举例子,我拿日常生活中的工具举例子。比如我的目的是将钉子锤进木板里面,这时候我有钳子、扳手、大锤子、小钉锤、皮锤,那我肯定选择小钉锤了。并且我会选型号、质量、趁手程度最好的那个钉锤。如果我只有一把钳子呢,钳子可以用来拔钉子,头部也是金属的,我可以利用这一点去锤钉子进木板,因为我只有一把钳子。同理,我只有一把扳手呢?我只有一把皮锤呢?皮锤也可以试着锤两下。而且如果我用的扳手的设计者考虑到了使用者会用来锤的设计,那更是不错了。 我说没有最好,只有最合适。很多人就直接会联想到,那我把我的工具箱装满,每种工具我都买一个(每种技术都学),这又回到上一点中我说的问题了。要掌握的是逻辑,要做到在问题导向下,没有锤子也要尽量找到考虑到用来锤的扳手,而且锤子这种东西存不存在还要另说呢。换句话说,即便互联网如此发达的今天,也没有任何一个人能知晓一切,就像那个无法填满的工具箱。在这个新的层面上看,一个人也不可能具有像佛陀那样的”无上正觉“(至少我没见过这样的人),没办法去理解一切事物的根本逻辑,也像那个无法填满的工具箱。以此类推… 四、是业务(具体需求)驱动,而非技术驱动,不必执着于技术 我也曾经这样考虑过–”先学会某种技术,之后我知道这些技术具体能做什么,之后在能做到的基础下去进行开发“这种想法。这其实是一种“必须由技术驱动业务”的本末倒置的想法,其实恰恰相反,而且一些独特的技术被创造出来以后,通常也是先变相创造了需求,之后再反向产生一种对技术的需要,这种形式的存在让我们产生“技术是最重要”的这种错觉。 许多本源的需求本身就存在,他们在没有计算机、软件、网络之前就存在了。技术里面操作细节也都是目的驱动的。最简单的,我想处理一段字符串,这个操作最终想拿到的那个存在变量中的数据肯是具有一定意义的,或许是给后续处理做准备,或许是更正了语意,或者是排版了格式。每一步操作都是有目的性的,所以做开发在原子上就是目的驱动的,小目的最终组成大目的(实际的需求)。 如果从技术的角度去看,学会无数种技术框架、规范、模板以后,不断的扩充自己能干什么,之后在这个前提下判断自己想干什么,这相当于把自己”困住了“。而且这与所谓创造性是相悖的行为(如果你需要创造性的话),也是一种敷衍。这是对已知的复用,不过也并非没有意义。 我建议的方式是先有需求驱动,之后再去找解决方法。如果是广为人知的需求,那么必然有成熟的解决办法。如果是小众需求,另想办法。如果你不理解我这句话,可以过几年再回来看一次。 技术革新很快。 五、独立思考,而非被牵动 从来不存在什么权威,信奉的应该是实用主义。甚至我在写篇博客的时候也不敢说这些逻辑对于读者完全适用,或者是永远是对的。如果你想了解一个东西,就去找那个最精纯的根源去了解…去读这个理论和做法真正来自哪本书…真正出处在哪…原作者是怎么说的,而不是找一个短视频解说一下就算了解了。因为语言会让思想(逻辑、想法)层层失真,你去最原本最精纯的地方看至少相对接近提出者的真正想法,这也只能说加大了你对作者真正想法理解的概率。 如果你没有时间,那至少要从实用主义的角度去验证。 不存在什么权威,每个人有自己的观点,甚至他们在同一个学派或圈子。 因为专业的营销、心理学策略、固有思维等等因素,出现了很多“二极管”(单向导通)思维,什么什么就是好,什么什么就是坏。但是现实呢,一切事物都是多元的。如果说每个事物都有属性的标识,这个属性可以说是有无穷大条。中国古典哲学的核心之一的“太极”也是破除二元论的重要依据,不能只看静态结果,不看条件、过程、关系等等多方面因素。你可以用中国古代“太极无限可分”、“万事万物皆太极”这样的思考角度去理解。 学会独立思考,不能人云亦云。(尽量) 六、允许争论,永不固步自封 在任何哲学(爱智慧)学派的历史上,永远是允许存在争论的,如果人家的思想比你好要做的只有学习。我感觉这条“允许争论”在技术领域依旧适用于我所说的第三条和第四条。 就拿最近比较火爆的 Agent 编程来说,对我来说可是亏大了。我之前熬过无数的夜,付出过无数的时间和精力去学习了解各种技术的细节,写Demo(我为了忘了细节的时候回去看),可是我考研回来继续写代码的时候突然有个朋友告诉我Agent可以直接替我写代码了,而且 AI 知道不可估量的信息,甚至还能自己检索,当时买了各种的计划、尝试各种模型,当时感觉不太行其实。不过半年过去的现现在我确实服了,真的能一定程度上做到又快又好了,反正我不可能五分钟完成一个模块的设计、编码。而且我发现了一个现象,技术一如既往的更新的很快,而且在 AI 这个杠杆下变得更快了,变得人力所不能及了。 Agent 编程确实方便了,但是也存在很多争论。有的人对 AI 编程嗤之以鼻,见到就骂,有的人对 AI 过分推崇,夸大宣传。而现实呢,只能说你自己用用!我的评价是有的确实好用。 至少从实用主义出发自己判断。 如果你还愿意拥抱技术,必须不断的更新自己。 你如果看到这里,欢迎跟我讨论一下,感激不尽。
视频 https://v.douyin.com/ANHZlk08v0Q/ 说明 Web 开发几乎渗透了现代数字生活的所有层面。从简单的信息展示到复杂的工业控制系统,只要是需要网络访问、跨设备、免安装的场景,都是 Web 开发的领域。(新手如果还不知道是干啥的需要继续看一下,很快就能懂!) 从Python的flask入手 Flask 是 Python 语言下一种相对简单便捷的 Web 开发框架,相当适合入门 Web 开发(简单的操作中获得完整的理解)、敏捷测试接口开发(快速启动可用接口、快速实现开发) 我将使用这个简单的Web开发框架作为Web开发入门快速带你入门Web 开发领域,并且马上可以实现简单后端项目,立刻理解Web后端开发中的诸多术语和开发模式 在这些教程中我因为压缩时长的原因,很多东西的细节(可能被认为是废话)的部分会被选择性跳过,比如传输协议,网络端口啥的这些都暂且不提了,您可以持续关注我的频道来更全面的了解其他开发知识,这样做还有个好处!就是想不起来的时候可以直接搜一下独立的知识点,快速解决遗忘问题 术语 Web API:网站的后台接口。API 通常返回JSON形式的数据(返回形式多种多样,包括 html 页面)。 路由:URL 和处理函数的"接线员"。比如把 /user/123 这个地址接到 get_user() 函数上,用户访问这个链接就执行对应代码 请求头:请求头是类HTTP请求中附加在主体内容之前的元数据区域, Restful API:一种设计规范。用不同的 HTTP 方法表示不同操作:GET 获取、POST 创建、PUT 修改、DELETE 删除等(按语义区分),类似对资源的增删改查 视图:Flask 里处理请求的函数。接收浏览器发来的数据,处理业务逻辑,最后返回结果(可以是文字、JSON 或网页)。 上下文:Flask 给每个请求创建的"临时工作台"。上面放着当前请求的数据(比如用户登录信息、表单参数),你在视图函数里随时能取出来用。 模板:带占位符的 HTML 文件(如 hello {{ name }})。视图函数把数据填进模板,生成最终网页发给浏览器,实现前端展示和后端逻辑的分离。 JSON:一种常见的文本数据格式(像 Python 字典的字符串版)。{"name": "张三", "age": 20},前后端通信用它交换数据,Flask 用 jsonify() 直接可以返回。 前后端分离:这个词其实本身有很多渊源(但这里秉着减少废话的原则),但是现在你可以理解前端和后端”不同源、分离“就是他俩运行在两个不同的程序中,这种情况下通常为了安全而需要进行跨越配置(前端通常指用户面向的视图那边,后端通常代表后台逻辑那边) 要素 返回结果:准确来说可以是任何允许的形式,而不仅是返回 JSON、网页等这种数据 接收请求参数:请求发起方会携带一些各种形式的参数(query、请求体、表单…) 模板:页面中嵌入一些专门准备被替换的标签,之后被代码中定义的数据填充 跨域问题:前后端服务非同源的时候,跨服务的请求会触发跨域安全机制,需要配置一下来允许请求 相关资料 https://github.com/pallets/flask https://flask.palletsprojects.com/en/stable/ 本次讲解代码 本人2022年讲解版本 《Flask Web 开发》(狗书)-【美】Miguel Grinberg
视频教程 https://v.douyin.com/bHdcmkaVSFI/ 问题导向 很多的 Python 依赖(轮子)版本是相耦合的,但是系统总体的 Python 环境是唯一的,如果想运行不同依赖版本下的项目代码,就需要重复性的卸载和删除这些库 有时候单纯的想试一下某个轮子,但是还担心安装之后卸载不干净 一些 Python 环境是不带包管理器 pip 的,例如单纯的 cPython 解决方案 针对依赖关系,使用虚拟环境 针对没有 pip 的情况,使用 Python 环境变量,或者自己补个 pip Conda是这样 创建完全隔离的运行环境,还能装 C/C++、R、CUDA、MKL、FFmpeg 等非 Python 二进制 安装前先计算整体依赖闭包,发现冲突会拒绝执行 体积大、启动慢,但是完全独立,就是不要求 conda 环境外部的系统环境有 Python conda create -n env、conda install xxx UV 能做到 快速创建虚拟环境,管理依赖 直接补 pip,在虚拟环境随便用 轻量、块,安装轻量、用起来快 UV有哪些操作 uv venv 创建虚拟环境,可以直接在虚拟环境下使用传统的requirements文件和基本的 pip 操作直接用 uv init myproj 创建标准的 uv 项目骨架 UV 基本项目骨架 uv init myproj # 生成 # myproj/ # ├── .python-version (可选,pin 3.11 等) # ├── pyproject.toml 项目元数据+依赖 # ├── README.md # ├── .gitignore # └── src/ # └── myproj/ # └── __init__.py uv add xxx 在UV项目中添加依赖 ...
之前的一篇文章中,我们探讨了不同编程语言之间的交互方式,当然那篇技术分享文章已经是三年前的了。最近接触了更多关于这方面的东西,就比如Docker和Containerd之间交互所用到的Unix Socket、RPC其实可以有更多巧妙应用,甚至作为用户界面。当然这次跟这个也是有关系的,本期的文章我主要想探讨的问题是所谓评判程序优秀程度时朗朗上口的两个指标“高内聚低耦合”,这是一个软件工程学中的概念,“内聚性”使得模块更加独立,“低耦合”使得模块之间的关系减弱。通常我们使用编程语言的一些特性还有巧妙的设计模式增强内聚、降低耦合。从而使得代码易于维护和重用,但这并不是强制的。这期我要说一些思路,但并不是所谓银弹,也就是说这个方案并不是一个万能钥匙,不过追求易于维护和职责分离的时候走投无路了,可以试一试我说的这些方案。 首先我说一个背景,假如说一个操作系统没有内置进程管理器,我们要做一个进程管理器,职责就是管理系统进程(类似systemd)。首先我们就会想到参考systemd对吧,先不说他的CLI 界面,就是这个模式来说,systemctl本身功能就是管理进程相关的,这个不会受外界影响,那它管理的进程功能应用呢?细想一下,是不是systemd 对业务进程是一种“一厢情愿”的超低耦合!那加入我们自己想做一个进程管理器,你会怎么做,难道直接将运行的业务内置进进程管理器?不过也不是不可以,看这个业务架构需要的细分程度,不过我们当然还是追求一定的通用性。现在我们讨论一种架构较为庞大,且各部分需要复用或可能需要复用,并且不同层次的服务都可能被直接或间接调用。 再来看systemd的CLI,就是我们常用的systemctl命令,它跟systemd之间呢?容易发现systemctl 与 systemd 之间是“进程隔离 + 文本协议(D-Bus)”的松耦合,就像Docker跟Containerd之间是用Unix Socket发送grpc消息一样。他们的共性就是-“进程隔离”,而根据我之前的文章,进程之间是有很多通信方式的,甚至可以跨设备、跨编程语言、跨服务。所以说在这个“颗粒度”的“隔离”是可行的,并且有效的增强高内聚低耦合的手段。 我认为低耦合的技巧在于“隔离”,恰当的软件隔离还是硬件隔离都可以实现一定程度的解耦合,得益于硬件接口和软件消息的多样性、可转换、规范性,我们可以非常方便的让各个部分各司其职,实现低耦合和复用。硬件层面,比如我有多台服务器,每一台对应着不同的服务,就像现在有的洗衣机专门分出来一个洗衣桶专门洗内衣、专门洗袜子。软件方面,进程隔离、类隔离、线程隔离都是非常常见的。但其实还有一种方式,电热毯是用来暖被窝的,热水壶就是用来烧水的,但是根本上都是电热原理,电热原理跟这里两种使用方法之间也是松耦合,这是一种原理与用途的解耦,这种机制把底层通用原理/机制与上层具体应用/场景分离开来,让同一个原理可以灵活地适配多种用途,而不被某一用途“绑死”。这第三种方式也揭示了一种新的思维,暂且我把“底层机制+中间抽象”称为“原子能力”,而原子能力可以支撑的叫“上层应用”,就像我刚才说的“电热原理”就是一种“原子能力”,“电热毯”和“热水壶”就是“上层应用”。 上面, 我对“原子能力”的定义中包含了“中间抽象”,其实“原子能力”本身也是可以分层整合成新的“原子能力”,这个衍生能力也很重要,这个一会说。我继续补充一个说法,这是一个一句话的设计原则,“不要让你的底层机制知道它在做什么业务”。如果我们要做的是实践,它是一种知识的整合体加上层封装,而这些理论知识必须对应来自几本书籍的话,这些书籍就是所谓“原子能力”,那么如果有一个图书馆呢?图书馆不是“书的堆积”,而是“知识的操作系统”。原子能力本身可以分层、整合、衍生出新的“原子能力”。 前提知识引入好了!现在你已经了解了软件和硬件“隔离解耦“和我的第三方法“机制与策略分离解耦”,现在你可以看这张表了。 维度 实现抓手(举例) 一句话记忆 1. 空间隔离 进程、容器、VM、沙箱、不同微服务、不同机柜、不同芯片 不在同一地址空间,就别想直接牵手。 2. 时间隔离 消息队列、事件溯源、CQRS、批处理窗口、断点续传 错开时间,自然不见面。 3. 协议/格式解耦 统一 IDL(Protobuf/Avro)、自描述消息(CloudEvents)、转码网关 语言不通,带个翻译。 4. 语义层解耦 原子能力图书馆、机制-策略分离、DSL→引擎→执行 只给说明书,不给故事书。 5. 依赖方向反转 DIP + IoC/DI、OSGi/Jigsaw SPI、插件化、Spring Factories 别来找我,我去找你。 6. 数据访问解耦 读写分离、事件存储 + 投影、数据虚拟化、Polyglot DB 数据长在一起,用法各自开花。 7. 版本解耦 并行版本、灰度路由、Feature Flag、Sidecar 代理兼容老协议 新老同堂,各走各门。 8. 组织解耦 康威逆运用:用架构反向约束团队边界、平台 + 业务双速团队 代码怎么拆,团队就怎么坐。 9. 治理解耦 服务网格( traffic / policy / security 三军分立)、策略引擎 OPA 流量、安全、观察,三权分立。 10. 资源解耦 Serverless/BaaS、弹性池、GPU/FPGA 资源抽象、统一调度层 谁用谁拿,用完即还。 11. 失败/重试解耦 断路器、舱壁、异步重试队列、幂等键、Saga 补偿 出错别连环,炸不到邻居。 12. 性能解耦 背压流控、批量聚合、缓存分层、CDN 边缘卸载 快慢分流,别让慢拖死快。 13. 安全解耦 零信任网络、mTLS 即服务、身份与业务逻辑分层(SPIFFE ID) 先验身份,再谈业务。 14. 硬件解耦 总线标准(PCIe)、即插即用固件、SerDes 通道抽象、Chiplet 管脚对齐,内部随便换。 15. 生命周期解耦 GitOps + 不可变基础设施、蓝绿/金丝雀发布、回滚与数据迁移脚本分离 生归生,死归死,生死不互卡。 你可能从前在哪看到过这张表,确实在一些书记上有想通或相似的说法和列举,但是你可能会看的一头雾水,不知所云。不过当你理解了我上面说的几种基本解耦方式以后,只要抓住你这几条“元思维”,表里的任何招式都能瞬间归类: ...
一、前言 我们学过C、Java、Python、Golang、Ruby…等等高级语言,它们都有自己的优点、特性、语法。你是否想过诸如这样的问题:这些高级语言之间有什么关系、有什么共性、如何只发挥自身优势规避劣势、如何相互协调合作、如何互相通信呢? 本文主要讲述的是不同编程语言之间如何通信(同语言不同服务器间依然适用),从而渐渐解释上面提到的一系列问题。 有的同学看到这里可能就要翻走了,觉得这篇文章要说的这个东西不就是分布式吗,这东西咱早会了,玩的肯定比你溜…但是!我要说并不只是分布式,而是本质上的东西,分布式只是其中的一种实现方式,还请您看我细细道来。 其实我们在日常使用计算机的过程中,非常常见的,就已经在使用不同编程语言相互协调合作相互通信的机制了,举几个最直观的例子:Docker是使用Go语言编写的,但是我们在Docker容器中可以使用Python、Ruby、Java等语言编写的程序、Java编译器最初是使用C语言编写的、Java虚拟机HotSpot是用C++语言编写的、消息队列支持不同编程语言之间通信、项目中不同服务之间相互请求… 这样做的好处显而易见:方便开发、方便跨平台、方便分配性能… 咋回事呢?我这里提出两个四字词语作为关键词:协调合作、共同语言 二、思路 日常生活中,我们人类之间的交流方式多种多样,语言、肢体语言、书面文字、手机发消息、视频通话…这些都是我们人类之间的通信方式,但是我们并不是每一种通信方式都会使用,而是根据场景、目的、效率等因素来选择合适的通信方式。 这些交流方式要分类的话,可以通过层面进行分类为:书面、口头、视觉、电子介质…。同理,在计算机程序上,也有很多的交互层面,比如:内存层面、变量作用域层面、网络层面、文件层面、进程层面、线程层面、硬件层面…。我们可以通过这些层面来进行分类和组合,然后再根据场景、目的、效率等因素来选择合适的通信合作方式。 在同一个层面下,不同的编程语言或不同的程序之间的协作要么依靠协调合作,要么依靠共同语言。说白了就是约定好合作方式,然后按照约定的方式进行合作。协调合作比如多个程序之间处理各自部分(各系统之间可以没有请求关系)使得最终的结果是预期的结果。共同语言比如:Java程序和Python程序之间的通信,可以通过约定好的文件格式、网络协议、内存格式、序列化方式等方式进行通信。 三、实现例子 以人肉为媒介(客观世界层面、通过协调合作和共同语言):顾名思义,直接让人用眼睛看,再录入!这个方法虽然正常人都能想到,但是我还是要写一下!人能做的事情其实随着技术发展,机器将来也可以做!因此可以联想到:OCR、自动化脚本、AI… 以系统控制台为媒介(操作系统层面、通过共同语言交互):如果您平时使用的操作系统是Windows,其实很容易想到,只要拿到一个命令行窗口,就可以对电脑做几乎任何操作,包括应用程序的启动、关闭、文件的读写、网络的请求等等。那么编程语言可以拿到命令行吗?答案是肯定的。并且只要编程语言可以调用操作系统的API(大多数编程语言都支持),拿到命令行,然后就可以对电脑做任何操作了。借助这一特性,我们可以在不同编程语言之间进行通信合作,比如:Python调用操作系统API拿到命令行,然后执行Java程序,Java程序执行完毕后,将结果返回给Python程序,Python程序再将结果返回给用户。这样就实现了Python和Java之间的通信合作。反之亦然。 Java代码 Python代码 运行结果 以文件系统为媒介(文件层面、通过共同语言交互):一般我们常见的操作系统都具有文件管理的功能。恰巧的是,高级语言中一般也都有编辑文件使用的库,我们可以直接通过编程语言对系统中的文件和文件夹进行读写操作,并且文件的内容(就是不同编程语言之间交互用到的共同语言)由我们开发者来自己规定。这里我举一个小例子,首先我们在系统上有一个公共可以访问的文本文档,在Java程序中我们封装了一个工具类专门用来读写文本文件的最后几行(要执行的命令),Python之中我们也是通过调用文件操作来实现文件读写。并且我们规定文件的每一行都是一条指令,使用,分割当条指令的各部分,并且我将每一条指令分为三部分,第一部分是指令,第二部分是参数(如果是多参数就可以用特定符号分割,如果各部分之间的分隔符与参数冲突可以通过固定指令和是否被执行完参数的长度来控制),第三部分是指令是否被执行完(也就是说,用户可以同时发布多条指令)。 Java代码 Python代码 执行效果 以时间分片为媒介(客观世界层面、通过协调合作交互):时间分片这个事情其实并不用多说什么,理解起来也容易。我们常将时间比作一条线,叫做时间线,这种方式的介绍也由此展开介绍。在时间线上发生的事件有这几种关系:交替、并行、半交替半并行等,总之就是可以一起执行,可以分开执行。一起执行的话(后两种)想要在各个服务程序中想要通信,这种方法只适用于部分场景(取决于选择的长期纯粹介质),这条例子中主要说的是交替执行。按时间分片交替执行其实是我们最直观的相同编程语言、不编程语言之间交互的方式,这种方式的精髓在于一个程序执行完成之后,必然会通过长期存储介质将信息保存(可以是纸带、文件、二进制流、图片等),之后下一个时间片中的程序再去约定好的地方将上一个程序传递过来的信息读取解析,然后再根据信息执行自己的任务,之后再通过长期存储介质将自己想传递出去的信息传递回去…我们常见的使用这种方式的地方就是在网关分布式程序(就是通过网关实现一系列执行同样业务的服务器的负载均衡等操作)中使用到的Redis共享Session,在这种模式下就属于以时间片为媒介的同种高级语言(可以不同种)交替执行。在同一个时间线上,一个请求打到网关上的时候,会经过负载均衡机制将请求分给网关下面的单台服务器,这些服务器因为是使用的共享的数据源,所以用户端看起来就是一台服务器(不会出现数据偏差)。 以语言中间件(工具库)为媒介(框架层面、通过共同语言):其实很多编程语言都有直接调用其他编程语言代码的库(这些库的底层原理可能是走的其他交互方式,但是我在这个层面介绍这些),比如Matlab能调用Python代码、Python也能调用Matlab的代码调用的分别都是自身语言下的库或和其他语言功能、比如在Python中使用Jpype调用Java程序… Python调用Matlab Python调库运行Java代码 以消息队列为媒介(框架层面、通过共同语言):不管消息队列是现成的还是自己实现的,不管它有多少高级又神奇的功能,本质上,能实现通信合作的原因就是这一个!传递的是字符串!一般使用消息中间件的情况下,消息是先从程序发送到消息队列中间件,之后经过消息队列中间件(可以有逻辑或规则)被其他程序(可以是相同语言或不同语言实现的)调库获得消息信息并处理。 以网络请求为媒介(网络层面、通过共同语言):这个方法是最常见的了!比如我们自己写的普通BS和CS结构的程序就一直在用!我一说您可能就会明白。首先后端程序语言就很多样,其次前端程序语言也有很多选择!没看懂?那再换个说法,假如说后端用Java、前端用三件套(HTML+CSS+JS),是不是!不同编程语言合作了!这种合作是通过请求API实现的,后端暴露特定请求可访问的API,前端向这些API按约定的方式发起请求。现在比较火爆的分布式技术(简单说就是服务器之间可以相互发请求、实现协作、实现负载均衡,有时是直接发请求、有时是通过RPC实现)就是这个原理。分布式中的这种合作也是通过暴露API或者使用RPC(远程过程调用)的形式直接调用其他后端程序中的方法。这里举个例子,在我的这个开源文件管理项目中我是用到Python语言作为功能支撑(方便好写),Java语言作为核心支撑(稳定性强)。可以看到,我这里在Python后端使用FastApi提供Get请求接口,在Java后端使用SpringBoot-Web中提供的RestTemplate调用Python提供的,这样就实现了Python和Java之间的通信合作,并且如果我们使用网关的话,这种结构可以实现水平拓展性能的负载均衡。再举个其他冷门搭配的例子,在我另一个开源项目中,使Golang去调用硬件芯片上提供的API(用C编写的),这样就实现了Golang和硬件芯片之间的通信合作。 分布式实现的文件管理项目中Java调用Python代码片段(main.py、FileAndFolderUtil.java) 绿植管理项目中Golang调用硬件上C提供的API代码片段(GreenBeltGoRun.go) 四、难点 五、看代码 控制台交互Python:查看 控制台交互Java:查看 通过文件交互Java:查看 通过文件交互Python:查看 通过文件交互用的文件:查看 Jpype:查看 测试Jpype用的Java代码:查看 测试Jpype用的Jar包:查看 测试Jpype用的Python代码:查看 分布式实现的文件管理项目:查看 分布式绿植管理项目:查看 六、总结 不同编程语言相互调用,其实是我们经常使用的开发模式。但是这种模式带来的便利往往被我们忽略掉。日常开发中经常会遇到通过这种方式可以便捷解决的需求,这种方式能够很有效的避免代码完全重构、跨语言扒库等等问题。 感谢您能耐心看完这篇文章,如果有什么问题,欢迎在评论区留言,我会尽快回复。 如果您觉得写的还不错,欢迎关注、点赞、分享、订阅、Star,您的点赞是我写作的动力。