#每日精进#2020年8月6日

zkbhj 发表了文章 • 0 个评论 • 149 次浏览 • 2020-08-06 09:31 • 来自相关话题

【早读:《深入理解计算机系统》】

第二章 信息的表示和处理

表示代码int sum(int x, int y) {
return x + y;
}当我们在不同的机器上编译上面的程序得到的机器代码都不尽相同:

Linux32     55 89 e5 8b 45 0c 03 45 08 c9 c3
Windows  55 89 e5 8b 45 0c 03 45 08 5d c3
Sun           81 c3 e0 08 90 03 00 09


因此,二进制代码是不兼容的,无法在不同机器之间移植。

这得到一个计算机系统的基本概念:从机器的角度来看,程序仅仅只是字节序列,机器没有关于原始程序的任何信息。

布尔代数简介

计算机的核心都是围绕1和0来演化的。对于0和1的起源,要追溯到1850年前后乔治·布尔的工作,所以这个也叫布尔代数。即通过将逻辑值TRUE和FALSE编码为二进制1和0设计出的一种代数,以研究逻辑推理的基本原则。






上面分别列出了~(NOT)、&(AND)、|(OR)和^(EXCLUSIVE-OR)四种基本运算。

后来创立信息论领域的Claude Shannon首先建立了布尔代数和数字逻辑之间的联系。

将上述基础的布尔运算扩展到位向量运算。位向量就是固定长度为w、由0和1组成的串。

假设 w=4,a=[0110],b=[1100]。那么四种运算 a&b、a|b、a^b、~b 结果分别如下:





 
布尔运算&对|满足分配率:a&(b|c) = (a&b)|(a&c);反过来,|也满足对&的分配率,即:a|(b&c) = (a|b) & (a|c)。

位向量的一个有用应用就是表示有限集合,即用位向量来给集合进行编码。

C语言的一个有用特性就是支持按位布尔运算。|、&、~、^这些运算可以用到任何“整型”的数据类型上。void inplace_swap(int *x, int *y){
*y = *x ^ *y;
*x = *x ^ *y;
*y = *x ^ *y;
}
上面这段代码,就是利用了两个事实来实现*x和*y所指向的变量值进行了交换操作。两个事实分别是:

异或运算是可交换和可结合的;

对于任意的a, a ^ a = 0;

所以上述程序的计算过程如下:

初始:*x = a    *y = b
第一步:*x = a   *y = a ^ b
第二步:*x = a ^ (a ^ b) = (a ^ a) ^ b = b   *y = a ^ b
第三部:*x = b   *y = b ^ ( a ^ b) = (b ^ b) ^ a = a


但是注意,这种方式和通常的交换两个数值的技术不一样,当移动一个值时,我们不需要第三个位置来临时存放另外一个值。这种交换方式并没有性能上的优势,它仅仅是一个智力游戏!

位级运算常见的用法就是实现掩码运算:掩码是一个位模式,表示从一个字中选出的位的集合。

比如对于掩码0xFF(最低的8位都是1)表示一个字的低位字节。x&0xFF会得到一个由x的最低有效字节组成的值。 
 
 
【英文中几点钟的说法o'clock是什么的缩写?】

o'clock = of the clock.

在14世纪以前,人类还没有发明出来时钟,都是通过一些其他途径来获取和感知时间,比如日晷、沙漏等。直到 14 世纪,现代意义上的时钟雏形才得以发明。当时的时钟会自己报时“说出”:It's 7 of the clock!后来,随着时钟的普及和大众化,人们开始将 of 的 f 和 the 一带而过,简略地读成了 o'clock。
 https://ask.zkbhj.com/?/article/370 查看全部

【早读:《深入理解计算机系统》】

第二章 信息的表示和处理

表示代码
int sum(int x, int y) {
return x + y;
}
当我们在不同的机器上编译上面的程序得到的机器代码都不尽相同:


Linux32     55 89 e5 8b 45 0c 03 45 08 c9 c3
Windows  55 89 e5 8b 45 0c 03 45 08 5d c3
Sun           81 c3 e0 08 90 03 00 09



因此,二进制代码是不兼容的,无法在不同机器之间移植。

这得到一个计算机系统的基本概念:从机器的角度来看,程序仅仅只是字节序列,机器没有关于原始程序的任何信息。

布尔代数简介

计算机的核心都是围绕1和0来演化的。对于0和1的起源,要追溯到1850年前后乔治·布尔的工作,所以这个也叫布尔代数。即通过将逻辑值TRUE和FALSE编码为二进制1和0设计出的一种代数,以研究逻辑推理的基本原则。

20200806092721.jpg


上面分别列出了~(NOT)、&(AND)、|(OR)和^(EXCLUSIVE-OR)四种基本运算。

后来创立信息论领域的Claude Shannon首先建立了布尔代数和数字逻辑之间的联系。

将上述基础的布尔运算扩展到位向量运算。位向量就是固定长度为w、由0和1组成的串。

假设 w=4,a=[0110],b=[1100]。那么四种运算 a&b、a|b、a^b、~b 结果分别如下:

20200806092735.jpg

 
布尔运算&对|满足分配率:a&(b|c) = (a&b)|(a&c);反过来,|也满足对&的分配率,即:a|(b&c) = (a|b) & (a|c)。

位向量的一个有用应用就是表示有限集合,即用位向量来给集合进行编码。

C语言的一个有用特性就是支持按位布尔运算。|、&、~、^这些运算可以用到任何“整型”的数据类型上。
void inplace_swap(int *x, int *y){
*y = *x ^ *y;
*x = *x ^ *y;
*y = *x ^ *y;
}

上面这段代码,就是利用了两个事实来实现*x和*y所指向的变量值进行了交换操作。两个事实分别是:

异或运算是可交换和可结合的;

对于任意的a, a ^ a = 0;

所以上述程序的计算过程如下:


初始:*x = a    *y = b
第一步:*x = a   *y = a ^ b
第二步:*x = a ^ (a ^ b) = (a ^ a) ^ b = b   *y = a ^ b
第三部:*x = b   *y = b ^ ( a ^ b) = (b ^ b) ^ a = a



但是注意,这种方式和通常的交换两个数值的技术不一样,当移动一个值时,我们不需要第三个位置来临时存放另外一个值。这种交换方式并没有性能上的优势,它仅仅是一个智力游戏!

位级运算常见的用法就是实现掩码运算:掩码是一个位模式,表示从一个字中选出的位的集合。

比如对于掩码0xFF(最低的8位都是1)表示一个字的低位字节。x&0xFF会得到一个由x的最低有效字节组成的值。 
 
 
英文中几点钟的说法o'clock是什么的缩写?】


o'clock = of the clock.


在14世纪以前,人类还没有发明出来时钟,都是通过一些其他途径来获取和感知时间,比如日晷、沙漏等。直到 14 世纪,现代意义上的时钟雏形才得以发明。当时的时钟会自己报时“说出”:It's 7 of the clock!后来,随着时钟的普及和大众化,人们开始将 of 的 f 和 the 一带而过,简略地读成了 o'clock。
 https://ask.zkbhj.com/?/article/370

#每日精进#2020年8月5日

zkbhj 发表了文章 • 0 个评论 • 161 次浏览 • 2020-08-05 11:20 • 来自相关话题

【早读:《深入理解计算机系统》】

第二章 信息的表示和处理

寻址和字节顺序

在几乎所有机器上,多字节对象被存储为连续的字节序列,对象的地址为最小的地址。

排列表示一个对象的字节有两个通用的规则:

小端法:在内存中按照从最低有效字节到最高有效字节的顺序存储对象;
大端法:在内存中按照从最高有效字节到最低有效字节的顺序存储对象;一旦选择了特定的操作系统,那么字节顺序也就固定下来。Android和IOS只能够运行于小端模式下。

两种方式没有谁好谁坏之分,对于那种字节排序的选择都是任意的。
大小端的说法来自于Jonathan Swift的《格利弗游记》一书,其中交战的两个派别无法就打开一个半熟的鸡蛋应该从哪一端打开达成一致意见。
不同的端模式下,会有以下影响:
1、通过网络在不同端模式的机器间传递数据时,发送和接收时,需要转换网络标准;
2、在检查机器级程序时,对数据的解读方式;
3、在编写规避正常的类型系统的程序时。​#include <stdio.h>

typedef unsigned char *byte_pointer;
//typedef char *byte_pointer;

void show_bytes(byte_pointer start, size_t len) {
size_t i;
for (i = 0; i < len; i++)
printf("%p\t0x%.2x\n", &start, start);
printf("\n");
}

void show_int(int x) {
show_bytes((byte_pointer) &x, sizeof(int));
}

void show_float(float x) {
show_bytes((byte_pointer) &x, sizeof(float));
}

void show_pointer(void *x) {
show_bytes((byte_pointer) &x, sizeof(void *));
}

​在这段程序中,“byte_pointer start”告诉编译器,应该把这个指针看成指向一个字节序列,而不是指向一个原始数据类型的对象。然后,这个指针会被看成是对象使用的最低字节地址。
这种强制类型转换不会改变真实的指针,它们只是告诉编译器以新的数据类型来看待被指向的数据。
使用ASCII码作为字符码的任何系统上都是将得到相同的结果,与字节顺序和字节大小规则无关。因而,文本数据比二进制数据具有更强的平台独立性。
 
【HTML页面里怎么实现代码包含?】
https://ask.zkbhj.com/?/question/387
 
【Yii2框架中如何区分不同的场景指定赋值字段和检验规则】
 
场景(scenario)

分析上面问题,会发现关键点是批量赋值(massive assignment)和数据校验(validate)两个方法。如果对不同的场景指定赋值字段和检验规则,问题就迎刃而解。

Yii中的scenario有 安全属性 和 活跃属性 两个概念。安全属性用在批量赋值的load方法,只有安全属性才能被赋值;活跃属性用在规则校验的validate方法,在活跃属性集中并且定义了校验规则的属性才会被校验。活跃属性和安全属性的关系是,安全属性是活跃属性的子集。

\yii\base\Model类定义了默认场景:SCENARIO_DEFAULT(值为default)。默认场景下,出现在rules方法中的属性既是活跃属性,又是安全属性(这句话基本正确,看后续解释)。为不同场景指定活跃属性、安全属性以及校验器,可以通过覆盖senarios或rules两个方法实现(几乎每个Model类都会重写rules方法,senarios用得少)。

rules

先看rules方法。默认的属性加校验器定义方式,让每个属性既是安全属性,也是活跃属性。如果想让某个属性不是安全属性(不能通过load批量赋值),在属性名前加感叹号!即可。例如student中的user_id字段:public function rules()
{
return [
["!user_od", "required"],
["!user_id", "integer"],
["!user_od", "unique"],
// other rules
];
}user_id是活跃属性,在写入数据库时会被校验。但它不是安全属性,不能通过load方法进行赋值,解决了安全隐患。

