panic recover defer channel git代码冲突 接口interface转结构体
驱动
https://blog.csdn.net/weixin_44895651/article/details/109193894
linux驱动有两种运行方式
- 将驱动编写进Linux内核中,当linux内核启动的时候就会自动运行驱动程序。
- 将驱动编译成模块(linux下模块拓展名为.ko),在linux内核启动以后使用“insmod”命令加载驱动模块。
vscode 键盘快捷方式keybindings.json
c语言extern关键字
https://blog.csdn.net/xingjiarong/article/details/47656339
extern关键字可以在一个文件中引用另一个文件中定义的变量或函数。
-
引用同一个文件中的变量
利用extern关键字,使用在后边定义的变量。#include<stdio.h> int func(); int main() { func(); //1 extern int num; printf("%d",num); //2 return 0; } int num = 3; int func() { printf("%d\n",num); }
-
引用另一个文件中的变量
-
引用另一个文件中的函数
//main.c #include <stdio.h> int main() { extern void func(); func(); return 0; }
//b.c #include <stdio.h> const int num = 5; void func() { print("fun in b.c"); }
摄像机数字变倍,光学变倍区别
数字变倍(变焦)就是已经有了的画面取其中一部分加以放大,也就是说,放得越大画面越不清楚。 光学变倍(变焦)是在实景当中,把某处放大,(类似与用望远镜看景物)。无论放的多大,都会清楚。 所以,光学变焦最重要。但光学变焦倍数越大,相机价格越高。
云台PPT
D 数据位
控制什么直接把相应的位至成1,其他位填0。
云台架构图
架构图分类
有一种比较流行的是4+1视图,分别为场景视图、逻辑视图、物理视图、处理流程视图和开发视图。
16进制转换10进制
https://www.jianshu.com/p/c883a6e23016
func main() {
// DataToPosition(24, 221)
h:=hexToBigInt("0x18dd")
fmt.Println(h)
}
func DataToPosition(dec1, dec2 int) {
a := dec1<<8 | dec2
fmt.Println(a)
}
func hexToBigInt(hex string) *big.Int {
n := new(big.Int)
n, _ = n.SetString(hex[2:], 16)
return n
}
var num01 int = 0xf
fmt.Printf("%x的十进制为%d", num01,num01)
1. 二进制转八进制 %b -> %o
2. 二进制转十进制 %b -> %d
3. 二进制转十六进制 %b -> %x
4. 八进制转二进制 %o -> %b
5. 八进制转十进制 %o -> %d
6. 八进制转十六进制 %o -> %x
7. 十进制转二进制 %d -> %b
8. 十进制转八进制 %d -> %o
9. 十进制转十六进制 %d -> %x
10. 十六进制转二进制 %x -> %b
11. 十六进制转八进制 %x -> %o
12. 十六进制转十进制 %x -> %d
Ubuntu20.04 alias别名
vim /home/ling/.bashrc
source /home/ling/.bashrc
alias ss='source ~/cgo/528.sh'
alias cc='cd /home/ling/go/src/neuron'
alias ww='go build'
alias ff='cp neuron /home/ling/share'
vscode常用快捷键
前进ctrl+left 后退ctrl+right
panic、recover、defer
链表:单向,双向,环形
https://www.cnblogs.com/mzhaox/p/11294107.html
图解panic & recove
https://mp.weixin.qq.com/s/vcJ6TsnknaCoYhH6XZnNMw
defer
https://mp.weixin.qq.com/s/gaC2gmFhJezH-9-uxpz07w
当前执行的goroutine持有一个defer链表的头指针,和一个panic链表头指针。
defer 头插法注册,从头开始执行
package main
import "fmt"
func B(a int) int {
a++
return a
}
func A(a int) {
a++
fmt.Println("A",a)
}
func main() {
a := 1
defer A(B(a))
a++
fmt.Println("main",a)
}
//main 2
//A 3
package main
import "fmt"
func A() {
defer A1()
defer A2()
}
func A1() {
fmt.Println("A1")
}
func A2() {
fmt.Println("A2")
defer B1()
defer B2()
}
func B1() {
fmt.Println("B1")
}
func B2() {
fmt.Println("B2")
}
func main() {
A()
}
// A2
// B2
// B1
// A1
defer1.12(有点儿慢)的性能问题主要缘于两个方面:
-
_defer结构体堆分配,即使有预分配的deferpool,也需要去堆上获取与释放。而且defer函数的参数还要在注册时从栈拷贝到堆,执行时又要从堆拷贝到栈。
-
defer信息保存到链表,而链表操作比较慢。
go1.13优化defer(性能提升30%)
- 避免在堆上分配,分配到栈上(执行阶段会分配在函数栈的局部变量区域),会把栈上分配的_defer结构体注册到defer链表;避免在堆上分配_defer结构体。
- 增加了heap字段,用于标识是否为堆分配。
go1.14优化defer(open coded defer)
- 增加一个标识变量df来解决这类问题,defer函数是否要执行。
- open coded defer。这种方式不仅不用创建_defer结构体,也脱离了defer链表的束缚。不过这种方式依然不适用于循环中的defer,所以1.12版本defer的处理方式是一直保留的。
- 我们一直在梳理的都是程序正常执行时defer的处理逻辑。一旦发生panic或者调用了runtime.Goexit函数,在这之后的正常逻辑就都不会执行了,而是直接去执行defer链表。那些使用open coded defer在函数内展开,因而没有被注册到链表的defer函数要通过栈扫描的方式来发现。
- 实际上Go1.14版本中defer的确变快了,但panic变得更慢了
但是,defer作为一个关键的语言特性,怎能如此受人诟病?所以GO语言在1.13和1.14中做出了不同的优化。
panic 发生错误
recover函数本身的逻辑很简单,它只做一件事,就是把当前执行的panic置为已恢复,也就是把它的_panic.recovered字段置为true,其他的不管。
recover函数 1.17.3可以通过另外的函数间接调用
1.14只能在defer函数中直接调用,不能通过另外的函数间接调用
error:遇到错误用日志打印error
Golang进程权限调度包runtime三大函数Gosched、Goexit、GOMAXPROCS
https://www.cnblogs.com/wt645631686/p/9656046.html
runtime.Gosched(),用于让出CPU时间片,让出当前goroutine的执行权限,调度器安排其它等待的任务运行,并在下次某个时候从该位置恢复执行。这就像跑接力赛,A跑了一会碰到代码runtime.Gosched()就把接力棒交给B了,A歇着了,B继续跑。
runtime.Goexit(),调用此函数会立即使当前的goroutine的运行终止(终止协程),而其它的goroutine并不会受此影响。runtime.Goexit在终止当前goroutine前会先执行此goroutine的还未执行的defer语句。请注意千万别在主函数调用runtime.Goexit,因为会引发panic。
runtime.GOMAXPROCS(),用来设置可以并行计算的CPU核数最大值,并返回之前的值。
默认此函数的值与CPU逻辑个数相同,即有多少个goroutine并发执行,当然可以设置它,它的取值是1~256。最好在主函数在开始前设置它,因为设置它会停止当前程序的运行。
GO默认是使用一个CPU核的,除非设置runtime.GOMAXPROCS
那么在多核环境下,什么情况下设置runtime.GOMAXPROCS会比较好的提高速度呢?
适合于CPU密集型、并行度比较高的情景。如果是IO密集型,CPU之间的切换也会带来性能的损失。
Channel
https://mp.weixin.qq.com/s/6ZEGtXRGKm2qP5b-rGLyVg
https://mp.weixin.qq.com/s/6FbmrrPODId7RZlj2bRUhw
介绍
- 协程之间的通信,按照golang的设计思想:以通信的方式共享内存。
- 本质是数据结构-队列,FIFO
- 线程安全,多个goroutine访问时,不需要加锁,就是说channel本身就是线程安全的(mutex)
- channel有类型的,int类型的只能存放int数据类型
- 引用类型,必须初始化才能写入数据,make后才能使用
make函数会在堆上分配一个runtime.hchan类型的数据结构,ch是存在于函数f栈桢上的一个指针,指向堆上的hchan数据结构。
为什么是堆上一个结构体?因为这种被设计用来实现协程间通信的组件,其作用域和生命周期不可能仅限于某个函数内部,所以gblang直接将其分配在堆上。
func f() { ch := make(chan int) ...}
//channel 数据结构type hchan struct { qcount uint // 数组长度,即已有元素个数 dataqsiz uint // 数组容量,即可容纳元素个数 buf unsafe.Pointer // 数组地址 elemsize uint16 // 元素大小 closed uint32 elemtype *_type // 元素类型 sendx uint // 下一次写下标位置 recvx uint // 下一次读下标位置 recvq waitq // 读等待队列 sendq waitq // 写等待队列 lock mutex}
管道读写,只读,只写
- 读写:var chan1 chan int
- 只读:var chan2 chan<- int
- 只写:var chan3 <-chan int
<- 前只写,后只读
字符串逆序输出
func StrT() { // var str = "255 11 0 81 0 0 92 255 11 0 89 136 209 189" var b, bb []byte // 字符串转字节 // var bytes []byte = []byte(str) b = append(b, 255) b = append(b, 11) b = append(b, 0) b = append(b, 81) b = append(b, 0) b = append(b, 0) b = append(b, 92) for i := 0; i < len(b); i++ { // 定义一个变量存放从后往前的值 tmp := b[len(b)-i-1] // 从后往前的值跟从前往后的值调换 // b[len(b)-i-1] = b[i] // 从前往后的值跟从后往前的值进行调换 bb = append(bb, tmp) } fmt.Println("b",b) fmt.Println(len(b)) fmt.Println("bb",bb) fmt.Println(len(bb))}
string,ASCII码,二进制中的原码、反码、补码
string:go底层存的是data,len
ASCII码:用于显示现代英语,共定义了128个字符。
二进制,逢二进一,可以看做时钟(59->0)。
计算机二进制中的原码,反码,补码 https://www.cnblogs.com/codeshell/p/14023387.html
流程图
https://www.cnblogs.com/tdbk-nwnu/p/9138921.html
git代码冲突
https://git-scm.com/book/zh/v2/Git-工具-高级合并
https://blog.csdn.net/weixin_43867210/article/details/86362640
https://www.cnblogs.com/wteam-xq/p/4122163.html
- 原因多人同时修改了同一个文件
- 养成好习惯,提交前先pull,下班前push代码,上班Pull最新代码
- git diff 或Beyond Compare 3工具对比代码冲突的地方,修改后重新提交
- 代码合并merge
指针偏移
https://blog.csdn.net/u010125463/article/details/46531883
https://blog.csdn.net/cjzjolly/article/details/82116772
在C语言中,每个地址实际上指向一个8bit的内存区,但如果某个内存区的地址使用一个明确的类型指针例如int、long来进行保 存,那么指针偏移时地址的偏移数以类型占的字节数为基本单位进行偏移,例如int p变量+1的时候实际上跳过的是sizeof(int)的类型字节数的地址为单位进行跳跃——也就是跳跃4个地址,但如果是不确认类型的情况下使用void来保存,则必须指定每次跳跃的准确地址数。
接口interface转结构体
data := client.ReceivePTZData()
rdata := data.(dsd.Position)
point.Positions = rdata
定时器
https://www.topgoer.com/并发编程/定时器.html
timer:时间到了,只执行一次。
ticker:时间到了多次执行。