邢栋博客

邢栋博客,Action博客,记录工作和生活中的点点滴滴

关于栈内存和堆内存
数据结构中的栈和堆:
栈:是一种连续储存的数据结构,具有先进先出的性质。通常的操作有入栈(压栈)、出栈和栈顶元素,就要将之前的所有元素出栈才能完成。类比现实中的箱子一样。
堆:是一种非连续的树形储存结构,每个节点有一个值,整棵树是经过排序的。特点是根节点的值最小(或最大),且根节点的两个子树也是一个堆。常用来实现优先队列,存取随意。

内存中的栈区和堆区:
一般说的内存,指的是计算机的随机储存器(RAM),程序都在这里面运行。
栈内存:由程序自动向操作系统申请分配以及回收,速度快,使用方便,但程序员无法控制。若分配失败,则提示栈溢出错误。注意,const局部变量也存储在栈区内,栈区向地址减小的方向增长。
堆内存:程序员向操作系统申请一块内存,当系统收到程序的申请时,会遍历一个记录空闲内存地址的链表,寻找第一个空间大于所申请空间的堆栈点,然后将该结点从空间结点链表中删除,并将该节点的空间分配给程序。分配的速度较慢,地址不连续,容易碎片化。此外,由程序员申请,同时也必须由程序员负责销毁,否则会导致内存泄漏。

关于堆和栈区别的比喻:
堆和栈的区别可以引用一位前辈的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大
golang声明通道struct{}
sign := make(chan struct{}, 3)
sign <- struct{}{}
<-sign
声明通道sign的时候以chan struct{}作为其类型的。其中的类型字面量struct{}有些类似于空接口类型interface{},它代表了既不包含任何字段也不拥有任何方法的空结构体类型。
struct{}类型值的表示方法只有一个,即:struct{}{}。并且,它占用的内存空间是0字节。确切的说,这个值在整个go程序中永远都只会存一份。虽然我们无数次的使用这个值的字面量,但是用到的却都是同一个值。
当我们仅仅把通道当做传递某种简单信号的介质的时候,用struct{}作为其元素类型是再好不过的了。
go语句及其执行规则(goroutine)
go语言不但有着独特的并发编程模型,以及用户级线程goroutine,还拥有强大的用于调度goroutine、对接系统线程的调度器。
这个调度器是go语言运行时系统的重要组成部分,它主要负责统筹调配go并发编程模型中的三个元素,即:G(gotoutine的缩写),P(process的缩写)和M(machine的缩写)。
其中M指代的是系统级线程。而P指的是一种可以承诺若干个G,而且能够使这些G适时地与M进行对接,并得到真正运行的中介。


//demo1:
package main
import (
	"fmt"
	//"time"
)
func main() {
	num := 10
	sign := make(chan struct{}, num)
	for i := 0; i < num; i++ {
		go func() {
			fmt.Println(i)
			sign <- struct{}{}
		}()
	}
	// 办法1。
	//time.Sleep(time.Millisecond * 500)

	// 办法2。
	for j := 0; j < num; j++ {
		<-sign
	}
}

golang让多个goroutine按照既定的顺序运行

//demo1:
package main
import (
	"fmt"
	"sync/atomic"
	"time"
)
func main() {
	var count uint32
	trigger := func(i uint32, fn func()) {
		for {
			if n := atomic.LoadUint32(&count); n == i {
				fn()
				atomic.AddUint32(&count, 1) //count++
				break
			}
			time.Sleep(time.Nanosecond)
		}
	}

	for i := uint32(0); i < 10; i++ {
		go func(i uint32) {
			fn := func() {
				fmt.Println(i)
			}
			trigger(i, fn)
		}(i)
	}
	trigger(10, func() {})
}


关于golang值的内存寻址

go语言哪些值不可以寻址
1.常量的值。 
2.基本类型值的字面量。 
3.算术操作的结果值。
4.对各种字面量的索引表达式和切片表达式的结果值。不过有一个例外,对切片字面量的索引结果值却是可寻址的。
5.对字符串变量的索引表达式和切片表达式的结果值
6.对字典变量的索引表达式的结果值。
7.函数字面量和方法字面量,以及对它们的调用表达式的结果值。
8.结构体字面量的字段值,也就是对结构体字面量的选择表达式的结果值。
9.类型转换表达式的结果值。
10.类型断言表达式的结果值。
11.接收表达式的结果值。