再看rules方法按场景区分校验器规则的做法:定义校验器时on属性指定规则在哪些场景下生效,except属性则排除一些场景(如果不指定on和except,规则对所有场景生效)。例如:public function rules()
{
return [
["password", "string", "length" => [8, 16], "on" => ["signup"]], // 仅在signup场景时才被验证
["status", "integer", "except" => ["signup"], // 除了signup场景,其他情况都校验
// other rules
];
}在原来基础上新增感叹号和on/except属性,非常简便的就定义了非安全属性以及分场景指定校验规则。

scenarios

另外一种更清晰定义安全属性和活跃属性的做法是重写scenarios方法。scenarios方法返回一个数组,数组的键是场景名称,值是活跃属性集合(包饭安全属性)。例如student表的可能实现如下:public function scenarios()
{
return [
self::SCENARIO_DEFAULT => ["!user_id", "grade", "class", xxxx],
"update" => ["grade", "class", xxxx],
];
}默认情形下(学生报名),年级、班级这些信息是安全属性,但user_id不是,只能在程序内部赋值,并在插入数据时被校验;在修改信息时,user_id不是活跃属性,既不能被批量赋值,也不需要校验(事实上它不应该改变)。

scenarios方法只能定义活跃属性和安全属性,无法定义校验规则,需要和rules配合使用。
https://www.cnblogs.com/yangxunwu1992/p/6669380.html

 
【关于未来几年国内经济形势的分析总结】】
 
疫情发生以来,国内外经济形势发生了重大变化。国际局势也从全球化走向了逆全球化的道路,美国通过各种手段(贸易战、“中国病毒”论、打压华为、打压Tik Tok、关闭领事馆、干涉中国内政等)不断打压中国,各大企业也在不断将企业撤出中国。
 
最近最热门的经济词汇就是经济内循环,意思是说,以后要以国内市场为主,国内生产出来的东西,主要在自己国内消化掉,重新转化为生产力。也就是走内需拉动经济增长的路子。这是在疫情发生以及国内外形式发生如此变化之后的无奈之举。
 
我们过去拉动经济的三驾马车是外贸,基建和房地产,内需一向很薄弱,这几年内需份额有所提高,但还不足以成为拉动经济增长的主要动力。
 
最主要体现在居民收入不足,杠杆过高,中产被绑在房地产的战车上面等。
 
从微观层面看,中国消费结构呈现两边高中间低的M字型结构(健康的结构应该是相反的,两边低中间高,中产成为消费的主力)。所以中国目前的情况就是有钱人并不会受到高房价的影响而降低消费,反而还因此提高了消费能力,还在消费升级。然后相对经济收入低的人群消费能力本就低,地摊经济很火就说明这个问题。中产,由于购房等压力,从中端消费跌落到低端消费。
 
所以,国内要实现以经济内循环为主,国际循环为辅的国内国际双循环的新发展格局,有以下几种办法:
1、提高居民购买力
主要就是降房价和提高居民收入,提高居民收入很难,现在经济太差,没有需求就没有工作岗位,居民收入不下降已经很不错,但房价是有可能缓慢下降的

2、发展房地产。
过去十几年就是这么干的,但现在房价太高,已经到了伤害经济的底部,已经不能继续走拉抬房价发展经济的老路。

3、让股市走出慢牛。
目前看也相对可行,上层也一直在强调要通过资本市场服务实体经济,这也是我一向看好A股走牛的重要原因。
 
4、发展高科技和人民币国际化。
 
讲通俗一点,就是:

经济内循环其实就是要过苦日子的另一个代名词。也可以简单理解为好好干活,但不要想着能挣很多钱。在未来很长一段时间里面,物价会相对比较便宜。

 
https://zhuanlan.zhihu.com/p/165347415
 
【Go语言核心36讲:第12节 使用函数的正确姿势(1)】
 
在 Go 语言中,函数可是一等的(first-class)公民,函数类型也是一等的数据类型(函数类型属于引用类型,它的零值为nil)。
这意味着函数不但可以用于封装代码、分割功能、解耦逻辑,还可以化身为普通的值,在其他函数间传递、赋予变量、做类型判断和转换等。“函数是一等的公民”是函数式编程(functional programming)的重要特征。Go 语言在语言层面支持了函数式编程。

package main

import "fmt"

type Printer func(contents string) (n int, err error)

func printToStd(contents string) (bytesNum int, err error) {
return fmt.Println(contents)
}

func main() {
var p Printer
p = printToStd
p("something")
}函数的签名其实就是函数的参数列表和结果列表的统称,它定义了可用来鉴别不同函数的那些特征,同时也定义了我们与函数交互的方式。

各个参数和结果的名称不能算作函数签名的一部分,对于结果声明,名字也可以没有。且函数的名称也不算函数签名的一部分,只是个标识符而已。

高阶函数
 

1. 接受其他的函数作为参数传入;
2. 把其他的函数作为结果返回。

只要满足了其中任意一个特点,我们就可以说这个函数是一个高阶函数。
 
卫述语句
 
卫述语句是指被用来检查关键的先决条件的合法性,并在检查未通过的情况下立即终止当前代码块执行的语句。在 Go 语言中,if 语句常被作为卫述语句。
if op == nil {
return 0, errors.New("invalid operation")
} 查看全部
【早读:《深入理解计算机系统》】

第二章 信息的表示和处理

寻址和字节顺序

在几乎所有机器上,多字节对象被存储为连续的字节序列,对象的地址为最小的地址。

排列表示一个对象的字节有两个通用的规则:


小端法:在内存中按照从最低有效字节到最高有效字节的顺序存储对象;
大端法:在内存中按照从最高有效字节到最低有效字节的顺序存储对象;一旦选择了特定的操作系统,那么字节顺序也就固定下来。Android和IOS只能够运行于小端模式下。


两种方式没有谁好谁坏之分,对于那种字节排序的选择都是任意的。
大小端的说法来自于Jonathan Swift的《格利弗游记》一书,其中交战的两个派别无法就打开一个半熟的鸡蛋应该从哪一端打开达成一致意见。
不同的端模式下,会有以下影响:
1、通过网络在不同端模式的机器间传递数据时,发送和接收时,需要转换网络标准;
2、在检查机器级程序时,对数据的解读方式;
3、在编写规避正常的类型系统的程序时。
​#include <stdio.h>

typedef unsigned char *byte_pointer;
//typedef char *byte_pointer;

void show_bytes(byte_pointer start, size_t len) {
size_t i;
for (i = 0; i < len; i++)
printf("%p\t0x%.2x\n", &start, start);
printf("\n");
}

void show_int(int x) {
show_bytes((byte_pointer) &x, sizeof(int));
}

void show_float(float x) {
show_bytes((byte_pointer) &x, sizeof(float));
}

void show_pointer(void *x) {
show_bytes((byte_pointer) &x, sizeof(void *));
}

​在这段程序中,“byte_pointer start”告诉编译器,应该把这个指针看成指向一个字节序列,而不是指向一个原始数据类型的对象。然后,这个指针会被看成是对象使用的最低字节地址。
这种强制类型转换不会改变真实的指针,它们只是告诉编译器以新的数据类型来看待被指向的数据。
使用ASCII码作为字符码的任何系统上都是将得到相同的结果,与字节顺序和字节大小规则无关。因而,文本数据比二进制数据具有更强的平台独立性。
 
【HTML页面里怎么实现代码包含?】
https://ask.zkbhj.com/?/question/387
 
【Yii2框架中如何区分不同的场景指定赋值字段和检验规则】
 
场景(scenario)

分析上面问题,会发现关键点是批量赋值(massive assignment)和数据校验(validate)两个方法。如果对不同的场景指定赋值字段和检验规则,问题就迎刃而解。

Yii中的scenario有 安全属性 和 活跃属性 两个概念。安全属性用在批量赋值的load方法,只有安全属性才能被赋值;活跃属性用在规则校验的validate方法,在活跃属性集中并且定义了校验规则的属性才会被校验。活跃属性和安全属性的关系是,安全属性是活跃属性的子集。

\yii\base\Model类定义了默认场景:SCENARIO_DEFAULT(值为default)。默认场景下,出现在rules方法中的属性既是活跃属性,又是安全属性(这句话基本正确,看后续解释)。为不同场景指定活跃属性、安全属性以及校验器,可以通过覆盖senarios或rules两个方法实现(几乎每个Model类都会重写rules方法,senarios用得少)。

rules

先看rules方法。默认的属性加校验器定义方式,让每个属性既是安全属性,也是活跃属性。如果想让某个属性不是安全属性(不能通过load批量赋值),在属性名前加感叹号!即可。例如student中的user_id字段:
public function rules()
{
return [
["!user_od", "required"],
["!user_id", "integer"],
["!user_od", "unique"],
// other rules
];
}
user_id是活跃属性,在写入数据库时会被校验。但它不是安全属性,不能通过load方法进行赋值,解决了安全隐患。

再看rules方法按场景区分校验器规则的做法:定义校验器时on属性指定规则在哪些场景下生效,except属性则排除一些场景(如果不指定on和except,规则对所有场景生效)。例如:
public function rules()
{
return [
["password", "string", "length" => [8, 16], "on" => ["signup"]], // 仅在signup场景时才被验证
["status", "integer", "except" => ["signup"], // 除了signup场景,其他情况都校验
// other rules
];
}
在原来基础上新增感叹号和on/except属性,非常简便的就定义了非安全属性以及分场景指定校验规则。

scenarios

另外一种更清晰定义安全属性和活跃属性的做法是重写scenarios方法。scenarios方法返回一个数组,数组的键是场景名称,值是活跃属性集合(包饭安全属性)。例如student表的可能实现如下:
public function scenarios()
{
return [
self::SCENARIO_DEFAULT => ["!user_id", "grade", "class", xxxx],
"update" => ["grade", "class", xxxx],
];
}
默认情形下(学生报名),年级、班级这些信息是安全属性,但user_id不是,只能在程序内部赋值,并在插入数据时被校验;在修改信息时,user_id不是活跃属性,既不能被批量赋值,也不需要校验(事实上它不应该改变)。

scenarios方法只能定义活跃属性和安全属性,无法定义校验规则,需要和rules配合使用。
https://www.cnblogs.com/yangxunwu1992/p/6669380.html

 
【关于未来几年国内经济形势的分析总结】】
 
疫情发生以来,国内外经济形势发生了重大变化。国际局势也从全球化走向了逆全球化的道路,美国通过各种手段(贸易战、“中国病毒”论、打压华为、打压Tik Tok、关闭领事馆、干涉中国内政等)不断打压中国,各大企业也在不断将企业撤出中国。
 
最近最热门的经济词汇就是经济内循环,意思是说,以后要以国内市场为主,国内生产出来的东西,主要在自己国内消化掉,重新转化为生产力。也就是走内需拉动经济增长的路子。这是在疫情发生以及国内外形式发生如此变化之后的无奈之举。
 
我们过去拉动经济的三驾马车是外贸,基建和房地产,内需一向很薄弱,这几年内需份额有所提高,但还不足以成为拉动经济增长的主要动力。
 
最主要体现在居民收入不足杠杆过高中产被绑在房地产的战车上面等。
 
从微观层面看,中国消费结构呈现两边高中间低的M字型结构(健康的结构应该是相反的,两边低中间高,中产成为消费的主力)。所以中国目前的情况就是有钱人并不会受到高房价的影响而降低消费,反而还因此提高了消费能力,还在消费升级。然后相对经济收入低的人群消费能力本就低,地摊经济很火就说明这个问题。中产,由于购房等压力,从中端消费跌落到低端消费。
 
所以,国内要实现以经济内循环为主,国际循环为辅的国内国际双循环的新发展格局,有以下几种办法:
1、提高居民购买力
主要就是降房价和提高居民收入,提高居民收入很难,现在经济太差,没有需求就没有工作岗位,居民收入不下降已经很不错,但房价是有可能缓慢下降的

2、发展房地产。
过去十几年就是这么干的,但现在房价太高,已经到了伤害经济的底部,已经不能继续走拉抬房价发展经济的老路。

3、让股市走出慢牛。
目前看也相对可行,上层也一直在强调要通过资本市场服务实体经济,这也是我一向看好A股走牛的重要原因。
 
4、发展高科技和人民币国际化。
 
讲通俗一点,就是:


经济内循环其实就是要过苦日子的另一个代名词。也可以简单理解为好好干活,但不要想着能挣很多钱。在未来很长一段时间里面,物价会相对比较便宜。


 
https://zhuanlan.zhihu.com/p/165347415
 
【Go语言核心36讲:第12节 使用函数的正确姿势(1)】
 
在 Go 语言中,函数可是一等的(first-class)公民,函数类型也是一等的数据类型(函数类型属于引用类型,它的零值为nil)。
这意味着函数不但可以用于封装代码、分割功能、解耦逻辑,还可以化身为普通的值,在其他函数间传递、赋予变量、做类型判断和转换等。“函数是一等的公民”是函数式编程(functional programming)的重要特征。Go 语言在语言层面支持了函数式编程。

package main

import "fmt"

type Printer func(contents string) (n int, err error)

func printToStd(contents string) (bytesNum int, err error) {
return fmt.Println(contents)
}

func main() {
var p Printer
p = printToStd
p("something")
}
函数的签名其实就是函数的参数列表和结果列表的统称,它定义了可用来鉴别不同函数的那些特征,同时也定义了我们与函数交互的方式。


各个参数和结果的名称不能算作函数签名的一部分,对于结果声明,名字也可以没有。且函数的名称也不算函数签名的一部分,只是个标识符而已。


高阶函数
 


1. 接受其他的函数作为参数传入;
2. 把其他的函数作为结果返回。


只要满足了其中任意一个特点,我们就可以说这个函数是一个高阶函数。
 
卫述语句
 
卫述语句是指被用来检查关键的先决条件的合法性,并在检查未通过的情况下立即终止当前代码块执行的语句。在 Go 语言中,if 语句常被作为卫述语句。
if op == nil { 
return 0, errors.New("invalid operation")
}

#每日精进#2020年8月4日

zkbhj 发表了文章 • 0 个评论 • 150 次浏览 • 2020-08-04 14:51 • 来自相关话题

【早读:《深入理解计算机系统》】
 
第二章 信息的表示和处理

大多数计算机使用8位的块,或字节,作为最小的可寻址内存单位。

机器级程序将内存视为一个非常大的字节数组,称为虚拟内存。

内存中每个字节由一个唯一的数字来标识,称为它的地址。所有可能的地址的集合就称为虚拟地址空间。

所以,这个虚拟地址空间只是一个展现给机器级程序的概念性映像。实际上,它将DRAM、闪存、磁盘存储器等和操作系统软件结合起来,封装了复杂性,为程序提供一个看上去统一的字节数组。


C语言中的一个指针的值,都是某个存储块的第一个字节的虚拟地址。每个程序对象可以简单地视为一个字节块,而程序本身就是一个字节序列。

十六进制表示法

由于二进制和十进制对于描述位模式来说都非常不方便:二进制太冗长,十进制和位模式的互相转化很麻烦,替代的方法就是引入16进制。

以0x或者0X开头,0~9、A~F,不区分大小写且大小写不敏感。

重要的是二进制、十进制和十六进制之间的互相转换方法,详细的可以进入凯冰科技知识共享中心搜索相关问题或文章查看。

对于x=2的n次方这个公式,转换十六进制,可以转化为n=i+4j,然后得到的十六进制就是:0x + 2的i次方 + j个0,比如512,是2的9次方,9=1+4*2,所以十六进制就是0x200。

字数据大小

每台计算机都有一个字长,指明指针数据的标称大小。字长决定虚拟地址空间的最大大小。32位字长限制的虚拟地址空间位4千兆字节(约4GB),而现在比较普及的64位字长的虚拟空间位16EB。

大多数64位机器也可以运行32位机器编译的程序,这是一种向后兼容。//该编译后的程序可以在32或64位机器上运行
linux> gcc -m32 prog.c

//该编译后,只能在64位机器上运行
linux> gcc -m64 prog.c我们将程序称为32位程序或64位程序,区别在于该程序是如何编译的,而不是其运行的机器类型。

ISO C99引入了确定大小的数据类型,int32_t 和int64_t,其数据大小是固定的,分别为4个字节和8个字节。使用确切大小的整数类型是程序员准确控制数据表示的最佳途径。

程序员应该力图使他们的程序可以在不同的机器和编译器上可移植,可移植的一方面就是说程序对不同数据类型的确切大小不敏感。

比如许多程序员假设一个声明为int类型的程序对象能被用来存储一个指针,这在大多数32位的机器上能够正常工作,但是在一台64位的机器上却会导致问题。所以,1980到2010年期间(32位机器是主流)编写的程序,之后64位机器陆续普及之后,迁移过来的程序就暴露出来许多隐藏的对字长的依赖性问题,导致错误。

【垂直行业如电商如何衡量搜索引擎的优劣】

在电商行业中,无论是2B还是2C,最终的业务目的就是交易成单,众所周知搜索服务旨在让消费者能够更快的定位到自己想要的产品。

一般电商搜索的核心是搜索精度和搜索广度,精度就是搜索的精确性,广度就是搜索结果的范围,其关键结果肯定是“为用户找到想要的商品”,但过于追求搜索的精确度就会导致出现搜索的结果比较少或结果为0的情况,用户搜不到商品势必会引发流失,因此在搜索服务里面还可以做的就是给用户提供一些相关性搜索结果。那么搜索做的好不好,其实就是在搜索精度和搜索广度二者之间做一个比较好的平衡点。

搜索过程中遇到的问题:

1.随机性发现的Bad case
2.KPI或者OKR考核
3.业务方诉求

核心指标
 
“搜索PV”:指访问搜索页面的次数;“搜索UV”:访问过搜索结果页的用户数;“无结果率”:空结果PV/搜索PV,无结果率越低,代表客户搜索需求解决情况越好;“TOP5 PV—CTR”:指该query search结果中,排在前五位的item有被点击的搜索PV/该query搜索PV该指标能一定程度反应排序效果;“人均搜索PV”:搜索PV/搜索UV;该指标的含义比较复杂,一方面人均pv大的话可能代表用户对搜索比较感兴趣,但另一方面人均pv大也可能代表搜索召回的结果较差,导致用户无法使用较少的点击找到满足需求的结果;“有点击搜索PV占比”:有点击搜索PV/搜索PV数;“PV-CTR”:搜索结果页item点击数/搜索PV数;“UV-CTR”:点击的uv / 曝光的uv;“Item-CTR”:搜索结果页item点击数/搜索结果页item总曝光PV数;
 
搜索技术等级分类





 
https://developer.aliyun.com/article/769492
 
  查看全部

【早读:《深入理解计算机系统》】
 
第二章 信息的表示和处理

大多数计算机使用8位的块,或字节,作为最小的可寻址内存单位。

机器级程序将内存视为一个非常大的字节数组,称为虚拟内存。

内存中每个字节由一个唯一的数字来标识,称为它的地址。所有可能的地址的集合就称为虚拟地址空间。

所以,这个虚拟地址空间只是一个展现给机器级程序的概念性映像。实际上,它将DRAM、闪存、磁盘存储器等和操作系统软件结合起来,封装了复杂性,为程序提供一个看上去统一的字节数组。


C语言中的一个指针的值,都是某个存储块的第一个字节的虚拟地址。每个程序对象可以简单地视为一个字节块,而程序本身就是一个字节序列。

十六进制表示法

由于二进制和十进制对于描述位模式来说都非常不方便:二进制太冗长,十进制和位模式的互相转化很麻烦,替代的方法就是引入16进制。

以0x或者0X开头,0~9、A~F,不区分大小写且大小写不敏感。

重要的是二进制、十进制和十六进制之间的互相转换方法,详细的可以进入凯冰科技知识共享中心搜索相关问题或文章查看。

对于x=2的n次方这个公式,转换十六进制,可以转化为n=i+4j,然后得到的十六进制就是:0x + 2的i次方 + j个0,比如512,是2的9次方,9=1+4*2,所以十六进制就是0x200。

字数据大小

每台计算机都有一个字长,指明指针数据的标称大小。字长决定虚拟地址空间的最大大小。32位字长限制的虚拟地址空间位4千兆字节(约4GB),而现在比较普及的64位字长的虚拟空间位16EB。

大多数64位机器也可以运行32位机器编译的程序,这是一种向后兼容。
//该编译后的程序可以在32或64位机器上运行
linux> gcc -m32 prog.c

//该编译后,只能在64位机器上运行
linux> gcc -m64 prog.c
我们将程序称为32位程序或64位程序,区别在于该程序是如何编译的,而不是其运行的机器类型。

ISO C99引入了确定大小的数据类型,int32_t 和int64_t,其数据大小是固定的,分别为4个字节和8个字节。使用确切大小的整数类型是程序员准确控制数据表示的最佳途径。

程序员应该力图使他们的程序可以在不同的机器和编译器上可移植,可移植的一方面就是说程序对不同数据类型的确切大小不敏感。

比如许多程序员假设一个声明为int类型的程序对象能被用来存储一个指针,这在大多数32位的机器上能够正常工作,但是在一台64位的机器上却会导致问题。所以,1980到2010年期间(32位机器是主流)编写的程序,之后64位机器陆续普及之后,迁移过来的程序就暴露出来许多隐藏的对字长的依赖性问题,导致错误。

【垂直行业如电商如何衡量搜索引擎的优劣】

在电商行业中,无论是2B还是2C,最终的业务目的就是交易成单,众所周知搜索服务旨在让消费者能够更快的定位到自己想要的产品。

一般电商搜索的核心是搜索精度和搜索广度,精度就是搜索的精确性,广度就是搜索结果的范围,其关键结果肯定是“为用户找到想要的商品”,但过于追求搜索的精确度就会导致出现搜索的结果比较少或结果为0的情况,用户搜不到商品势必会引发流失,因此在搜索服务里面还可以做的就是给用户提供一些相关性搜索结果。那么搜索做的好不好,其实就是在搜索精度和搜索广度二者之间做一个比较好的平衡点。

搜索过程中遇到的问题:


1.随机性发现的Bad case
2.KPI或者OKR考核
3.业务方诉求


核心指标
 
  • “搜索PV”:指访问搜索页面的次数;
  • “搜索UV”:访问过搜索结果页的用户数;
  • “无结果率”:空结果PV/搜索PV,无结果率越低,代表客户搜索需求解决情况越好;
  • “TOP5 PV—CTR”:指该query search结果中,排在前五位的item有被点击的搜索PV/该query搜索PV该指标能一定程度反应排序效果;
  • “人均搜索PV”:搜索PV/搜索UV;该指标的含义比较复杂,一方面人均pv大的话可能代表用户对搜索比较感兴趣,但另一方面人均pv大也可能代表搜索召回的结果较差,导致用户无法使用较少的点击找到满足需求的结果;
  • “有点击搜索PV占比”:有点击搜索PV/搜索PV数;
  • “PV-CTR”:搜索结果页item点击数/搜索PV数;
  • “UV-CTR”:点击的uv / 曝光的uv;
  • “Item-CTR”:搜索结果页item点击数/搜索结果页item总曝光PV数;

 
搜索技术等级分类

13cfe86b5b2f4aacba814f4fb2f080e5.png

 
https://developer.aliyun.com/article/769492
 
 

#每日精进#2020年8月3日

zkbhj 发表了文章 • 0 个评论 • 157 次浏览 • 2020-08-03 20:45 • 来自相关话题

【早读:《深入理解计算机系统》】

第二章 信息的表示和处理

现代计算机存储和处理信息以二值信号表示。二值信号能够很容易的被表示、存储和传输,且用二值信号进行存储和执行计算的电子电路非常简单可靠。

三种重要的数字表示:
 

无符号编码:基于传统的二进制表示法,表示大于或者等于0的数字;
补码编码:表示有符号整数的最常见方式;
浮点数编码:表示实数的科学计数法的以2为基数的版本;


计算机的表示法是以有限数量的位来对一个数字进行编码,所以一旦超出界限,某些运算就会溢出,导致令人吃惊的后果。

整数的计算机运算满足人们所熟知的真正整数运算的许多性质。但是浮点数不一样。

整数的表示虽然只能编码一个相对较小的数值范围,但是这种表示是精确的;

浮点数虽然可以编码一个比较大的数值范围,但是这种标示只是近似的;

通过如下命令,可以在gcc编译C程序时指定C语言版本:
linux> gcc -std=c11 zkbhj.c
//其他版本参数
//GNU 89 无,-std=gnu89
//ANSI ,ISO C90 -ansi,-std=c89
//ISO C99 -std=c99
//ISO C11 -std=c11
【Go核心36讲:第11节 通道的高级玩法】

单向通道

所谓单向通道就是,只能发不能收,或者只能收不能发的通道。

声明一个只能发(向通道发送)不能收(从通道接收),容量为1的单向通道:
var uselessChan = make(chan<- int, 1)声明一个只能收(从通道接收)不能发(向通道发送),容量为1的单向通道:
var uselessChan = make(<-chan int, 1)
与发送操作和接收操作对应,这里的“发”和“收”都是站在操作通道的代码的角度上说的。

单向通道有什么应用价值?

概括地说,单向通道最主要的用途就是约束其他代码的行为。
//参数定义中就约束 ch只能进行发送操作,不能接收
//可以限制方法函数内对参数的操作行为做限定
func SendInt(ch chan<- int) {
ch <- rand.Intn(1000)
}//这段接口声明中,就约定了所以要实现这个接口的实现类型
//都约定了这些方法的参数类型
type Notifier interface {
SendInt(ch chan<- int)
}在实际调用的时候,传递一个双向通道即可,因为Go 语言在这种情况下会自动地把双向通道转换为函数所需的单向通道。

一种专门为了操作通道而存在的语句:select语句

select语句只能与通道联用,它一般由若干个分支组成。每次执行这种语句的时候,一般只有一个分支中的代码会被运行。分支分为两种,一种叫做候选分支,另一种叫做默认分支。每个case表达式中都只能包含操作通道的表达式。
select {
case <-intChannels[0]:
fmt.Println("The first candidate case is selected.")
case <-intChannels[1]:
fmt.Println("The second candidate case is selected.")
case elem := <-intChannels[2]: fmt.Printf("The third candidate case is selected, the element is %d.\n", elem)
default: fmt.Println("No candidate case is selected!")
}select语句只能对其中的每一个case表达式各求值一次。所以,如果我们想连续或定时地操作其中的通道的话,就往往需要通过在for语句中嵌入select语句的方式实现。但这时要注意,简单地在select语句的分支中使用break语句,只能结束当前的select语句的执行,而并不会对外层的for语句产生作用。这种错误的用法可能会让这个for语句无休止地运行下去。

select语句的分支选择规则总结:

1、对于每一个case表达式,都至少会包含一个代表发送操作的发送表达式或者一个代表接收操作的接收表达式;
2、select语句包含的候选分支中的case表达式都会在该语句执行开始时先被求值,并且求值的顺序是依从代码编写的顺序从上到下的;
3、对于每一个case表达式,如果其中的发送表达式或者接收表达式在被求值时,相应的操作正处于阻塞状态,那么对该case表达式的求值就是不成功的;
4、仅当select语句中的所有case表达式都被求值完毕后,它才会开始选择候选分支。这时候,它只会挑选满足选择条件的候选分支执行。所有的都不满足,执行default;
5、如果select语句发现同时有多个候选分支满足选择条件,那么它就会用一种伪随机的算法在这些分支中选择一个并执行;

 
【关于730政治局会议的总结】

15大要点(内循环 + 持久战)
 
​中国发展仍处于战略机遇期从持久战角度认识中长期问题以国内大循环为主题建立中长期协调机制牢牢把握扩大内需这个战略基点确保宏观政策落地见效保持货币供应量合理增长毫不放松抓好常态化疫情防控扩大最终消费加快新基建以新型城镇化带动投资和消费产业链补短板和锻长板从严打击证券违法活动住房不炒缓解疫情对年轻人就业影响

我们遇到的很多问题是中长期的,必须从持久战的角度加以认识

“在泡沫中狂欢的日志不多了,做好潮水退却后的准备,是每个国家,每个人都要面对的现实”

——吴晓灵 前央行副行长 查看全部
【早读:《深入理解计算机系统》】

第二章 信息的表示和处理

现代计算机存储和处理信息以二值信号表示。二值信号能够很容易的被表示、存储和传输,且用二值信号进行存储和执行计算的电子电路非常简单可靠。

三种重要的数字表示:
 


无符号编码:基于传统的二进制表示法,表示大于或者等于0的数字;
补码编码:表示有符号整数的最常见方式;
浮点数编码:表示实数的科学计数法的以2为基数的版本;



计算机的表示法是以有限数量的位来对一个数字进行编码,所以一旦超出界限,某些运算就会溢出,导致令人吃惊的后果。

整数的计算机运算满足人们所熟知的真正整数运算的许多性质。但是浮点数不一样。

整数的表示虽然只能编码一个相对较小的数值范围,但是这种表示是精确的;

浮点数虽然可以编码一个比较大的数值范围,但是这种标示只是近似的;

通过如下命令,可以在gcc编译C程序时指定C语言版本:
linux> gcc -std=c11 zkbhj.c
//其他版本参数
//GNU 89 无,-std=gnu89
//ANSI ,ISO C90 -ansi,-std=c89
//ISO C99 -std=c99
//ISO C11 -std=c11

【Go核心36讲:第11节 通道的高级玩法】

单向通道

所谓单向通道就是,只能发不能收,或者只能收不能发的通道。

声明一个只能发(向通道发送)不能收(从通道接收),容量为1的单向通道:
var uselessChan = make(chan<- int, 1)
声明一个只能收(从通道接收)不能发(向通道发送),容量为1的单向通道:
var uselessChan = make(<-chan int, 1)
与发送操作和接收操作对应,这里的“发”和“收”都是站在操作通道的代码的角度上说的。

单向通道有什么应用价值?

概括地说,单向通道最主要的用途就是约束其他代码的行为。
//参数定义中就约束 ch只能进行发送操作,不能接收
//可以限制方法函数内对参数的操作行为做限定
func SendInt(ch chan<- int) {
ch <- rand.Intn(1000)
}
//这段接口声明中,就约定了所以要实现这个接口的实现类型
//都约定了这些方法的参数类型
type Notifier interface {
SendInt(ch chan<- int)
}
在实际调用的时候,传递一个双向通道即可,因为Go 语言在这种情况下会自动地把双向通道转换为函数所需的单向通道。

一种专门为了操作通道而存在的语句:select语句

select语句只能与通道联用,它一般由若干个分支组成。每次执行这种语句的时候,一般只有一个分支中的代码会被运行。分支分为两种,一种叫做候选分支,另一种叫做默认分支。每个case表达式中都只能包含操作通道的表达式。
select {
case <-intChannels[0]:
fmt.Println("The first candidate case is selected.")
case <-intChannels[1]:
fmt.Println("The second candidate case is selected.")
case elem := <-intChannels[2]: fmt.Printf("The third candidate case is selected, the element is %d.\n", elem)
default: fmt.Println("No candidate case is selected!")
}
select语句只能对其中的每一个case表达式各求值一次。所以,如果我们想连续或定时地操作其中的通道的话,就往往需要通过在for语句中嵌入select语句的方式实现。但这时要注意,简单地在select语句的分支中使用break语句,只能结束当前的select语句的执行,而并不会对外层的for语句产生作用。这种错误的用法可能会让这个for语句无休止地运行下去。

select语句的分支选择规则总结:


1、对于每一个case表达式,都至少会包含一个代表发送操作的发送表达式或者一个代表接收操作的接收表达式;
2、select语句包含的候选分支中的case表达式都会在该语句执行开始时先被求值,并且求值的顺序是依从代码编写的顺序从上到下的;
3、对于每一个case表达式,如果其中的发送表达式或者接收表达式在被求值时,相应的操作正处于阻塞状态,那么对该case表达式的求值就是不成功的;
4、仅当select语句中的所有case表达式都被求值完毕后,它才会开始选择候选分支。这时候,它只会挑选满足选择条件的候选分支执行。所有的都不满足,执行default;
5、如果select语句发现同时有多个候选分支满足选择条件,那么它就会用一种伪随机的算法在这些分支中选择一个并执行;


 
【关于730政治局会议的总结】

15大要点(内循环 + 持久战)
 
  1. ​中国发展仍处于战略机遇期
  2. 从持久战角度认识中长期问题
  3. 以国内大循环为主题
  4. 建立中长期协调机制
  5. 牢牢把握扩大内需这个战略基点
  6. 确保宏观政策落地见效
  7. 保持货币供应量合理增长
  8. 毫不放松抓好常态化疫情防控
  9. 扩大最终消费
  10. 加快新基建
  11. 以新型城镇化带动投资和消费
  12. 产业链补短板和锻长板
  13. 从严打击证券违法活动
  14. 住房不炒
  15. 缓解疫情对年轻人就业影响


我们遇到的很多问题是中长期的,必须从持久战的角度加以认识


“在泡沫中狂欢的日志不多了,做好潮水退却后的准备,是每个国家,每个人都要面对的现实”

——吴晓灵 前央行副行长


#每日精进#2020年08月02日

zkbhj 发表了文章 • 0 个评论 • 132 次浏览 • 2020-08-02 19:46 • 来自相关话题

【午读:《深入理解计算机系统》】

第一章 计算机系统漫游

现代系统之间利用网络通信,和其他系统连接在一起。从一个单独的系统来看,网络可以视为一个I/O设备。

系统不仅仅只是硬件,而是硬件和软件互相交织的结合体,他们之间共同协作已达到运行应用程序的最终目的。

Amdahl(安达尔定律)定律

主要思想是:当对系统的某个部分加速时,其对系统整体性能的影响取决于该部分的重要性和加速程度。
主要观点是:想要显著加速整个系统,必须提升全系统中相当大的部分的速度。

 
Amdahl定律描述了改善任何过程的一般原则。

并发和并行

整个计算机发展历史中,我们一直在做两件事:一是让计算机做得更多,二是让计算机运行的更快。
并发:是一个通用概念,指一个同时具有多个活动的系统;
并行:指的是用并发来使一个系统运行得更快。

进程级并发
并发构建在进程整个抽象上,就能够设计出同时有多个程序执行的系统。
单处理器系统:只有一个处理器的系统;
多处理器系统:一个由单操作系统内核控制的多处理器组成的系统。
超线程,有时称为同时多线程,是一项允许一个CPU执行多个控制流的技术。

指令级并行
CPU可以同时执行多条指令的属性称为指令级并行。
超标量处理器:处理器能够达到比一个时钟周期一条指令更快的执行速率。

计算机系统中抽象的重要性
计算机系统提供的一些抽象,它提供不同层次的抽象表示来隐藏实际实现的复杂性。
比如上一节中:文件是对I/O设备的抽象,虚拟内存是对主存和磁盘的抽象,进程则是对一个正在运行的程序的抽象(处理器、主存和I/O的抽象)。
虚拟机,则提供对整个计算机的抽象。

第一章总结
计算机系统是由硬件和系统软件组成的,它们共同协作以运行应用程序。计算机内部的信息被表示为一组组的位,它们根据上下文有不同的解释方式。程序被其他程序翻译成不同的形式,开始是ASCII文本,然后被编译器和链接器翻译成二进制可执行文件。

处理器读取并解释存储在主存里的二进制指令。因为计算机花了大把时间用于存储器、I/O设备和CPU寄存器之间复制数据,所以讲系统中的存储设备划分成层次结构——CPU寄存器在顶部,接着是多层的硬件高速缓存存储器、DRAM主存和磁盘存储器。

在层次模型中,位于更高层的存储设备比低层的存储设备要更快,单位比特造价也更高。层次结构中较高层次存储设备可以作为较低层次存储设备的高速缓存。通过理解和运用这种存储层次结构的知识,程序员可以优化C程序的性能。

操作系统内核是应用程序和硬件之间的媒介。它提供三个基本的抽象:

(1)文件是对I/O设备的抽象

(2)虚拟存储器是对主存和I/O设备的抽象

(3)进程是对处理器、主存和I/O设备的抽象。

另外,虚拟机提供了对整个计算机的抽象。

最后,网络提供了计算机系统之间通信的手段。从特殊系统的角度来看,网络就是一种I/O设备。
 

一周的早读,完成了《深入理解计算机系统》这本又厚又重的计算机最底层原理书籍第一章的阅读和理解。
好好利用碎片时间,以及找到自己的高效时间段及学习方式很重要。
积少成多,积流成河!
明天开启第二章:程序结构和执行!


PS广而告之时间:

正在筹划一个作为技术人员角度的个人分享网站,以很程序员的视角,将学习过的一门语言、一本技术书籍,以“手册”的形式输出出来。
根据能量守恒定律,有输入就要有输出,既然自己有这样的渠道和能力,打算把体系学习过的一些内容,沉淀成一本本技术手册分享出来,可以给更多有同样需求的人提供一些有意义的帮助和指导。
还是凯冰科技10多年来坚持的一句slogan:
代码改变世界,技术改变生活
Code changes the world, technology changes life
doc.zkbhj.com
第一本就是这本《深入理解计算机系统》。嘿嘿~

【关于如何在美团里继续使用支付宝支付的方法】

额。。由于一些你懂的的原因,大部分美团用户已经无法再美团APP上用支付宝进行支付了。这里暂时不评论这件事情的对与错好与坏,只是从技术的角度,帮你找到了一个怎么继续在美团里使用支付宝支付的方法,操作步骤如下:

1、打开美团APP,点击进入个人中心页面,点击右上角的在线客服,进入客服聊天界面;

2、输入问题:支付宝无法使用;

3、在返回的结果里选择:放弃优惠,恢复支付宝。






经过上面的几步“骚操作”,就可以继续在美团里使用支付宝进行支付了!
 
​【Go语言核心36讲:第10节 通道的基本操作 】

☆ 通道(Channel)

通道是Go 语言最有特色的数据类型,是不同Goroutine之间通信的“桥梁”。
 

Don’t communicate by sharing memory; share memory by communicating. (不要通过共享内存来通信,而应该通过通信来共享内存。)


通道类型的值是 Go 语言自带的、唯一一个可以满足并发安全性的类型。

当容量为0时,我们可以称通道为非缓冲通道,也就是不带缓冲的通道。而当容量大于0时,我们可以称为缓冲通道,也就是带有缓冲的通道。

一个通道相当于一个先进先出(FIFO)的队列。也就是说,通道中的各个元素值都是严格地按照发送的顺序排列的,先被发送通道的元素值一定会先被接收。元素值的发送和接收都需要用到操作符<-。我们也可以叫它接送操作符。一个左尖括号紧接着一个减号形象地代表了元素值的传输方向。

☆ 对通道的发送和接收操作都有哪些基本的特性?

1、对于同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的。

元素值从外界进入通道时会被复制。更具体地说,进入通道的并不是在接收操作符右边的那个元素值,而是它的副本。另一方面,元素值从通道进入外界时会被移动。这个移动操作实际上包含了两步,第一步是生成正在通道中的这个元素值的副本,并准备给到接收方,第二步是删除在通道中的这个元素值。

2、发送操作和接收操作中对元素值的处理都是不可分割的。

这里的“不可分割”的意思是,它们处理元素值时都是一气呵成的,绝不会被打断。

发送时,“复制元素值”和“放置副本到通道内部”这两个步骤不会被打断;

接收时,“复制通道内元素值”“放置副本到接收方”“删掉原值”三个步骤不会被打断。

3、发送操作在完全完成之前会被阻塞。接收操作也是如此。

以上各步骤执行期间,其他操作都会被阻塞。如此阻塞代码其实就是为了实现操作的互斥和元素值的完整。

☆ 发送操作和接收操作在什么时候可能被长时间的阻塞?

有缓冲的,如果通道已满,对它的所有发送操作都会被阻塞,直到通道中有元素值被接收走。如果通道已空,对它的所有接收操作都会被阻塞,直到通道中有新的元素值出现。所有被阻塞的goroutine都是按FIFO的策略执行的。

非缓冲通道,情况要简单一些。无论是发送操作还是接收操作,一开始执行就会被阻塞,直到配对的操作也开始执行,才会继续传递。由此可见,非缓冲通道是在用同步的方式传递数据。

对于值为nil的通道,不论它的具体类型是什么,对它的发送操作和接收操作都会永久地处于阻塞状态。它们所属的 goroutine 中的任何代码,都不再会被执行。所以我们一定不要忘记初始化通道!

☆ 发送操作和接收操作在什么时候会引发 panic?

通道一旦关闭,再对它进行发送操作,就会引发 panic。

如果我们试图关闭一个已经关闭了的通道,也会引发 panic。

通过接收表达式的第二个结果值,可以来判断通道是否关闭,但是可能有延时的。即如果通道已经关闭,但还有值未被取出,则这个时候,返回的仍然是true!

所以最佳实践告诉我们,千万不要让接收方关闭通道,而应当让发送方做这件事。 查看全部

【午读:《深入理解计算机系统》】

第一章 计算机系统漫游

现代系统之间利用网络通信,和其他系统连接在一起。从一个单独的系统来看,网络可以视为一个I/O设备。

系统不仅仅只是硬件,而是硬件和软件互相交织的结合体,他们之间共同协作已达到运行应用程序的最终目的。

Amdahl(安达尔定律)定律


主要思想是:当对系统的某个部分加速时,其对系统整体性能的影响取决于该部分的重要性和加速程度。
主要观点是:想要显著加速整个系统,必须提升全系统中相当大的部分的速度。


 
Amdahl定律描述了改善任何过程的一般原则。

并发和并行

整个计算机发展历史中,我们一直在做两件事:一是让计算机做得更多,二是让计算机运行的更快。
并发:是一个通用概念,指一个同时具有多个活动的系统;
并行:指的是用并发来使一个系统运行得更快。

进程级并发
并发构建在进程整个抽象上,就能够设计出同时有多个程序执行的系统。
单处理器系统:只有一个处理器的系统;
多处理器系统:一个由单操作系统内核控制的多处理器组成的系统。
超线程,有时称为同时多线程,是一项允许一个CPU执行多个控制流的技术。

指令级并行
CPU可以同时执行多条指令的属性称为指令级并行。
超标量处理器:处理器能够达到比一个时钟周期一条指令更快的执行速率。

计算机系统中抽象的重要性
计算机系统提供的一些抽象,它提供不同层次的抽象表示来隐藏实际实现的复杂性。
比如上一节中:文件是对I/O设备的抽象,虚拟内存是对主存和磁盘的抽象,进程则是对一个正在运行的程序的抽象(处理器、主存和I/O的抽象)。
虚拟机,则提供对整个计算机的抽象。

第一章总结
计算机系统是由硬件和系统软件组成的,它们共同协作以运行应用程序。计算机内部的信息被表示为一组组的位,它们根据上下文有不同的解释方式。程序被其他程序翻译成不同的形式,开始是ASCII文本,然后被编译器和链接器翻译成二进制可执行文件。

处理器读取并解释存储在主存里的二进制指令。因为计算机花了大把时间用于存储器、I/O设备和CPU寄存器之间复制数据,所以讲系统中的存储设备划分成层次结构——CPU寄存器在顶部,接着是多层的硬件高速缓存存储器、DRAM主存和磁盘存储器。

在层次模型中,位于更高层的存储设备比低层的存储设备要更快,单位比特造价也更高。层次结构中较高层次存储设备可以作为较低层次存储设备的高速缓存。通过理解和运用这种存储层次结构的知识,程序员可以优化C程序的性能。

操作系统内核是应用程序和硬件之间的媒介。它提供三个基本的抽象:

(1)文件是对I/O设备的抽象

(2)虚拟存储器是对主存和I/O设备的抽象

(3)进程是对处理器、主存和I/O设备的抽象。

另外,虚拟机提供了对整个计算机的抽象。

最后,网络提供了计算机系统之间通信的手段。从特殊系统的角度来看,网络就是一种I/O设备。
 


一周的早读,完成了《深入理解计算机系统》这本又厚又重的计算机最底层原理书籍第一章的阅读和理解。
好好利用碎片时间,以及找到自己的高效时间段及学习方式很重要。
积少成多,积流成河!
明天开启第二章:程序结构和执行!



PS广而告之时间

正在筹划一个作为技术人员角度的个人分享网站,以很程序员的视角,将学习过的一门语言、一本技术书籍,以“手册”的形式输出出来。
根据能量守恒定律,有输入就要有输出,既然自己有这样的渠道和能力,打算把体系学习过的一些内容,沉淀成一本本技术手册分享出来,可以给更多有同样需求的人提供一些有意义的帮助和指导。
还是凯冰科技10多年来坚持的一句slogan:
代码改变世界,技术改变生活
Code changes the world, technology changes life
doc.zkbhj.com
第一本就是这本《深入理解计算机系统》。嘿嘿~

【关于如何在美团里继续使用支付宝支付的方法】

额。。由于一些你懂的的原因,大部分美团用户已经无法再美团APP上用支付宝进行支付了。这里暂时不评论这件事情的对与错好与坏,只是从技术的角度,帮你找到了一个怎么继续在美团里使用支付宝支付的方法,操作步骤如下:


1、打开美团APP,点击进入个人中心页面,点击右上角的在线客服,进入客服聊天界面;

2、输入问题:支付宝无法使用;

3、在返回的结果里选择:放弃优惠,恢复支付宝。



WechatIMG147.jpeg

经过上面的几步“骚操作”,就可以继续在美团里使用支付宝进行支付了!
 
​【Go语言核心36讲:第10节 通道的基本操作 】

☆ 通道(Channel)

通道是Go 语言最有特色的数据类型,是不同Goroutine之间通信的“桥梁”。
 


Don’t communicate by sharing memory; share memory by communicating. (不要通过共享内存来通信,而应该通过通信来共享内存。)



通道类型的值是 Go 语言自带的、唯一一个可以满足并发安全性的类型。

当容量为0时,我们可以称通道为非缓冲通道,也就是不带缓冲的通道。而当容量大于0时,我们可以称为缓冲通道,也就是带有缓冲的通道。

一个通道相当于一个先进先出(FIFO)的队列。也就是说,通道中的各个元素值都是严格地按照发送的顺序排列的,先被发送通道的元素值一定会先被接收。元素值的发送和接收都需要用到操作符<-。我们也可以叫它接送操作符。一个左尖括号紧接着一个减号形象地代表了元素值的传输方向。

☆ 对通道的发送和接收操作都有哪些基本的特性?

1、对于同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的。

元素值从外界进入通道时会被复制。更具体地说,进入通道的并不是在接收操作符右边的那个元素值,而是它的副本。另一方面,元素值从通道进入外界时会被移动。这个移动操作实际上包含了两步,第一步是生成正在通道中的这个元素值的副本,并准备给到接收方,第二步是删除在通道中的这个元素值。

2、发送操作和接收操作中对元素值的处理都是不可分割的。

这里的“不可分割”的意思是,它们处理元素值时都是一气呵成的,绝不会被打断。

发送时,“复制元素值”和“放置副本到通道内部”这两个步骤不会被打断;

接收时,“复制通道内元素值”“放置副本到接收方”“删掉原值”三个步骤不会被打断。

3、发送操作在完全完成之前会被阻塞。接收操作也是如此。

以上各步骤执行期间,其他操作都会被阻塞。如此阻塞代码其实就是为了实现操作的互斥和元素值的完整。

☆ 发送操作和接收操作在什么时候可能被长时间的阻塞?

有缓冲的,如果通道已满,对它的所有发送操作都会被阻塞,直到通道中有元素值被接收走。如果通道已空,对它的所有接收操作都会被阻塞,直到通道中有新的元素值出现。所有被阻塞的goroutine都是按FIFO的策略执行的。

非缓冲通道,情况要简单一些。无论是发送操作还是接收操作,一开始执行就会被阻塞,直到配对的操作也开始执行,才会继续传递。由此可见,非缓冲通道是在用同步的方式传递数据。

对于值为nil的通道,不论它的具体类型是什么,对它的发送操作和接收操作都会永久地处于阻塞状态。它们所属的 goroutine 中的任何代码,都不再会被执行。所以我们一定不要忘记初始化通道!

☆ 发送操作和接收操作在什么时候会引发 panic?

通道一旦关闭,再对它进行发送操作,就会引发 panic。

如果我们试图关闭一个已经关闭了的通道,也会引发 panic。

通过接收表达式的第二个结果值,可以来判断通道是否关闭,但是可能有延时的。即如果通道已经关闭,但还有值未被取出,则这个时候,返回的仍然是true!

所以最佳实践告诉我们,千万不要让接收方关闭通道,而应当让发送方做这件事。

#每日精进#2020年8月1日

zkbhj 发表了文章 • 0 个评论 • 146 次浏览 • 2020-08-01 16:48 • 来自相关话题

 【《无证之罪》紫金陈,阅读总结】
这本书也是在刷完了网剧版(秦昊、邓家佳主演,《无证之罪》8.2分 )之后来读的原著。电视剧版还是做了很大的改动的,整个作品作为侦探推理小说来讲还是可圈可点的,一名技术精尖的法医犯罪,可以把所有证据消灭掉;一个辞职了刑警队长的大学数学教授,可以把高次方程的理论代入到案件的推导中。最后的结局说实话竟然是团灭,真的没有想到。怎么说,个人不是很喜欢这个结局。喜欢推理的同学,可以一看。
 
https://ask.zkbhj.com/?/article/351
 
【Elasticsearch全文检索的实现原理简介】
 
全文搜索原理:倒排索引
 
大家都知道,在数据库中直接全表查询的时间复杂度是o(n),如果对索引列进行查询,其时间复杂度为o(logn),如果数据以key-value形式存储,查询时间复杂度将降为o(1)。那么在全文搜索中我们直接建立从查询词到文档的映射是不是也就获得了o(1)的查询性能?这种词汇到文档的映射被称之为倒排索引。 
索引、类型与文档
索引:含相同属性的文档集合。相当于关系型数据库中的一个database类型:索引可以定义一个或者多个类型,文档必须属于一个类型,其相当于关系型数据库中的表,是通过mapping定义的。mapping中主要包括字段名、字段数据类型和字段索引类型这3个方面的定义,相当于关系型数据库中的schema。(类型在ES7.0中已被废弃)文档:可以被索引的基本数据单位,也是全文搜索中被搜索的对象,可以对应一个网页,一篇txt文档或者一个商品。 相当于关系型数据库中的表中的一行记录。
 
分片

有时候一个索引的数据量非常大,甚至超出了单机的存储能力,这个时候需要对索引分片存储,分别存到不同机器上。

备份

为了防止节点故障到时索引分片丢失,一般会对分片进行备份。备份除了可以保障数据安全性,还可以分担搜索的压力。

ES创建索引默认5个分片,1个备份,分片只能在创建索引的时候指定而备份可以后期动态修改。 
查询
 //指定属性查询
{
"query":{
"match":{
"name":"一页书"
}
}
}

//范围查询
{
"query":{
"range":{
"age{
"gte":18,
"lte":60
}
}
}
}

//多个条件联合查询
{
"query":{
“bool”: {
"must":[
{
"match":{
"name":"一页书"
}
},
{
"filter":{
"term"{
"age":18
}
}
}
]
}
}
}match、macth_phrase、multi_match与term的区别
match对会先对query进行分词,只要文档里面包含一个query中一个词就会被搜出来;macth_phrase也会对query进行分词,但一个文档必须包含query里面所有的词才会被搜出来,可以通过slop参数降低这种约束;
multi_match对多个字段同时进行匹配;term表示完全匹配,不对query进行分词,直接去匹配索引。
{
"query": {
"match_phrase": {
"content" : {
"query" : "我的宝马多少马力",
"slop" : 1
}
}
}
}https://zhuanlan.zhihu.com/p/94181307
 
【中文分词及结巴分词原理】
 
昨天在跟同事讨论我们搜索系统在做实体识别的时候,具体的实现原理是什么,当时对比的是ES是如何做分词的,想当然的理解成结巴也是用的词典树来实现的,今天查了一下,其实不是词典树,而是有向无环图(DAG)。
 
自如的NLP部分(实体识别)用的技术方案是结巴分词。所以,今天详细深入了解下一下中文分词及结巴分词相关的内容。详细见:
https://ask.zkbhj.com/?/article/364
 
  查看全部

 【《无证之罪》紫金陈,阅读总结】
这本书也是在刷完了网剧版(秦昊、邓家佳主演,《无证之罪》8.2分 )之后来读的原著。电视剧版还是做了很大的改动的,整个作品作为侦探推理小说来讲还是可圈可点的,一名技术精尖的法医犯罪,可以把所有证据消灭掉;一个辞职了刑警队长的大学数学教授,可以把高次方程的理论代入到案件的推导中。最后的结局说实话竟然是团灭,真的没有想到。怎么说,个人不是很喜欢这个结局。喜欢推理的同学,可以一看。
 
https://ask.zkbhj.com/?/article/351
 
【Elasticsearch全文检索的实现原理简介】
 
全文搜索原理:倒排索引
 
大家都知道,在数据库中直接全表查询的时间复杂度是o(n),如果对索引列进行查询,其时间复杂度为o(logn),如果数据以key-value形式存储,查询时间复杂度将降为o(1)。那么在全文搜索中我们直接建立从查询词到文档的映射是不是也就获得了o(1)的查询性能?这种词汇到文档的映射被称之为倒排索引。 
索引、类型与文档
  • 索引:含相同属性的文档集合。相当于关系型数据库中的一个database
  • 类型:索引可以定义一个或者多个类型,文档必须属于一个类型,其相当于关系型数据库中的表,是通过mapping定义的。mapping中主要包括字段名、字段数据类型和字段索引类型这3个方面的定义,相当于关系型数据库中的schema。(类型在ES7.0中已被废弃)
  • 文档:可以被索引的基本数据单位,也是全文搜索中被搜索的对象,可以对应一个网页,一篇txt文档或者一个商品。 相当于关系型数据库中的表中的一行记录。

 
分片

有时候一个索引的数据量非常大,甚至超出了单机的存储能力,这个时候需要对索引分片存储,分别存到不同机器上。

备份

为了防止节点故障到时索引分片丢失,一般会对分片进行备份。备份除了可以保障数据安全性,还可以分担搜索的压力。

ES创建索引默认5个分片,1个备份,分片只能在创建索引的时候指定而备份可以后期动态修改。 
查询
 
//指定属性查询
{
"query":{
"match":{
"name":"一页书"
}
}
}

//范围查询
{
"query":{
"range":{
"age{
"gte":18,
"lte":60
}
}
}
}

