1. 前言 之前看到 M1 芯片出来之后,就想说些什么,结果光写 x86 和 ARM 就写了 4000 多字,考虑到文章篇幅,只得分为上下两篇,上一篇文章发出后有很多人表示非常喜欢,让我赶紧更新,在这里向支持我的读者们表示感谢 🙏。
那么话不多说,这篇我们来聊一聊,这次的芯片到底有何不同,以至于让那么多人说苹果不讲武德。
在这之前我先说明,我只是一个计算机专业的学生,从来就没有自诩自己是什么专家学者,我写博客也只是为了做一些简单的科普,把自己知道的一些知识分享给大家。如果文章中有什么错误的地方,还请各位读者指正。
2. M1 芯片 ≠ CPU 首先,我们要先摆脱一个认知误区,M1 芯片不是一块 CPU,而是一块专为 Mac 设计的 SoC 芯片。CPU 只是 M1 芯片的一个组成部分。
所谓 SoC 芯片,指的是系统级芯片(System on Chip),也称片上芯片,是一个将电脑或其他电子系统集成到单一芯片的集成电路。 SoC 集成的主要包括处理器(CPU,GPU 等)、基带、各种接口控制模块、各种互联总线等,其典型代表为手机芯片。举个例子,CPU 公司将自己的所生产的 CPU 设计卖给其他公司,而其他公司就根据该 CPU 自己添加上所需要的各种外设控制器,这就是 SoC。
所以简单来说:SoC 就是一块集成了 CPU、GPU 等多种结构的芯片。因此,千万不要简单的认为 M1 芯片就是 CPU。
官网有一张图,就很好地说明了 M1 芯片的组成成分。如下图所示,苹果称其为统一内存架构(Unified memory architechture),即通过 Fabric 高速总线将中央处理器、图形处理器、神经网络引擎、缓存、DRAM 内存全部连接在一起。因此,M1 芯片的强大,绝不是靠一个强悍的 CPU 支撑的,而是众多性能强大的部件结合苹果优秀的设计共同努力的成果。
3. 统一内存架构(UMA) 通过上一段内容,我们知道了 M1 芯片的强大光靠一颗强大的 CPU 是不够的,毕竟苹果也没办法突破物理定律,单纯通过设计让 CPU 的性能提升数倍。很明显苹果采用了其他的技巧来弯道超车,而**「统一内存架构」**就是其中之一。...
M1 暴打 Intel?——x86 与 ARM 的爱恨情仇
最近这段时间数码圈里最火的莫过于苹果最新推出的三款基于自研芯片 M1 的电脑了,分别是 MacBook Air、13 寸的 MacBook Pro 以及 Mac Mini。其热度也是久居不下,哪怕距离发布会已经过去 10 多天了,却仍然能看见各种评测视频、文章层出不穷。在一些平台搜索 MacBook M1 的相关视频、文章,无一例外都是:Apple 真香、性能起飞、虐杀英特尔等等这类词汇。 最近新出的拆解视频我也有看了一些,可以发现其实新出的 Mac 在模具方面和前几年相比没有什么太大的变化,最大的亮点在于便是其自研的 ARM 芯片 M1 了。
此次的 M1 芯片的出现,带火了另一个名词,ARM 架构。同时也让一个探讨许久的问题又重新浮出水面:ARM 芯片真的会超越 x86 芯片吗?
本文先不探讨 M1 芯片的设计思路,先来认识学习下两个经常听见但有可能并不太清楚的名词:ARM 与 x86。
ARM 与 x86 随着信息技术的普及,在现在,相信你随便找一个人问他知不知道 CPU 是什么,我想他的答案都会是肯定的。但如果你再问他,知道 CPU 的 x86 架构和 ARM 架构吗,我想一些计算机专业的同学可能都不会太清楚,因此在谈此次苹果的 M1 芯片之前,我们先来聊一聊 ARM 与 x86。
时下「打工人」这个名词很火,而 CPU 就是整个计算机中最勤劳且最核心的打工人。x86 和 ARM 便是 CPU 中两种不同类型的打工人,这两种架构很大一个区别就是指令集。
架构?指令集? 看到这里你是不是很疑惑,架构到底是什么?指令集又是什么?别急,我们还是以打工人为例,将 CPU 代入该角色来说明。
事实上,CPU 做的事情很简单也最核心,简单来说就是接收指令+运算。CPU 和千千万打工人一样,首先要有正常的工作能力(即执行能力/运算能力),然后又有足够的逻辑能力(能明白做事的顺序),最后还要有一定的理解能力,能听懂别人的话(即指令集),才能正常工作。而把这些集中在一起就构成了所谓的「架构」。你可以将「架构」理解为一套**“工具”、“方法”和“规范”的集合**。...
互联网是如何工作的?
前言 我们每天都在使用网络,面对这个看不见也摸不着的东西,你有没有思考过他的背后发生了什么吗?
相信很多人第一次接触网络是通过一个叫「网站」的东西,那网站又究竟是什么?
影视剧里经过出现的通过 IP 地址获取定位,是真的可以实现吗?
相信你在阅读本文后就会有一个清晰的认知了。
网站?服务器?网络? 首先我们要理解的是,一个网站只是一堆保存在硬盘上的文件, 就像你的电影、 音乐或图片一样。 然而,网站的唯一的不同之处是: 网站包含一种称为 HTML 的代码。也正是这个叫 HTML 的东西让网站有了好看的皮肤(界面)。
如果你对编程不熟悉,一开始你会很难理解 HTML,因为 HTML 其实是让你的浏览器(Chrome、Safrai、FireFox、IE 等)去**“理解”**的信息,浏览器读得懂这些代码,然后会按照代码的内容展示这些文件。
就和我们对待自己的电脑文件一样,我们会把 HTML 文件存储在硬盘的某个位置, 然后通过浏览器去访问这些 HTML 文件。对于互联网,我们使用特定而功能强大的电脑,我们称之为服务器,所以其实服务器本质上也是一台电脑,它们没有屏幕、鼠标或者键盘,因为它们的主要目的是存储数据,并用它来提供服务。 这就是为什么它们被称作服务器的原因——因为他们用数据服务你。
因此如果想要存储更多的信息,我们有两种解决方案:
增加服务器的容量 增加服务器的数量 显而易见的,一台服务器可以存储的信息是有限的,哪怕是不断增加一台机器的容量也肯定是有上限的。所以,我们可以通过第二种方式以达到**「量变产生质变」**的效果。
于是,一台又一台的服务器通过“网线”连接在了一起,形成了类似下面这样的结构
众多服务器组成的这种结构被称为“互联网”,而其中每台服务器都被称作“节点”,所以「顺着网线来打你」是有理论依据的。
IP 地址?域名? 那么紧接着,问题就来了。
既然网络是用来存储文件的,对于我这个初次上网的人,我又如何找到我想要的内容呢?
不着急,我们先来设想一个场景。
闰土家里有几套房子,其中房子 A 被闰土爸妈当作仓库了,一天,妈妈让闰土去房子 A 拿一个家传的盒子 X,说是给未来儿媳妇准备的,房子 A 在 a 市 b 区 c 小区 d 号,并给了侧门钥匙,让他从侧门 C 进去拿,盒子 X 在房子 A 的 2 楼的房间 B 里的衣柜。...
想追女神?先学 Synchronized 吧
在之前的《从找对象到多线程》一文中我曾介绍了一些和多线程有关的知识,而谈到多线程,就一定离不开「锁」这个名词。在 Java 中,锁的使用主要有两种:Synchronized 关键字和 Lock 接口,本文将会换个角度来聊一聊 synchronized 中的锁。
Synchronized 用的锁是存在对象头里的,用来表明当前对象所持有的锁。在 Java SE1.6 之前,Synchronized 是作为重量锁出现的,一旦使用了 synchronized,就一定会阻塞到其他线程。而在 Java SE1.6 后,为了减少获得锁和释放锁带来的性能问题,引入了"偏向锁"和"轻量锁"的概念。由此可以得知,在新的 Java 中,锁一共有 4 种状态:无锁状态、偏向锁状态、轻量锁状态和重量锁状态。这几个状态会随着竞争不断升级且只能升级不能降级,即轻量锁只会升级到重量锁而不会降级到偏向锁。
以上的解释未免太过官方了,我们从一个小例子入手。
我们用女神来表示同步代码块,就好比女神有很多追求者,同步代码块也会被很多线程执行。有一天女神的微博状态变成了「单身」,此时她就处于无锁状态,于是这些追求者纷纷创建了一个名为**「找对象」的线程**,此时对于女神(对象)来说,还没有任何线程来访问她,所以当第一个男生小 A 试图邀请她看电影的时候**(获取锁)**,她会偏向小 A 的邀请,此时她就是处于「偏向锁」状态的。有了这次经历之后,小 A 就知道该怎么邀请女神而不用反复试探了,这就是「可重入锁」,即同一个线程可以多次访问同一代码块。
再后来女神发了一条微博,说今天和这个男生看电影很开心。这条微博被其他男生看见了,大家也都知道了女神这个对象的偏向状态了。可还是有男生小 B 想追女神,此时这两个男生各自「找对象」的线程就在女神这个对象上产生了竞争。
小 B 一直关注女神的微博动态,他心想着,只要小 A 被女神拒绝了,女神就会变成「无锁」状态,自己也就有机会被女神偏向了。女神也知道小 B 在追自己,为了找到最合适的另一半,女神也在暗中观察小 B,有两个竞争者同时竞争,这时候她就处于**「轻量锁」的状态。虽然女神明显更喜欢小 A,但在小 B 心里觉得小 A 除了比自己早点出现外根本不具有和自己竞争的能力,于是不断给女神献殷勤,保持关系,这就叫自旋,**不断的将自己的时间花费在获取锁上,逐渐成为一条舔 🐶。
虽然一开始女神也会偶尔答应小 B 的邀请,但当竞争者越来越多后,小 B 变得疯狂起来,追求逐渐变成了骚扰,女神也逐渐不耐烦起来。最终在小 A 的努力下,女神和小 A 确定了关系,并发了微博告知众人,此时她的状态就升级成为**「重量锁」状态**。这时,除了小 A,其他所有竞争者的「找对象」线程都没有办法再追求女神了。这样做的好处就是赶紧断了那些追求者的念头,让他们可以早日觅得其他良人,不要在一棵树上吊死。
从线程的角度来看,重量锁使除了拥有锁的线程外的其他所有线程都阻塞,这样可以有效防止 CPU 空转,避免造成资源的浪费。
在偏向锁和轻量锁阶段,女神还没有和任何人确定关系,只要给点甜头小 B 等其他追求者都会很开心,这是一种「乐观锁」。而一旦女神和小 A 确定了关系,自身状态升级为重量锁后,小 B 就很不开心了,对他来说这就是一种「悲观锁」。...
接口调度者—— API 网关
背景 我们知道在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的服务他们自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些小系统通常以提供 Rest Api 风格的接口来被 H5, Android, IOS 以及第三方应用程序调用。
在《浅入浅出消息队列》这一篇文章中,我提到了消息队列是方便服务与服务之间的通信解耦,如下图所示:
那么这时候问题来了,如果一个外部的应用(浏览器、App)要去访问这个大应用怎么办?
很简单啊,直接通过 HTTP 请求不就完了?
问题 真的这么简单吗?我们以淘宝的商品详情页为例:
如上图所示,这个页面包含了视频、库存、商品价格、商品评价等内容,这些数据都来自不同的微服务中,所以没办法像传统单体应用一样依靠数据库的 join 查询来得到最终结果,因此就需要多次调用以检索数据,如下图所示: 这就会引发几个严重的问题:
不同的客户端设备可能需要不同的数据。Web,H5,APP,需要单独写一套 API 多次客户端请求导致用户体验不佳。移动网络相较于服务于服务间的局域网,有更低的带宽和更高的延时,如果可以同时执行请求倒也还好,但如果客户端要按照顺序执行请求,就会让用户体验变得异常糟糕。 缺乏封装导致前后端不协调。过分的拆分 API,会导致客户端和服务端过度耦合,再加上移动端 APP 的新版本迭代到每个手机用户时需要很久,这样会使后端很难更改服务的 API。 这样显然是不好的设计,因此,本期的“天降猛男”就出现了——API 网关。
API 网关 在介绍 API 网关前,我们先来介绍一个设计模式——外观模式。
外观模式(Facade Pattern)它向现有的系统添加一个接口,来隐藏系统的复杂性。类图如下所示:
之所以要在说 API 网关前说一下外观模式,是因为二者的设计理念是类似的。
和外观模式类似,API 网关封装了应用程序的内部架构,并为其客户端提供 API,他还可能具有其他职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。下图展示了客户端、API 网关和服务之间的关系。
所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。其出现也是侧面贯彻了软件工程中**“高内聚,低耦合”**的思想。
核心作用 API 网关负责请求路由、API 组合和协议转换。来自外部客户端的所有 API 请求首先会先转到 API 网关,后者再将请求路由到相应的服务。API 网关使用 API 组合模式处理其他请求,调用多个服务并聚合结果。同时他还可以在客户端友好的协议(例如 HTTP)与客户端不友好的协议之间进行转换。
请求路由 当 API 网关收到请求时,随机会查询路由映射,该映射将指定请求路由到哪个服务。例如,路由映射可以将 HTTP 方法和路径映射到服务的 HTTP URL,这一点和 Nginx 提供的反向代理的功能是一样的,后面我们也会对其进行一个比较。...
你的系统可用性 5 个 9 了吗?
又是一年放榜日,众多考生满怀期待的点开招生网,结果输了信息才发现根本没办法查询——查询人数太多了,直接把系统打挂了!
这个时候,还没翻身的码农闰土被问到一个直击心灵的问题:这个系统可用性达到了多少个 9?
想要回答这个问题,我们得先有些前置知识。
可用性&可靠性 这两个词很相似,我也一直找不到一个很好的定义区分这两个词,直到后来在看分布式系统的时候,看到了一个解释:
可用性被定义为系统的一个属性,它说明系统已准备好,马上就可以使用。换句话说,高度可用的系统在任何给定的时刻都能及时地工作。 可靠性是指系统可以无故障地持续运行,是一个持续的状态。与可用性相反,可靠性是根据时间段而不是任何时刻来进行定义的。
举个例子,想要评估一个舔 🐶,可用性就是你找他的时候能不能找到,而可靠性就是你需要花钱的时候他出手大不大方。一个舔 🐶 如果随叫随到,但是花钱太抠,就是高可用、低可靠;而如果他经常找不到人,但出手很大方,就是低可用、高可靠。
类比到系统时,如果系统在每小时崩溃 1ms,那么它的可用性就超过 99.9999%,但是它还是高度不可靠。与之类似,如果一个系统从来不崩溃,但是每年要停机两星期,那么它是高度可靠的,但是可用性只有 96%。
百度百科对于系统可靠性的解释是:系统可靠性一般是指在规定的时间内和规定的工况下,系统完成规定功能的能力/概率。也就是系统的无故障运行概率。而在我们在评估一个系统的可用性和可靠性时,一般都会说三个 9,四个 9 之类的。这些一般都是说系统的**SLA(Service Level Agreement)**具体是几个「9」,以此,来表示该系统一年中具体宕机的时间。对于这几个 9 的解释,我会放到第三节来详细解释。
不过,在实际交流过程中,大多数人对这两个词的理解还是差不多的。况且咬文嚼字也并非本文的主题,接下来我们来看看可用性的计算方式。
可用性计算 通常我们用 A 表示一个系统的可用性,用以下几个指标来辅助计算:
相关指标 MTBF MTBF,即平均故障间隔时间,英文全称是“Mean Time Between Failure”。是衡量一个产品(尤其是电器产品)的可靠性指标。单位为“小时”。具体来说,是指相邻两次故障之间的平均工作时间,也称为平均故障间隔。
MTTR MTTR,全称是 Mean Time To Repair,即平均修复时间。是指可修复产品的平均修复时间,就是从出现故障到修复中间的这段时间。MTTR 越短表示易恢复性越好。
通过上述公式计算出单个组件的可用性后,我们便可以以此计算出整个系统的可用性,而系统可用性是通过将系统建模为串联和并联的组件来计算的。以下规则用于确定系统是串联的还是并联的:
如果组件的失效导致组合变得不可操作,则认为这两个部件是串联操作的 如果组件的故障导致另一部件接管故障部件的操作,则认为这两部件并行操作 串行可用性 如上图所示,两个组件 X 和 Y,如果有一个出问题导致整个组合都不可用,就认为 X 和 Y 这两个组件是串联的。只有组件 X 和组件 Y 同时可用时,整个组合才可用。由此可见,组合的可用性是这两部分的乘积,公式如下:
A = Ax Ay...
【译】如何创建一个可复用的网页爬虫
原文地址:How to Create a Reusable Web Scraper 网页爬虫是个非常有趣的玩具。不过不好玩的是,我们需要根据不同网页上的元素不断的调整自己的代码。这就是为什么我要着手实现一个更好的网页爬虫项目——通过该项目可以以最少的更改实现对新网页的爬取。
第一步是将网页爬虫按照逻辑分成每个独立的部分:
页面请求器 页面验证器 模板页面处理器 页面请求器 页面请求器的实现有一些技巧。下载网页时要考虑很多因素。你需要确保你可以随机的使用用户代理,并且不要过于频繁地从同一域中请求。
此外,停下手头的工作去分析为什么网页无法下载是一件出力不讨好的事。尤其是当你的爬虫已经在多个站点运行了好几个小时的情况下。因此,我们会处理一些请求,并将它们保存为文件。
将请求保存到文件中还有另外一个好处。你不必担心一个标签的消失会影响到你的爬虫。如果页面处理器是独立的,并且你已经完成了页面的下载,你还可以根据需要快速且频繁的对其进行处理。如果发现有另一个要抓取的数据元素怎么办?别担心。只需添加一个标签,然后在你已下载的页面上重新运行处理器即可。
以下是一些实际情况下的示例代码:
import requests import pickle from random import randint from urllib.parse import urlparse def _random_ua(): ua_list = ["user agent1, user agent2", "user agent3"] random_num = randint(0, len(ua_list)) return ua_list[random_num] def _headers(): return { 'user-agent': _random_ua() } def _save_page(response): uri = urlparse(response.url) filename = uri.netloc + ".pickle" with open(filename, 'wb+') as pickle_file: pickle....
云计算之 Anything As a Service
这年头,不管什么应用,仿佛“上云“都成了标配,感觉拥抱了“云”,应用的逼格都上升了。那真的是这样的吗?
是的,的确是这样。 云计算是一种按照需求通过 Internet 获取计算资源的形态。这些计算资源被包装成为服务,提供给用户。而提供这些服务的主体,我们称之为云服务供应商(Cloud Service Provider)。云服务最主要的有三类,就是本文的三个主角 IaaS、PaaS、SaaS。 那这三个 aaS 到底是个啥?
XaaS 看到这个标题,可能就有人产生疑惑了,那三个 aaS 都不知道是什么,怎么突然又多了一个 XaaS。不急,且听我娓娓道来。 XaaS,即一切皆服务,代表 “X as a service”、“anything as a service”或“everything as a service” 。这一缩写指越来越多地通过互联网提供的服务,而不仅仅指本地或现场服务。云计算的本质就是 XaaS。 XaaS 最常见的例子就是“软件即服务”(Software as a Service,SaaS)、“基础设施即服务”(Infrastructure as a Service,IaaS)和“平台即服务”(platform as a service,PaaS)。
详解 根据所提供服务的不同,云服务可以被分为以下三类/三层:
缩写 全写 注释 IaaS Infrastructure as a Service 基础设施即服务 PaaS Platform as a Service 平台即服务 SaaS Software as a Service 软件即服务 如下图所示:...
DO,VO,DTO 你知道吗?
作为后端最常用的编程语言之一,Java 已经有很多年的历史了,在阿里内部,Java 也是使用最广泛的一门语言。在阿里实习的这段时间,规范一词是我感受最深的。没有规矩不成方圆,今天来说一下 Java 中的各种 O(bject)。
为什么会出现这些 O? 我们知道,这些 O 不管叫什么名字,其本质都还是对象(Object),既然本质都一样,为什么非要给他们套上各种马甲? 个人认为原因有三: 第一,随着编程工业化的发展,需要有一套合理的体系出现。中国人喜欢造神,外国人喜欢造概念,于是 MVC、MVP、MVVM 等编程模型就出现了,为了搭配这些编程模型的使用,需要对 Object 的功能进行划分,于是我们便看到了这些层出不穷的 Object。当然这里并没有批评这些概念的意思。 其二,我认为在团队协作编码中,一个好的命名方式是可以节约很多时间成本的。就比如getItemById一眼看去就知道是通过 id 获取一个 item 对象,ItemVO一眼看去就知道是前端透出的 json 对应的对象。 其三,如此划分,可以让项目结构更加清楚,不至于出现东一块西一块,对象乱扔的局面。尽可能避免了在多人协作时对象混乱的情况。 总的来说,这一切都是为了让软件编程更加合理、更加规范、更加高效。
有哪些 O? 这些 O 有很多衍生出的命名,比如 VO、DO、BO,这里我们把常见的 O 列举出来,然后一一解释。
以下内容参考阿里巴巴 Java 开发手册,如果有需要可以在微信公众号「01 二进制」后台回复「Java 开发手册」获得。
DO( Data Object):与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。 PO(Persistant Object):持久对象,一个 PO 的数据结构对应着库中表的结构,表中的一条记录就是一个 PO 对象 DTO( Data Transfer Object):数据传输对象,Service 或 Manager 向外传输的对象。 BO( Business Object):业务对象。 由 Service 层输出的封装业务逻辑的对象。 AO( Application Object):应用对象。 在 Web 层与 Service 层之间抽象的复用对象模型,极为贴近展示层,复用度不高。 VO( View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。 POJO( Plain Ordinary Java Object):POJO 专指只有 setter/getter/toString 的简单类,包括 DO/DTO/BO/VO 等。 DAO(Data Access Objects):数据访问对象,和上面那些 O 不同的是,其功能是用于进行数据操作的。通常不会用于描述数据实体。 一下子给出 8 个常见的 O,光看解释大家可能会有些迷糊,接下来我们从下面这张图入手,带大家直观的感受下,这些 O 的用处。...