总结:不可变的、临时结果和不安全的
1.不可变的值不可寻址。常量、基本类型的值字面量、字符串变量的值、函数以及方法的字面量都是如此。其实这样规定也有安全性方面的考虑。
2.绝大多数被视为临时结果的值都是不可寻址的。算术操作的结果值属于临时结果,针对值字面量的表达式结果值也属于临时结果。但有一个例外,对切片字面量的索引结果值虽然也属于临时结果,但却是可寻址的。
3.若拿到某值的指针可能会破坏程序的一致性,那么就是不安全的,该值就不可寻址。由于字典的内部机制,对字典的索引结果值的取址操作都是不安全的。另外,获取由字面量或标识符代表的函数或方法的地址显然也是不安全的。

package main

type Named interface {
	// Name 用于获取名字。
	Name() string
}

type Dog struct {
	name string
}

func (dog *Dog) SetName(name string) {
	dog.name = name
}

func (dog Dog) Name() string {
	return dog.name
}

func main() {
	// 示例1。
	const num = 123
	//_ = &num // 常量不可寻址。
	//_ = &(123) // 基本类型值的字面量不可寻址。

	var str = "abc"
	_ = str
	//_ = &(str[0]) // 对字符串变量的索引结果值不可寻址。
	//_ = &(str[0:2]) // 对字符串变量的切片结果值不可寻址。
	str2 := str[0]
	_ = &str2 // 但这样的寻址就是合法的。

	//_ = &(123 + 456) // 算术操作的结果值不可寻址。
	num2 := 456
	_ = num2
	//_ = &(num + num2) // 算术操作的结果值不可寻址。

	//_ = &([3]int{1, 2, 3}[0]) // 对数组字面量的索引结果值不可寻址。
	//_ = &([3]int{1, 2, 3}[0:2]) // 对数组字面量的切片结果值不可寻址。
	_ = &([]int{1, 2, 3}[0]) // 对切片字面量的索引结果值却是可寻址的。
	//_ = &([]int{1, 2, 3}[0:2]) // 对切片字面量的切片结果值不可寻址。


	//_ = &(map[int]string{1: "a"}[0]) // 对字典字面量的索引结果值不可寻址。
	var map1 = map[int]string{1: "a", 2: "b", 3: "c"}
	_ = map1
	//_ = &(map1[2]) // 对字典变量的索引结果值不可寻址。

	//_ = &(func(x, y int) int {
	//	return x + y
	//}) // 字面量代表的函数不可寻址。
	//_ = &(fmt.Sprintf) // 标识符代表的函数不可寻址。
	//_ = &(fmt.Sprintln("abc")) // 对函数的调用结果值不可寻址。

	dog := Dog{"little pig"}
	_ = dog
	//_ = &(dog.Name) // 标识符代表的函数不可寻址。
	//_ = &(dog.Name()) // 对方法的调用结果值不可寻址。

	//_ = &(Dog{"little pig"}.name) // 结构体字面量的字段不可寻址。

	//_ = &(interface{}(dog)) // 类型转换表达式的结果值不可寻址。
	dogI := interface{}(dog)
	_ = dogI
	//_ = &(dogI.(Named)) // 类型断言表达式的结果值不可寻址。
	named := dogI.(Named)
	_ = named
	//_ = &(named.(Dog)) // 类型断言表达式的结果值不可寻址。

	var chan1 = make(chan int, 1)
	chan1 <- 1
	//_ = &(<-chan1) // 接收表达式的结果值不可寻址。

}