//多个条件联合查询
{
"query":{
“bool”: {
"must":[
{
"match":{
"name":"一页书"
}
},
{
"filter":{
"term"{
"age":18
}
}
}
]
}
}
}
match、macth_phrase、multi_match与term的区别
  • match对会先对query进行分词,只要文档里面包含一个query中一个词就会被搜出来;
  • macth_phrase也会对query进行分词,但一个文档必须包含query里面所有的词才会被搜出来,可以通过slop参数降低这种约束;

  • multi_match对多个字段同时进行匹配;
  • term表示完全匹配,不对query进行分词,直接去匹配索引。

{
"query": {
"match_phrase": {
"content" : {
"query" : "我的宝马多少马力",
"slop" : 1
}
}
}
}
https://zhuanlan.zhihu.com/p/94181307
 
【中文分词及结巴分词原理】
 
昨天在跟同事讨论我们搜索系统在做实体识别的时候,具体的实现原理是什么,当时对比的是ES是如何做分词的,想当然的理解成结巴也是用的词典树来实现的,今天查了一下,其实不是词典树,而是有向无环图(DAG)。
 
自如的NLP部分(实体识别)用的技术方案是结巴分词。所以,今天详细深入了解下一下中文分词及结巴分词相关的内容。详细见:
https://ask.zkbhj.com/?/article/364
 
 

#每日精进#2020年7月31日

zkbhj 发表了文章 • 0 个评论 • 141 次浏览 • 2020-07-31 08:34 • 来自相关话题

【早读:《深入理解计算机系统》】

第一章 计算机系统漫游

进程

进程是操作系统对一个正在运行程序的一种抽象。一个系统上可以同时运行多个进程,每个进程都好像在独占的使用硬件,他们之间并发运行。

CPU并发执行进程,是通过处理器的进程间切换实现的。操作系统实现这种交错执行的机制称为上下文切换。

操作系统保持跟踪进程运行所需的所有状态信息,称为上下文。

进程的转换是由操作系统的内核来管理的。内核不是一个独立的进程,相反,它是系统管理全部进程所用的代码和数据结构的集合。

线程

现代系统中,一个进程实际上可以由多个称为线程的执行单元组成,每个线程运行在进程的上下文中,并共享同样的代码和全局数据。
线程之间相比进程之间,更容易共享数据,线程切换的代价更小。

虚拟内存

是一个抽象概念,每个进程看到的内存都是一致的,称为虚拟地址空间。

地址最上面是留给操作系统中的代码和数据的,所有进程都一样;底部区域存放用户进程定义的代码和数据。






每个进程看到的虚拟地址空间由大量准确定义的区构成,每个区有专门的功能,由低到高分别是:
程序代码和数据:对所有进程来讲,代码是从同一个固定地址开始的,紧接着是和C全局变量相对应的数据位置;堆:运行时堆,可以通过像malloc和 free这样的标准库函数来在运行时进行动态地扩展和收缩;共享库:用来存放C标准库和数学库这样的共享库的代码和数据的区域。栈:用它来实现函数调用,和堆一样,用户栈可以在执行期间动态的扩展和收缩。每调用一个函数,栈会增长;一个函数返回时,栈会收缩;内核虚拟内存:为内核保留的,存放一些内核函数,必须由内核来执行这些操作。