golang笔记之Printf函数
package main
import "fmt"
import "os"
type point struct {
	x, y int
}
func main() {
	//Go 为常规 Go 值的格式化设计提供了多种打印方式。例如,这里打印了 point 结构体的一个实例。
	p := point{1, 2}

	fmt.Printf("%v\n", p) // {1 2}
	// 如果值是一个结构体,%+v 的格式化输出内容将包括结构体的字段名。
	fmt.Printf("%+v\n", p) // {x:1 y:2}
	// %#v 形式则输出这个值的 Go 语法表示。例如,值的运行源代码片段。
	fmt.Printf("%#v\n", p) // main.point{x:1, y:2}
	//需要打印值的类型,使用 %T。
	fmt.Printf("%T\n", p) // main.point
	//格式化布尔值是简单的。
	fmt.Printf("%t\n", true)

	//格式化整形数有多种方式,使用 %d进行标准的十进制格式化。
	fmt.Printf("%d\n", 123)
	//这个输出二进制表示形式。
	fmt.Printf("%b\n", 14)
	//这个输出给定整数的对应字符。
	fmt.Printf("%c\n", 33)
	//%x 提供十六进制编码。
	fmt.Printf("%x\n", 456)
	//对于浮点型同样有很多的格式化选项。使用 %f 进行最基本的十进制格式化。
	fmt.Printf("%f\n", 78.9)
	//%e 和 %E 将浮点型格式化为(稍微有一点不同的)科学技科学记数法表示形式。
	fmt.Printf("%e\n", 123400000.0)
	fmt.Printf("%E\n", 123400000.0)

	//使用 %s 进行基本的字符串输出。
	fmt.Printf("%s\n", "\"string\"")
	//像 Go 源代码中那样带有双引号的输出,使用 %q。
	fmt.Printf("%q\n", "\"string\"")
	//和上面的整形数一样,%x 输出使用 base-16 编码的字符串,每个字节使用 2 个字符表示。
	fmt.Printf("%x\n", "hex this")
	//要输出一个指针的值,使用 %p。
	fmt.Printf("%p\n", &p)
	//当输出数字的时候,你将经常想要控制输出结果的宽度和精度,可以使用在 % 后面使用数字来控制输出宽度。默认结果使用右对齐并且通过空格来填充空白部分。
	fmt.Printf("|%6d|%6d|\n", 12, 345)
	//你也可以指定浮点型的输出宽度,同时也可以通过 宽度.精度 的语法来指定输出的精度。
	fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)
	//要最对齐,使用 - 标志。
	fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)
	//你也许也想控制字符串输出时的宽度,特别是要确保他们在类表格输出时的对齐。这是基本的右对齐宽度表示。
	fmt.Printf("|%6s|%6s|\n", "foo", "b")
	//要左对齐,和数字一样,使用 - 标志。
	fmt.Printf("|%-6s|%-6s|\n", "foo", "b")
	//到目前为止,我们已经看过 Printf了,它通过 os.Stdout输出格式化的字符串。Sprintf 则格式化并返回一个字符串而不带任何输出。
	s := fmt.Sprintf("a %s", "string")
	fmt.Println(s)
	//你可以使用 Fprintf 来格式化并输出到 io.Writers而不是 os.Stdout。
	fmt.Fprintf(os.Stderr, "an %s\n", "error")
}
golang笔记之值类型和引用类型
值类型:所有像int、float、bool和string这些类型都属于值类型,使用这些类型的变量直接指向存在内存中的值,值类型的变量的值存储在栈中。当使用等号=将一个变量的值赋给另一个变量时,如 j = i ,实际上是在内存中将 i 的值进行了拷贝。可以通过 &i 获取变量 i 的内存地址

引用类型:复杂的数据通常会需要使用多个字,这些数据一般使用引用类型保存。一个引用类型的变量r1存储的是r1的值所在的内存地址(数字),或内存地址中第一个字所在的位置,这个内存地址被称之为指针,这个指针实际上也被存在另外的某一个字中。

局部变量被声明后必须在相同的代码块中使用它,否则会得到编译错误,全局变量允许声明但不使用.如果要交换两个变量(已声明且赋值)的值,可以简单地使用a,b = b,a,这被称为并行或同时赋值; _实际上是一个只写变量,我们无法得到它的值,这样做是因为Go语言中必须使用所有被声明的局部变量,但有时我们并不需要使用从一个函数中得到的所有返回值;并行赋值也被用于当一个函数返回多个返回值时,比如这里的val和错误err是通过调用func1函数同时得到:val,err = func1()