虚拟内存的运作需要硬件和操作系统之间精密复杂的交互,包括对处理器生成的每个地址的硬件翻译。

文件
文件就是字节序列,仅此而已。计算机中的每一个设备都会被看成是文件。 查看全部
【早读:《深入理解计算机系统》】

第一章 计算机系统漫游

进程

进程是操作系统对一个正在运行程序的一种抽象。一个系统上可以同时运行多个进程,每个进程都好像在独占的使用硬件,他们之间并发运行。

CPU并发执行进程,是通过处理器的进程间切换实现的。操作系统实现这种交错执行的机制称为上下文切换。

操作系统保持跟踪进程运行所需的所有状态信息,称为上下文。

进程的转换是由操作系统的内核来管理的。内核不是一个独立的进程,相反,它是系统管理全部进程所用的代码和数据结构的集合。

线程

现代系统中,一个进程实际上可以由多个称为线程的执行单元组成,每个线程运行在进程的上下文中,并共享同样的代码和全局数据。
线程之间相比进程之间,更容易共享数据,线程切换的代价更小。

虚拟内存

是一个抽象概念,每个进程看到的内存都是一致的,称为虚拟地址空间。

地址最上面是留给操作系统中的代码和数据的,所有进程都一样;底部区域存放用户进程定义的代码和数据。

WX20200731-082727@2x.png


每个进程看到的虚拟地址空间由大量准确定义的区构成,每个区有专门的功能,由低到高分别是:
  • 程序代码和数据:对所有进程来讲,代码是从同一个固定地址开始的,紧接着是和C全局变量相对应的数据位置;
  • 堆:运行时堆,可以通过像malloc和 free这样的标准库函数来在运行时进行动态地扩展和收缩;
  • 共享库:用来存放C标准库和数学库这样的共享库的代码和数据的区域。
  • 栈:用它来实现函数调用,和堆一样,用户栈可以在执行期间动态的扩展和收缩。每调用一个函数,栈会增长;一个函数返回时,栈会收缩;
  • 内核虚拟内存:为内核保留的,存放一些内核函数,必须由内核来执行这些操作。


虚拟内存的运作需要硬件和操作系统之间精密复杂的交互,包括对处理器生成的每个地址的硬件翻译。

文件
文件就是字节序列,仅此而已。计算机中的每一个设备都会被看成是文件。

#每日精进#2020年07月30日

zkbhj 发表了文章 • 0 个评论 • 153 次浏览 • 2020-07-30 08:34 • 来自相关话题

 
【早读:《深入理解计算机系统》】

第一章 计算机系统漫游

hello程序运行过程:

1、键盘输入"./hello"后,shell程序将字符逐一读入寄存器,再把它们存放到主存中;
2、敲击回车,shell就知道我们已经输入结束了,然后shell会执行一系列指令,将hello程序中的代码和数据从磁盘复制到主存。这其中利用了直接存储器存取(DMA),数据直接通过总线从磁盘进入主存中,不会经过处理器;
3、代码和数据加载完毕之后,处理器就开始执行hello程序的main程序中的机器语言指令,将数据(hello,world\n)字符串中的字符从主存中复制到寄存器文件中,再从寄存器文件中复制到显示器设备,最终显示出结果。


高速缓存的重要性:上面的执行过程,我们就可以发现,系统花费了大量的时间把信息从一个地方移动到另一个地方!这些复制都是巨大的开销,减慢了程序”真正“的工作。因此,系统设计者通过让”存储设备形成层次结构”来提供速度,尽可能让这些复制操作能够尽快完成。






存储器层次结构的主要思想是上一层的存储器作为低一层存储器的高速缓存。

L1、L2、L3这些更小更快的存储设备,称为高速缓存存储器(cache memory,简称cache或高速缓存)。高速缓存是用一种叫做静态随机访问存储器(SRAM)的硬件技术实现的。

高速缓存之所以能加快访问速度,从而提高系统整体的效率,是利用了高速缓存的局部性原理:即程序具有访问局部区域里的数据和代码的趋势。通过让高速缓存里存放可能经常访问的数据,大部分的内存操作都能在高速缓存中快速完成。

操作系统管理硬件

应用程序并不能直接跟硬件“打交道”,而是要通过“操作系统”这一“中间商”提供的服务来和硬件进行交流。

操作系统有2个基本功能:
防止硬件被失控的应用程序滥用;向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。
 
操作系统通过以下三个抽象概念来实现上述2个功能:
文件:是对I/O设备的抽象表示;虚拟内存:是对主存和磁盘I/O设备的抽象表示;进程:是对处理器、主存和磁盘I/O设备的抽象表示。Posix标准是IEEE组织为了组织Unix越来越混乱,越来越不标准化而制定的标准化Unix开发提出来的一套标准规范。
 
 
【爱英语Show】
 
开电脑,关电脑不能用Open the computer 和 Close the computer!这两个表达方式的意思是 拆开/关上的意思。
正确的表达方式应该是 Turn on the computer 和 Turn off the computer!
另外,打开/关闭电脑中的文件,可以说 Open the file 或者 Close the file。
 

【高次方程】
 
今天中午在读紫金陈的《无证之罪》时,严良给赵铁民分析案情时提到,这个案子不能用常规的方法。普通的案子,可以根据线索通过“推论”算出来“嫌疑人”,就像是方程,可以通过公式计算出结果。但是这个案子,要用对应“高次方程”的求解方法来分析:那就是先确定结果,再代入方程中进行论证。也就是先确定嫌疑人,然后代入案情中推论。
 
严良提到的“高次方程”其实指的是次数大于等于5的方程,这类方程有一个特点: 高于5次(大于等于5)的方程没有精确代数解(这个定理已经被证明)。 这种方程只能通过数值计算的方法,用数值逼近求近似解。
 
埃瓦里斯特·伽罗瓦,用群论系统化地阐述了五次及五次以上方程不能用公式求解。
 
【今日放学别走】

今天的放学别走部门同学一起Review了近期完成的筛选项后台管理系统的项目代码,项目使用了Gin框架,其中有一个配置文件格式是以前没有接触过的,是Toml。之前一直接触过的有yaml、json、ini之类的,这个今天还是第一次听,大概了解了下一个配置文件的相关内容。

GitHub觉得 YAML 不够简洁优雅,因此捣鼓出了一个TOML。TOML的全称是 Tom’s Obvious, Minimal Language,因为它的作者是 GitHub联合创始人Tom Preston-Werner 。

TOML 的目标是成为一个极简的配置文件格式。TOML 被设计成可以无歧义地被映射为哈希表,从而被多种语言解析。

是大小写敏感的。

可能是目前最好的配置文件格式。详细可以点击了解:
https://blog.csdn.net/john_f_lau/article/details/55803069
 
【Go语言核心36讲:第9节 字典的操作和约束】

Go 语言的字典类型(Map)其实是一个哈希表(hash table)的特定实现,在这个实现中,键和元素的最大不同在于,键的类型是受限的,而元素却可以是任意类型的。之所以会受限,是因为哈希表中的一个重要过程:映射。

映射过程的第一步就是:把键值转换为哈希值。

Go 语言规范规定,键类型的值必须要支持判等操作,所以字典的键类型不可以是函数类型、字典类型和切片类型。

应该优先考虑哪些类型作为字典的键类型?求哈希和判等操作的速度越快,对应的类型就越适合作为键类型。优先选用数值类型和指针类型,通常情况下类型的宽度越小越好。如果非要选择字符串类型的话,最好对键值的长度进行额外的约束。

除了添加键 - 元素对,我们在一个值为nil的字典上做任何操作都不会引起错误。当我们试图在一个值为nil的字典中添加键 - 元素对的时候,Go 语言的运行时系统就会立即抛出一个 panic。

永远要注意那些可能引发 panic 的操作,比如像一个值为nil的字典添加键 - 元素对。 查看全部

 
【早读:《深入理解计算机系统》】

第一章 计算机系统漫游

hello程序运行过程:


1、键盘输入"./hello"后,shell程序将字符逐一读入寄存器,再把它们存放到主存中;
2、敲击回车,shell就知道我们已经输入结束了,然后shell会执行一系列指令,将hello程序中的代码和数据从磁盘复制到主存。这其中利用了直接存储器存取(DMA),数据直接通过总线从磁盘进入主存中,不会经过处理器;
3、代码和数据加载完毕之后,处理器就开始执行hello程序的main程序中的机器语言指令,将数据(hello,world\n)字符串中的字符从主存中复制到寄存器文件中,再从寄存器文件中复制到显示器设备,最终显示出结果。



高速缓存的重要性:上面的执行过程,我们就可以发现,系统花费了大量的时间把信息从一个地方移动到另一个地方!这些复制都是巨大的开销,减慢了程序”真正“的工作。因此,系统设计者通过让”存储设备形成层次结构”来提供速度,尽可能让这些复制操作能够尽快完成。

timg.jpeg


存储器层次结构的主要思想是上一层的存储器作为低一层存储器的高速缓存。

L1、L2、L3这些更小更快的存储设备,称为高速缓存存储器(cache memory,简称cache或高速缓存)。高速缓存是用一种叫做静态随机访问存储器(SRAM)的硬件技术实现的。

高速缓存之所以能加快访问速度,从而提高系统整体的效率,是利用了高速缓存的局部性原理:即程序具有访问局部区域里的数据和代码的趋势。通过让高速缓存里存放可能经常访问的数据,大部分的内存操作都能在高速缓存中快速完成。

操作系统管理硬件

应用程序并不能直接跟硬件“打交道”,而是要通过“操作系统”这一“中间商”提供的服务来和硬件进行交流。

操作系统有2个基本功能:
  1. 防止硬件被失控的应用程序滥用;
  2. 向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。

 
操作系统通过以下三个抽象概念来实现上述2个功能:
  • 文件:是对I/O设备的抽象表示;
  • 虚拟内存:是对主存和磁盘I/O设备的抽象表示;
  • 进程:是对处理器、主存和磁盘I/O设备的抽象表示。Posix标准是IEEE组织为了组织Unix越来越混乱,越来越不标准化而制定的标准化Unix开发提出来的一套标准规范。

 
 
【爱英语Show】
 
开电脑,关电脑不能用Open the computer 和 Close the computer!这两个表达方式的意思是 拆开/关上的意思。
正确的表达方式应该是 Turn on the computer 和 Turn off the computer!
另外,打开/关闭电脑中的文件,可以说 Open the file 或者 Close the file。
 

【高次方程】
 
今天中午在读紫金陈的《无证之罪》时,严良给赵铁民分析案情时提到,这个案子不能用常规的方法。普通的案子,可以根据线索通过“推论”算出来“嫌疑人”,就像是方程,可以通过公式计算出结果。但是这个案子,要用对应“高次方程”的求解方法来分析:那就是先确定结果,再代入方程中进行论证。也就是先确定嫌疑人,然后代入案情中推论。
 
严良提到的“高次方程”其实指的是次数大于等于5的方程,这类方程有一个特点: 高于5次(大于等于5)的方程没有精确代数解(这个定理已经被证明)。 这种方程只能通过数值计算的方法,用数值逼近求近似解
 
埃瓦里斯特·伽罗瓦,用群论系统化地阐述了五次及五次以上方程不能用公式求解
 
【今日放学别走】

今天的放学别走部门同学一起Review了近期完成的筛选项后台管理系统的项目代码,项目使用了Gin框架,其中有一个配置文件格式是以前没有接触过的,是Toml。之前一直接触过的有yaml、json、ini之类的,这个今天还是第一次听,大概了解了下一个配置文件的相关内容。

GitHub觉得 YAML 不够简洁优雅,因此捣鼓出了一个TOML。TOML的全称是 Tom’s Obvious, Minimal Language,因为它的作者是 GitHub联合创始人Tom Preston-Werner 。

TOML 的目标是成为一个极简的配置文件格式。TOML 被设计成可以无歧义地被映射为哈希表,从而被多种语言解析。

是大小写敏感的。

可能是目前最好的配置文件格式。详细可以点击了解:
https://blog.csdn.net/john_f_lau/article/details/55803069
 
【Go语言核心36讲:第9节 字典的操作和约束】

Go 语言的字典类型(Map)其实是一个哈希表(hash table)的特定实现,在这个实现中,键和元素的最大不同在于,键的类型是受限的,而元素却可以是任意类型的。之所以会受限,是因为哈希表中的一个重要过程:映射。

映射过程的第一步就是:把键值转换为哈希值。

Go 语言规范规定,键类型的值必须要支持判等操作,所以字典的键类型不可以是函数类型、字典类型和切片类型。

应该优先考虑哪些类型作为字典的键类型?求哈希和判等操作的速度越快,对应的类型就越适合作为键类型。优先选用数值类型和指针类型,通常情况下类型的宽度越小越好。如果非要选择字符串类型的话,最好对键值的长度进行额外的约束。

除了添加键 - 元素对,我们在一个值为nil的字典上做任何操作都不会引起错误。当我们试图在一个值为nil的字典中添加键 - 元素对的时候,Go 语言的运行时系统就会立即抛出一个 panic。

永远要注意那些可能引发 panic 的操作,比如像一个值为nil的字典添加键 - 元素对。

#每日精进#2020年7月29日

zkbhj 发表了文章 • 0 个评论 • 142 次浏览 • 2020-07-29 09:29 • 来自相关话题

【早读:《深入理解计算机系统》】

第一章 计算机系统漫游

1、了解编译系统是如何工作的有以下优势: 
优化程序性能:了解编译系统将不同的C代码转化为机器代码的方式,比如一个switch是否总是比if-else更高效?一个函数调用的开销有多大等;理解链接时出现的错误:静态变量和全局变量的区别是什么;避免安全漏洞:缓冲区溢出错误一直都是安全漏洞的主要原因。需要限制从不受信任的源接收数据的数量和格式。


2、shell是一个命令行解释器,它输出一个提示符,然后等待输入一个命令行,然后执行这个命令。首先第一个单词如果是内置的shell命令(如cat、top之类的内置命令),那么shell会假设只是一个可执行文件的名字,进而加载并运行它,将输出信息显示到屏幕上。然后换行输出提示符,等待下一个命令行输入。

系统的硬件组成如下图所示:






总线:贯穿整个系统的一组电子管道,被设计成传递定长的字节块(字word),字长(字中的字节数)是一个基本的系统参数,比如4个字节(32位)或8个字节(64位);

I/O设备:系统与外部世界联系的通道。图示里有4个I/O设备:输入的键盘鼠标,输出的显示器,长期存储数据的磁盘驱动器;I/O设备通过一个控制器或者适配器与I/O总线相连。控制器是设备本身或者主板上的芯片组,而适配器是插在主板插槽上的卡;

主存:一个临时存储设备,执行程序时存放程序和程序处理的数据。物理上是一组动态随机存取存储器(DRAM)。逻辑上是一个线性的字节数组,每个字节有唯一的地址,从0开始;

处理器:中央处理单元(CPU),是解释或执行存储在主存中指令的引擎。处理器的核心是一个大小为一个字的存储设备(寄存器),称为程序计数器(PC)。在通电之后的任何时刻,PC都指向主存中的某条机器语言指令。寄存器文件是一个小的存储设备,由一些单个字长的寄存器组成,都有唯一的名字。CPU可能会执行的操作有: 
加载:从主存复制一个字节或者一个字到寄存器,以覆盖原来的内容;存储:从寄存器复制一个字节或者一个字到主存的某个位置,覆盖原来的内容;操作:把两个寄存器内容复制到ALU,ALU对他们进行算数运算,将结果放到一个寄存器里,覆盖原来的内容跳转:从指令本身中抽取一个字,复制到程序计数器PC中,覆盖PC中原来的值;

实际上现代处理器使用了非常复杂的机制来加速程序执行(多核,寄存器缓存等)

【安全用药清单】 
安全保存药物的方法:药品能不开封就不开封,能买铝箔单片封存的,就别买整瓶包装;治疗方案有多种药物可选时,尽量选那种服用的注意事项比较少、吃起来比较方便的药,这样就能避免因未服用方法不当带来的风险;两种以上药物同时使用时,可能存在风险,可以咨询医院要放的药师进行药物重整;食物和药物混合使用,可能存在风险,尤其需要注意西柚、酒、咖啡、牛油果、黄豆;把父母常吃的药拍个照片,存在手机里,以备不时之需。
 
https://mp.weixin.qq.com/s/atZhbBMFyUOvGXy3YPncnA
 
【数据归一化】
 
今天被同事问到什么是归一化。只是以前听过,没有结构化了解过这个概念,今天查了一下,有了一个初级的认识和了解。
 
在物理学的定义上,归一化的解释是:

归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为标量。 在多种计算中都经常用到这种方法。

看到这个概念,就又牵扯到另外一个概念:量纲!量纲是物理学中的一个重要概念。可以定性地表示出导出量与基本量之间的关系。量纲指数都为0的物理量,称为无量纲量。
 
但是作为我们搜索推荐相关的实际应用场景,这里的归一化指的是:数据的标准化(normalization)和归一化!