iota:特殊常量,可以认为是一个可以被编译器修改的常量。在每一个const关键字出现时,被重置为0,然后在下一个const出现之前,每出现一次iota,值自动加1.
php+nginx+mysql+apache查看其编译参数
查看nginx编译参数:/usr/local/nginx/sbin/nginx -V

查看php编译参数:/usr/local/php/bin/php -i | grep configure

查看mysql编译参数:cat /usr/local/mysql/bin/mysqlbug | grep CONFIGURE_LINE //待纠正

查看apache编译参数:cat /usr/local/apache2/build/config.nice   //待认证
关于负载均衡
负载均衡的工作方式

1.http重定向
当http代理(比如浏览器)向web服务器请求某个url后,web服务器可以通过http响应信息中的location标记来返回一个新的url。这意味着http代理需要继续请求这个新的url,完成自动跳转。
缺点:吞吐率限制
优点:不需要额外的技术支持

2.dns负载均衡
dns负责提供域名解析服务,当访问某个站点时,实际上首先需要通过该站点域名的dns服务器来获取域名指向的ip地址,这一过程,dns服务器完成了域名到ip地址的映射,同样,这样映射也可以是一对多的,这个时候,dns服务器便充当了负载均衡调度器
dig google.cn 查看dns的配置
缺点:dns记录缓存更新不及时、策略的局限性、不能做健康检查
优点:可以寻找最近的服务器,加快请求速度
适用场景:多机房部署的时候


3.反向代理负载均衡
在用户的请求到达反向代理服务器时(已经到达网站机房),由反向代理服务器根据算法转发到具体的服务器。常用的apache,nginx都可以充当反向代理服务器。反向代理的调度器可以根据扮演的是用户和实际服务器中间人的角色。
工作在http层(七层)
缺点:代理服务器成为性能的瓶颈,特别是一次上传大文件
有点:配置简单、策略丰富、维持用户回话、可根据访问路径做转发。
适用场景:请求量不高的,简单负载均衡。后端较大的应用。

4.ip负载均衡
工作在传输层(四层)
通过操作系统内修改发送来的ip数据包,将数据包的目标地址修改为内部实际服务器地址,从而实现请求的转发,做到负载均衡。lvs的nat模式。
缺点:所有数据进出还是过负载机器,网络宽带成为瓶颈。
优点:内核完成转发,性能高。
使用场景:对性能要求高,但对宽带要求不高的应用。视频和下载等大宽带的应用,不适合使用。

5.数据链路层的负载均衡
工作在数据链路层(二层)
在请求到达负载均衡器后,通过配置所有集群机器的虚拟ip和负载均衡器相同,再通过修改请求的mac地址,从而做到请求的转发。与ip负载均衡不一样的是,在请求访问服务器 之后,直接返回客户。而无需经过负载均衡器。LVS DR(Direct Routing)模式。
缺点:配置复杂
优点:由集群机器直接返回,提高了出口宽带。
适用场景:大型网站使用最广的一种负载均衡方法



负载均衡中维护用户的session会话
1.把同一个用户在某一个会话中的请求,都分配到固定的某一台服务器上去,常见的负载均衡算法有ip_hash法。
2.session数据集中存储。session数据集中存储就是利用数据库或者缓存来存储session数据,实现了session和应用服务器的解耦。
3.使用cookie代替session。


负载均衡常见的策略
1.轮询
能力比较弱的服务器导致能力较弱的服务器最先超载

2.加权轮询
这种算法解决了简单轮训调度算法的缺点:传入的请求按照顺序被分配到集群中服务器,但是会考虑提前为每台服务器分配的权重。

3.最少连接数
根据后端服务器当前的连接数情况,动态的选取其中当前积压连接数量最少的一台服务器处理当前的请求,尽可能的提高后端服务的利用效率,将请求合理的分流到每一台服务器

4.加权最少连接数

5.源ip_hash
这种方式通过生成请求源ip的哈希值,并通过这个hash值来找到正确的真实服务器,这意味着对于同一主机来说他对应的服务器总是相同。

6.随机
通过系统的随机算法,根据后端服务器的列表大小值来随机选取其中的一台服务器进行访问,实际效果接近轮询的结果。



优惠券
广告位-淘宝
最新微语