数据的标准化(normalization)是将数据按比例缩放,使之落入一个小的特定区间。在某些比较和评价的指标处理中经常会用到,去除数据的单位限制,将其转化为无量纲的纯数值,便于不同单位或量级的指标能够进行比较和加权。

目前数据标准化方法有多种,归结起来可以分为直线型方法(如极值法、标准差法)、折线型方法(如三折线法)、曲线型方法(如半正态性分布)。不同的标准化方法,对系统的评价结果会产生不同的影响,然而不幸的是,在数据标准化方法的选择上,还没有通用的法则可以遵循。

其中最典型的就是数据的归一化处理,即将数据统一映射到[0,1]区间上。

 
归一化的目标有2个:
把数变为(0,1)之间的小数。主要是为了数据处理方便提出来的,把数据映射到0~1范围之内处理,更加便捷快速,应该归到数字信号处理范畴之内。把有量纲表达式变为无量纲表达式。
 
归一化后有两个好处,一是提升模型的收敛速度,二是提升模型的精度。
 
https://blog.csdn.net/pipisorry/article/details/52247379
https://www.zhihu.com/question/20467170
 
【今日开发小技巧】
 
今天同事在群里分享了2个提高Go语言代码质量,提前发现代码问题的小技巧:

build的时候,通过参数-race开启竞态检测,然后访问一下应用,就可以看到有哪些可能会出问题的点;
可以用https://staticcheck.io/ 这个在线代码检查工具做一个代码检查;

 【SVGA格式的“图片”】
 
今天在做社区项目写接口文档的时候,品牌图是要支持动画的,移动端开发说品牌图是否支持svga,查了一下才知道这个svga到底是哪路神仙?先看下官方介绍:

SVGA 是一种跨平台的开源动画格式,同时兼容 iOS / Android / Web。SVGA 除了使用简单,性能卓越,同时让动画开发分工明确,各自专注各自的领域,大大减少动画交互的沟通成本,提升开发效率。动画设计师专注动画设计,通过工具输出 svga 动画文件,提供给开发工程师在集成 svga player 之后直接使用。动画开发从未如此简单!

SVGA 除了使用简单,性能卓越,同时让动画开发分工明确,各自专注各自的领域,大大减少动画交互的沟通成本,提升开发效率。

动画设计师专注动画设计,通过工具输出 svga 动画文件,提供给开发工程师在集成 SVGAPlayer 之后直接使用。 
—— 来自官网svga.io


在开发APP的过程中,需要在APP中实现设计同学的UE效果动画,一般都是通过代码实现的,当对于较复杂的动画时,例如直播中刷礼物时的动画,这时利用代码实现会比较复杂。而且Android和iOS两端不好统一效果,如果用gif图片来实现的话,在图片大小和动画帧数之间很难权衡。而且会导致内存吃紧。为了解决这样的问题,实现复杂动画的开源库和SVGA应运而生,还有一个动画开源库Lottie。

对比和详细使用教程可以参考:
https://www.jianshu.com/p/60d28d7bab48​ 
 
【Go语言核心36讲:第8节 Container包中的那些容器】

Go 语言的链表实现在标准库的container/list代码包中。这个代码包中有两个公开的程序实体——List和Element,List 实现了一个双向链表(以下简称链表),而 Element 则代表了链表中元素的结构。
MoveBefore方法和MoveAfter方法,它们分别用于把给定的元素移动到另一个元素的前面和后面;
MoveToFront方法和MoveToBack方法,分别用于把给定的元素移动到链表的最前端和最后端;Front和Back方法分别用于获取链表中最前端和最后端的元素;InsertBefore和InsertAfter方法分别用于在指定的元素之前和之后插入新元素;PushFront和PushBack方法则分别用于在链表的最前端和最后端插入新元素;

在List包含的方法中,用于插入新元素的那些方法都只接受interface{}类型的值。这些方法在内部会使用Element值,包装接收到的新元素。

为什么链表可以做到开箱即用?

List和Element都是结构体类型。结构体类型有一个特点,那就是它们的零值都会是拥有特定结构,但是没有任何定制化内容的值,相当于一个空壳。值中的字段也都会被分别赋予各自类型的零值。var l list.List
上面声明的变量 l 的值是什么呢?

这个零值将会是一个长度为0的链表。
List这个结构体类型有两个字段,一个是Element类型的字段root,另一个是int类型的字段len。顾名思义,前者代表的就是那个根元素,而后者用于存储链表的长度。注意变量小写,所以是包级私有。len的零值是0,代表该链表未包含任何元素,root的零值是该类型的空格,字面量标识的话就是Element{}。

 关键在于它的“延迟初始化”机制。所谓的延迟初始化,你可以理解为把初始化操作延后,仅在实际需要的时候才进行。指针相等是链表已经初始化的充分必要条件。List的根元素永远不会持有任何实际的元素值,而该元素的存在就是为了连接这个循环链表的首尾两端。List的零值是一个只包含了根元素,但不包含任何实际元素值的空链表。

https://time.geekbang.org/column/intro/100013101  查看全部
QQ截图20200729092412.jpg

【早读:《深入理解计算机系统》】

第一章 计算机系统漫游

1、了解编译系统是如何工作的有以下优势: 
  • 优化程序性能:了解编译系统将不同的C代码转化为机器代码的方式,比如一个switch是否总是比if-else更高效?一个函数调用的开销有多大等;
  • 理解链接时出现的错误:静态变量和全局变量的区别是什么;
  • 避免安全漏洞:缓冲区溢出错误一直都是安全漏洞的主要原因。需要限制从不受信任的源接收数据的数量和格式。



2、shell是一个命令行解释器,它输出一个提示符,然后等待输入一个命令行,然后执行这个命令。首先第一个单词如果是内置的shell命令(如cat、top之类的内置命令),那么shell会假设只是一个可执行文件的名字,进而加载并运行它,将输出信息显示到屏幕上。然后换行输出提示符,等待下一个命令行输入。

系统的硬件组成如下图所示:

QQ截图20200729092547.jpg


总线:贯穿整个系统的一组电子管道,被设计成传递定长的字节块(字word),字长(字中的字节数)是一个基本的系统参数,比如4个字节(32位)或8个字节(64位);

I/O设备:系统与外部世界联系的通道。图示里有4个I/O设备:输入的键盘鼠标,输出的显示器,长期存储数据的磁盘驱动器;I/O设备通过一个控制器或者适配器与I/O总线相连。控制器是设备本身或者主板上的芯片组,而适配器是插在主板插槽上的卡;

主存:一个临时存储设备,执行程序时存放程序和程序处理的数据。物理上是一组动态随机存取存储器(DRAM)。逻辑上是一个线性的字节数组,每个字节有唯一的地址,从0开始;

处理器:中央处理单元(CPU),是解释或执行存储在主存中指令的引擎。处理器的核心是一个大小为一个字的存储设备(寄存器),称为程序计数器(PC)。在通电之后的任何时刻,PC都指向主存中的某条机器语言指令。寄存器文件是一个小的存储设备,由一些单个字长的寄存器组成,都有唯一的名字。CPU可能会执行的操作有: 
  1. 加载:从主存复制一个字节或者一个字到寄存器,以覆盖原来的内容;
  2. 存储:从寄存器复制一个字节或者一个字到主存的某个位置,覆盖原来的内容;
  3. 操作:把两个寄存器内容复制到ALU,ALU对他们进行算数运算,将结果放到一个寄存器里,覆盖原来的内容
  4. 跳转:从指令本身中抽取一个字,复制到程序计数器PC中,覆盖PC中原来的值;


实际上现代处理器使用了非常复杂的机制来加速程序执行(多核,寄存器缓存等)

【安全用药清单】 
  • 安全保存药物的方法:药品能不开封就不开封,能买铝箔单片封存的,就别买整瓶包装;
  • 治疗方案有多种药物可选时,尽量选那种服用的注意事项比较少、吃起来比较方便的药,这样就能避免因未服用方法不当带来的风险;
  • 两种以上药物同时使用时,可能存在风险,可以咨询医院要放的药师进行药物重整;
  • 食物和药物混合使用,可能存在风险,尤其需要注意西柚、酒、咖啡、牛油果、黄豆;
  • 把父母常吃的药拍个照片,存在手机里,以备不时之需。

 
https://mp.weixin.qq.com/s/atZhbBMFyUOvGXy3YPncnA
 
【数据归一化】
 
今天被同事问到什么是归一化。只是以前听过,没有结构化了解过这个概念,今天查了一下,有了一个初级的认识和了解。
 
在物理学的定义上,归一化的解释是:


归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为标量。 在多种计算中都经常用到这种方法。


看到这个概念,就又牵扯到另外一个概念:量纲!量纲是物理学中的一个重要概念。可以定性地表示出导出量与基本量之间的关系。量纲指数都为0的物理量,称为无量纲量。
 
但是作为我们搜索推荐相关的实际应用场景,这里的归一化指的是:数据的标准化(normalization)和归一化


数据的标准化(normalization)是将数据按比例缩放,使之落入一个小的特定区间。在某些比较和评价的指标处理中经常会用到,去除数据的单位限制,将其转化为无量纲的纯数值,便于不同单位或量级的指标能够进行比较和加权。

目前数据标准化方法有多种,归结起来可以分为直线型方法(如极值法、标准差法)、折线型方法(如三折线法)、曲线型方法(如半正态性分布)。不同的标准化方法,对系统的评价结果会产生不同的影响,然而不幸的是,在数据标准化方法的选择上,还没有通用的法则可以遵循。

其中最典型的就是数据的归一化处理,即将数据统一映射到[0,1]区间上


 
归一化的目标有2个:
  1. 把数变为(0,1)之间的小数。主要是为了数据处理方便提出来的,把数据映射到0~1范围之内处理,更加便捷快速,应该归到数字信号处理范畴之内。
  2. 把有量纲表达式变为无量纲表达式。

 
归一化后有两个好处,一是提升模型的收敛速度,二是提升模型的精度。
 
https://blog.csdn.net/pipisorry/article/details/52247379
https://www.zhihu.com/question/20467170
 
【今日开发小技巧】
 
今天同事在群里分享了2个提高Go语言代码质量,提前发现代码问题的小技巧:


build的时候,通过参数-race开启竞态检测,然后访问一下应用,就可以看到有哪些可能会出问题的点;
可以用https://staticcheck.io/ 这个在线代码检查工具做一个代码检查;


 【SVGA格式的“图片”】
 
今天在做社区项目写接口文档的时候,品牌图是要支持动画的,移动端开发说品牌图是否支持svga,查了一下才知道这个svga到底是哪路神仙?先看下官方介绍:


SVGA 是一种跨平台的开源动画格式同时兼容 iOS / Android / Web。SVGA 除了使用简单,性能卓越,同时让动画开发分工明确,各自专注各自的领域,大大减少动画交互的沟通成本,提升开发效率。动画设计师专注动画设计,通过工具输出 svga 动画文件,提供给开发工程师在集成 svga player 之后直接使用。动画开发从未如此简单!

SVGA 除了使用简单,性能卓越,同时让动画开发分工明确,各自专注各自的领域,大大减少动画交互的沟通成本,提升开发效率。

动画设计师专注动画设计,通过工具输出 svga 动画文件,提供给开发工程师在集成 SVGAPlayer 之后直接使用。 
—— 来自官网svga.io



在开发APP的过程中,需要在APP中实现设计同学的UE效果动画,一般都是通过代码实现的,当对于较复杂的动画时,例如直播中刷礼物时的动画,这时利用代码实现会比较复杂。而且Android和iOS两端不好统一效果,如果用gif图片来实现的话,在图片大小和动画帧数之间很难权衡。而且会导致内存吃紧。为了解决这样的问题,实现复杂动画的开源库和SVGA应运而生,还有一个动画开源库Lottie。

对比和详细使用教程可以参考:
https://www.jianshu.com/p/60d28d7bab48​ 
 
【Go语言核心36讲:第8节 Container包中的那些容器】

Go 语言的链表实现在标准库的container/list代码包中。这个代码包中有两个公开的程序实体——List和Element,List 实现了一个双向链表(以下简称链表),而 Element 则代表了链表中元素的结构。
MoveBefore方法和MoveAfter方法,它们分别用于把给定的元素移动到另一个元素的前面和后面;
  • MoveToFront方法和MoveToBack方法,分别用于把给定的元素移动到链表的最前端和最后端;
  • Front和Back方法分别用于获取链表中最前端和最后端的元素;
  • InsertBefore和InsertAfter方法分别用于在指定的元素之前和之后插入新元素;
  • PushFront和PushBack方法则分别用于在链表的最前端和最后端插入新元素;


在List包含的方法中,用于插入新元素的那些方法都只接受interface{}类型的值。这些方法在内部会使用Element值,包装接收到的新元素。

为什么链表可以做到开箱即用?

List和Element都是结构体类型。结构体类型有一个特点,那就是它们的零值都会是拥有特定结构,但是没有任何定制化内容的值,相当于一个空壳。值中的字段也都会被分别赋予各自类型的零值。
var l list.List

上面声明的变量 l 的值是什么呢?


这个零值将会是一个长度为0的链表。
List这个结构体类型有两个字段,一个是Element类型的字段root,另一个是int类型的字段len。顾名思义,前者代表的就是那个根元素,而后者用于存储链表的长度。注意变量小写,所以是包级私有。len的零值是0,代表该链表未包含任何元素,root的零值是该类型的空格,字面量标识的话就是Element{}。


 关键在于它的“延迟初始化”机制。所谓的延迟初始化,你可以理解为把初始化操作延后,仅在实际需要的时候才进行。指针相等是链表已经初始化的充分必要条件。List的根元素永远不会持有任何实际的元素值,而该元素的存在就是为了连接这个循环链表的首尾两端。List的零值是一个只包含了根元素,但不包含任何实际元素值的空链表。

https://time.geekbang.org/column/intro/100013101 

#每日精进#2020年7月28日

zkbhj 发表了文章 • 0 个评论 • 124 次浏览 • 2020-07-28 08:30 • 来自相关话题

开通微信公众号了,同学们可以关注:kiss-note。





 
【早读:《深入理解计算机系统》】
第一章 计算机系统漫游
计算机系统由硬件和系统软件组成;本书的目的是帮助你了解程序在系统上执行时,发生了什么以及为什么会这样;c的hello.c源程序开始,源程序实际上就是一个由值0和1组成的位序列,8个位为1组,称为字节,每个字节表示某些文本字符;像hello.c这样只由ASCII字符构成的文件称为文本文件,所有其他文件称为二进制文件;同样的字节序列可能表示不同的对象,唯一区分他们的办法是通过读取到这些数据对象时的上下文信息;C语言的起源:

贝尔实验室的Dennis Ritchie与1969年~1973年之间创建的,之后经历了ANSI C标准到现在的IOS标准。标准定义了C语言和一系列库函数(C标准库)。作者说C语言是“古怪的,有缺陷的,但同时也是一个巨大的成功”。
C语言与Unix操作系统关系密切。C从一开始就是作为一种用于Unix系统的程序语言开发出来的。Unix几乎全部使用C语言编写的;C语言 小而简单;C语言是为实践目的设计的。最初设计用来实现Unix操作系统,但是后来发现开发其他程序也很容易。
缺点:指针会造成困惑和麻烦。缺乏对抽象的显示支持,比如类、对象和异常。C++和Java解决了这些问题。

程序需要经过下面的命令,编译成低级机器语言指令才能被最终运行:
linux> gcc -o hello hello.c
编译系统由4个阶段的程序组成:预处理器(cpp)、编译器(ccl)、汇编器(as)、链接器(ld);

预处理阶段:根据#开头的命令,把包含进来的.h或者.c文件直接插入到相应位置,生成一个hello.i文件;
编译阶段:编译器将hello.i翻译成汇编语言程序,生成hello.s文件;
汇编阶段:汇编器将hello.s翻译成机器语言指令,把它们打包成一种可重定位目标程序,生成hello.o文件;
链接阶段:链接器将标准C库中的已经预编译好的.o文件(比如printf.o)以某种方式合并到我们的hello.o中,最终形成可执行文件hello。

汇编语言将不同的高级语言提供了通用的输出语言。相当于一个连接高级语言和机器语言的桥梁。
 
【成为一个优秀的人,可以从这些方面重点切入】
1、拥有强烈的好奇心:
你所能拥有的一切,都源自于探索;而探索的动力,都源自于好奇。正是因为这种好奇,驱动他们离开舒适区,获得更多新知识,不断拓展自己的边界。拥有好奇心的人,就像一块海绵。不断吸收新的知识,获得更大的成长。也因此,他们总是乐意接受更大的挑战。如果已经丢失了孩童时的好奇心,我们还能再捡起来吗?当然可以,当你对一件事情失去兴趣时,“我好奇如果我这么做了,会怎么样?”这么问自己!
 
2、面对不确定性,选择拥抱而不是怀疑:
人们厌恶不确定性,是因为厌恶不确定性背后巨大的风险。但是,不确定性背后,除了巨大的风险,也可能是巨大的收益。因为拥抱比怀疑,永远多一次机会。能成大事儿的人,在面对不确定性时,更容易选择拥抱,而不是怀疑。

3、相比赚钱,他们有更大的目标和想象力:
房子车子都只是附带品。最关键的是,我要不断成长,积累自己的价值,让自己变得稀缺,有能力去解决别人解决不了的问题。所以想要成大事儿,就要有更大的目标和想象力,专注于创造价值,而不是创造财富。
 
4、延迟满足,极度自律:
在这个世界上,要把一件事情做到极致,其实大部分时候都是很平淡,很枯燥的。延迟满足,能够让你在日复一日的枯燥中,不至于选择放弃。
 
5、不怕犯错,善于自省:
很多人不愿尝试做能力范围之外的事情,有一个原因是:害怕犯错。但其实只要不是什么致命错误,犯一些小错,反而是值得高兴的事。不怕犯错,善于自省,不断改进。这样的人,没有天花板。
 
希望我们都能不断成长为心目中那个,最好的自己。
https://mp.weixin.qq.com/s/9vGy6dc1vhBl58GA6F-ARw
 
【怎么理解美国关闭中国休斯顿使馆时间?本质是什么?】
说白了美方就是在故意找事。对美国好处很大,尤其对特朗普而言好处非常大。下面的视频很好的说明了这件政治事件。
https://player.youku.com/embed/XMTg5MDc5MzI3Ng==
对于这些在野党而言,今天的美国经济搞的再稀烂,那也是特朗普的锅。疫情越猛,经济越差,在野党越开心,当然要千方百计的破坏美国抗疫大局。
手段是合法的,用心是险恶的。所以不是特朗普不想消灭病毒,他是真的做不到。当然,特朗普也不是啥好货,他所有政治行为的唯一目的,也是为了选票和连任。其他一切东西,都没有这个重要,包括美国的未来。
这是人性,无关道德。
https://mp.weixin.qq.com/s/9m6Flh3X3wg9Xo-PJJzvuQ 
 
【Go语言核心36讲:第7节 数组与切片】
数组类型的值(以下简称数组)的长度是固定的(是其类型的一部分),而切片类型的值(以下简称切片)是可变长的。
我们其实可以把切片看做是对数组的一层简单的封装,因为在每个切片的底层数据结构中,一定会包含一个数组。数组可以被叫做切片的底层数组,而切片也可以被看作是对数组的某个连续片段的引用(所以Go 语言的切片类型属于引用类型)。
s3 := []int{1, 2, 3, 4, 5, 6, 7, 8}
s4 := s3[3:6]
fmt.Printf("The length of s4: %d\n", len(s4))
fmt.Printf("The capacity of s4: %d\n", cap(s4))
fmt.Printf("The value of s4: %d\n", s4)s3[3:6] 等同于数学表达式:[3, 6)。所以,s4的长度就是6-3=3。容量是从起始索引开始(无法向左扩展,只能从3开始,及0,1,2切片s4“看不到”),一直到“底层数组”最右端,所以,容量是 8-3=5。
 
切片容量如何增长?
它并不会改变原来的切片,而是会生成一个容量更大的切片,然后将把原有的元素和新元素一并拷贝到新切片中。在一般的情况下,你可以简单地认为新切片的容量(以下简称新容量)将会是原切片容量(以下简称原容量)的 2 倍。
但是,当原切片的长度(以下简称原长度)大于或等于1024时,Go 语言将会以原容量的1.25倍作为新容量的基准(以下新容量基准)。新容量基准会被调整(不断地与1.25相乘),直到结果不小于原长度与要追加的元素数量之和(以下简称新长度)。最终,新容量往往会比新长度大一些,当然,相等也是可能的。
另外,如果我们一次追加的元素过多,以至于使新长度比原容量的 2 倍还要大,那么新容量就会以新长度为基准。
 
切片的底层数组什么时候会被替换?
确切地说,一个切片的底层数组永远不会被替换。为什么?虽然在扩容的时候 Go 语言一定会生成新的底层数组,但是它也同时生成了新的切片。它只是把新的切片作为了新底层数组的窗口,而没有对原切片,及其底层数组做任何改动。请记住,
 
在无需扩容时,append函数返回的是指向原底层数组的新切片,而在需要扩容时,append函数返回的是指向新底层数组的新切片。
 
https://time.geekbang.org/column/intro/100013101
  查看全部
开通微信公众号了,同学们可以关注:kiss-note。

WX20200728-075634@2x.png

 
【早读:《深入理解计算机系统》】
第一章 计算机系统漫游
  • 计算机系统由硬件和系统软件组成;
  • 本书的目的是帮助你了解程序在系统上执行时,发生了什么以及为什么会这样;
  • c的hello.c源程序开始,源程序实际上就是一个由值0和1组成的位序列,8个位为1组,称为字节,每个字节表示某些文本字符;
  • 像hello.c这样只由ASCII字符构成的文件称为文本文件,所有其他文件称为二进制文件;
  • 同样的字节序列可能表示不同的对象,唯一区分他们的办法是通过读取到这些数据对象时的上下文信息;
  • C语言的起源:


贝尔实验室的Dennis Ritchie与1969年~1973年之间创建的,之后经历了ANSI C标准到现在的IOS标准。标准定义了C语言和一系列库函数(C标准库)。作者说C语言是“古怪的,有缺陷的,但同时也是一个巨大的成功”。

  1. C语言与Unix操作系统关系密切。C从一开始就是作为一种用于Unix系统的程序语言开发出来的。Unix几乎全部使用C语言编写的;
  2. C语言 小而简单;
  3. C语言是为实践目的设计的。最初设计用来实现Unix操作系统,但是后来发现开发其他程序也很容易。

缺点:指针会造成困惑和麻烦。缺乏对抽象的显示支持,比如类、对象和异常。C++和Java解决了这些问题。


  • 程序需要经过下面的命令,编译成低级机器语言指令才能被最终运行:

linux> gcc -o hello hello.c

  • 编译系统由4个阶段的程序组成:预处理器(cpp)、编译器(ccl)、汇编器(as)、链接器(ld);


预处理阶段:根据#开头的命令,把包含进来的.h或者.c文件直接插入到相应位置,生成一个hello.i文件;
编译阶段:编译器将hello.i翻译成汇编语言程序,生成hello.s文件;
汇编阶段:汇编器将hello.s翻译成机器语言指令,把它们打包成一种可重定位目标程序,生成hello.o文件;
链接阶段:链接器将标准C库中的已经预编译好的.o文件(比如printf.o)以某种方式合并到我们的hello.o中,最终形成可执行文件hello。


  • 汇编语言将不同的高级语言提供了通用的输出语言。相当于一个连接高级语言和机器语言的桥梁。

 
【成为一个优秀的人,可以从这些方面重点切入】
1、拥有强烈的好奇心:
你所能拥有的一切,都源自于探索;而探索的动力,都源自于好奇。正是因为这种好奇,驱动他们离开舒适区,获得更多新知识,不断拓展自己的边界。拥有好奇心的人,就像一块海绵。不断吸收新的知识,获得更大的成长。也因此,他们总是乐意接受更大的挑战。如果已经丢失了孩童时的好奇心,我们还能再捡起来吗?当然可以,当你对一件事情失去兴趣时,“我好奇如果我这么做了,会怎么样?”这么问自己!
 
2、面对不确定性,选择拥抱而不是怀疑:
人们厌恶不确定性,是因为厌恶不确定性背后巨大的风险。但是,不确定性背后,除了巨大的风险,也可能是巨大的收益。因为拥抱比怀疑,永远多一次机会。能成大事儿的人,在面对不确定性时,更容易选择拥抱,而不是怀疑。

3、相比赚钱,他们有更大的目标和想象力:
房子车子都只是附带品。最关键的是,我要不断成长,积累自己的价值,让自己变得稀缺,有能力去解决别人解决不了的问题。所以想要成大事儿,就要有更大的目标和想象力,专注于创造价值,而不是创造财富。
 
4、延迟满足,极度自律:
在这个世界上,要把一件事情做到极致,其实大部分时候都是很平淡,很枯燥的。延迟满足,能够让你在日复一日的枯燥中,不至于选择放弃。
 
5、不怕犯错,善于自省:
很多人不愿尝试做能力范围之外的事情,有一个原因是:害怕犯错。但其实只要不是什么致命错误,犯一些小错,反而是值得高兴的事。不怕犯错,善于自省,不断改进。这样的人,没有天花板。
 
希望我们都能不断成长为心目中那个,最好的自己。
https://mp.weixin.qq.com/s/9vGy6dc1vhBl58GA6F-ARw
 
【怎么理解美国关闭中国休斯顿使馆时间?本质是什么?】
说白了美方就是在故意找事。对美国好处很大,尤其对特朗普而言好处非常大。下面的视频很好的说明了这件政治事件。
https://player.youku.com/embed/XMTg5MDc5MzI3Ng==
对于这些在野党而言,今天的美国经济搞的再稀烂,那也是特朗普的锅。疫情越猛,经济越差,在野党越开心,当然要千方百计的破坏美国抗疫大局。
手段是合法的,用心是险恶的。所以不是特朗普不想消灭病毒,他是真的做不到。当然,特朗普也不是啥好货,他所有政治行为的唯一目的,也是为了选票和连任。其他一切东西,都没有这个重要,包括美国的未来。
这是人性,无关道德。
https://mp.weixin.qq.com/s/9m6Flh3X3wg9Xo-PJJzvuQ 
 
【Go语言核心36讲:第7节 数组与切片】
数组类型的值(以下简称数组)的长度是固定的(是其类型的一部分),而切片类型的值(以下简称切片)是可变长的。
我们其实可以把切片看做是对数组的一层简单的封装,因为在每个切片的底层数据结构中,一定会包含一个数组。数组可以被叫做切片的底层数组,而切片也可以被看作是对数组的某个连续片段的引用(所以Go 语言的切片类型属于引用类型)。
s3 := []int{1, 2, 3, 4, 5, 6, 7, 8}
s4 := s3[3:6]
fmt.Printf("The length of s4: %d\n", len(s4))
fmt.Printf("The capacity of s4: %d\n", cap(s4))
fmt.Printf("The value of s4: %d\n", s4)
s3[3:6] 等同于数学表达式:[3, 6)。所以,s4的长度就是6-3=3。容量是从起始索引开始(无法向左扩展,只能从3开始,及0,1,2切片s4“看不到”),一直到“底层数组”最右端,所以,容量是 8-3=5。
 
切片容量如何增长?
它并不会改变原来的切片,而是会生成一个容量更大的切片,然后将把原有的元素和新元素一并拷贝到新切片中。在一般的情况下,你可以简单地认为新切片的容量(以下简称新容量)将会是原切片容量(以下简称原容量)的 2 倍
但是,当原切片的长度(以下简称原长度)大于或等于1024时,Go 语言将会以原容量的1.25倍作为新容量的基准(以下新容量基准)。新容量基准会被调整(不断地与1.25相乘),直到结果不小于原长度与要追加的元素数量之和(以下简称新长度)。最终,新容量往往会比新长度大一些,当然,相等也是可能的。
另外,如果我们一次追加的元素过多,以至于使新长度比原容量的 2 倍还要大,那么新容量就会以新长度为基准。
 
切片的底层数组什么时候会被替换?
确切地说,一个切片的底层数组永远不会被替换。为什么?虽然在扩容的时候 Go 语言一定会生成新的底层数组,但是它也同时生成了新的切片。它只是把新的切片作为了新底层数组的窗口,而没有对原切片,及其底层数组做任何改动。请记住,
 
  • 在无需扩容时,append函数返回的是指向原底层数组的新切片,
  • 而在需要扩容时,append函数返回的是指向新底层数组的新切片。

 
https://time.geekbang.org/column/intro/100013101