go语言reset方法,go get 语法
golang中bufio包
一、介绍go标准库中的bufio
创新互联-专业网站定制、快速模板网站建设、高性价比迎泽网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式迎泽网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖迎泽地区。费用合理售后完善,10多年实体公司更值得信赖。
最近用golang写了一个处理文件的脚本,由于其中涉及到了文件读写,开始使用golang中的 io 包,后来发现golang 中提供了一个bufio的包,使用这个包可以大幅提高文件读写的效率,于是在网上搜索同样的文件读写为什么bufio 要比io 的读写更快速呢?根据网上的资料和阅读源码,以下来详细解释下bufio的高效如何实现的。
bufio 包介绍
bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象。
以上为官方包的介绍,在其中我们能了解到的信息如下:
bufio 是通过缓冲来提高效率
简单的说就是,把文件读取进缓冲(内存)之后再读取的时候就可以避免文件系统的io 从而提高速度。同理,在进行写操作时,先把文件写入缓冲(内存),然后由缓冲写入文件系统。看完以上解释有人可能会表示困惑了,直接把 内容-文件 和 内容-缓冲-文件相比, 缓冲区好像没有起到作用嘛。其实缓冲区的设计是为了存储多次的写入,最后一口气把缓冲区内容写入文件。下面会详细解释
bufio 封装了io.Reader或io.Writer接口对象,并创建另一个也实现了该接口的对象
io.Reader或io.Writer 接口实现read() 和 write() 方法,对于实现这个接口的对象都是可以使用这两个方法的
注明:介绍内容来自博主 LiangWenT
,原文链接: ,在查找资料时,发现这篇博客的内容很好理解
bufio包实现了缓存IO。它包装了io.Reader和io.Write对象,创建了另外的Reader和Writer对象,它们也实现了io.Reader和io.Write接口,具有缓存。注意:缓存是放在主存中,既然是保存在主存里,断电会丢失数据,那么要及时保存数据。
二、常用内容
1、Reader类型
NewReaderSize
作用:NewReaderSize将rd封装成一个带缓存的bufio.Reader对象。缓存大小由size指定(如果小于16则会被设为16)。如果rd的基类型就是有足够缓存的bufio.Reader类型,则直接将rd转换为基类型返回。
NewReader
funcReader相当于NewReaderSize(rd, 4096)
Peek
Peek返回缓存的一个切片,该切片引用缓存中前n个字节的数据,该操作不会将数据读出,只是引用,引用的数据在下一次读取操作之前有效的。如果切片长度小于n,则返回一个错误信息说明原因。如果n大于缓存的总大小,则返回ErrBufferFull。
Read
Read从b中数据到p中,返回读出的字节数和遇到的错误。如果缓存不为空,则只能读出缓冲中的数据,不会从底层io.Reader中提取数据,如果缓存为空,则:
1、len(p) = 缓存大小,则跳过缓存,直接从底层io.Reader中读出到p中
2、len(p) 缓存大小,则先将数据从底层io.Reader中读取到缓存中,再从缓存读取到p中。
Buffered
Buffered返回缓存中未读取的数据的长度。
Discard
Discard跳过后续的n个字节的数据,返回跳过的字节数。
Writer类型和方法
write结构
NewWriteSize
NewWriterSize将wr封装成一个带缓存的bufio.Writer对象,缓存大小由size指定(如果小于4096则会被设置未4096)。
NewWrite
NewWriter相等于NewWriterSize(wr, 4096)
WriteString
WriteString功能同Write,只不过写入的是字符串
WriteRune
WriteRune向b写入r的UTF-8编码,返回r的编码长度。
Flush
Available
Available 返回缓存中未使用的空间的长度
Buffered
Buffered返回缓存中未提交的数据长度
Reset
Reset将b的底层Write重新指定为w,同时丢弃缓存中的所有数据,复位所有标记和错误信息。相当于创建了一个新的bufio.Writer。
GO中还提供了Scanner类型,处理一些比较简单的场景。如处理按行读取输入序列或空格分隔的词等。
内容来自:
参考链接:
1)
2)
go语言的reflect(反射)
1、反射可以在运行时 动态获取变量的各种信息 ,比如变量的类型、类别;
2、如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法);
3、通过反射,可以修改 变量的值 ,可以调用关联的方法;
4、使用反射,需要import " reflect ".
5、示意图:
1、不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射。
例如以下这种桥接模式:
示例第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数。
1、reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型。
2、reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型reflect.Value是一个结构体类型。
3、变量、interface{}和reflect.Value是可以互相转换的,这点在实际开发中,会经常使用到。
1、reflect.Value.Kind,获取变量的 类别(Kind) ,返回的是一个 常量 。在go语言文档中:
示例如下所示:
输出如下:
Kind的范畴要比Type大。比如有Student和Consumer两个结构体,他们的 Type 分别是 Student 和 Consumer ,但是它们的 Kind 都是 struct 。
2、Type是类型,Kind是类别,Type和Kind可能是相同的,也可能是不同的。
3、通过反射可以在让 变量 在 interface{} 和 Reflect.Value 之间相互转换,这点在前面画过示意图。
4、使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,那么久应该使用reflect.Value(x).Int(),而不能使用其它的,否则报panic。
如果是x是float类型的话,也是要用reflect.Value(x).Float()。但是如果是struct类型的话,由于type并不确定,所以没有相应的方法,只能 断言。
5、通过反射的来修改变量,注意当使用SetXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的变量的值,同时需要使用到reflect.Value.Elem()方法。
输出num=20,即成功使用反射来修改传进来变量的值。
6、reflect.Value.Elem()应该如何理解?
go面试题整理(附带部分自己的解答)
原文:【 】
如果有解答的不对的,麻烦各位在评论写出来~
go的调度原理是基于GMP模型,G代表一个goroutine,不限制数量;M=machine,代表一个线程,最大1万,所有G任务还是在M上执行;P=processor代表一个处理器,每一个允许的M都会绑定一个G,默认与逻辑CPU数量相等(通过runtime.GOMAXPROCS(runtime.NumCPU())设置)。
go调用过程:
可以能,也可以不能。
因为go存在不能使用==判断类型:map、slice,如果struct包含这些类型的字段,则不能比较。
这两种类型也不能作为map的key。
类似栈操作,后进先出。
因为go的return是一个非原子性操作,比如语句 return i ,实际上分两步进行,即将i值存入栈中作为返回值,然后执行跳转,而defer的执行时机正是跳转前,所以说defer执行时还是有机会操作返回值的。
select的case的表达式必须是一个channel类型,所有case都会被求值,求值顺序自上而下,从左至右。如果多个case可以完成,则会随机执行一个case,如果有default分支,则执行default分支语句。如果连default都没有,则select语句会一直阻塞,直到至少有一个IO操作可以进行。
break关键字可跳出select的执行。
goroutine管理、信息传递。context的意思是上下文,在线程、协程中都有这个概念,它指的是程序单元的一个运行状态、现场、快照,包含。context在多个goroutine中是并发安全的。
应用场景:
例子参考:
waitgroup
channel
len:切片的长度,访问时间复杂度为O(1),go的slice底层是对数组的引用。
cap:切片的容量,扩容是以这个值为标准。默认扩容是2倍,当达到1024的长度后,按1.25倍。
扩容:每次扩容slice底层都将先分配新的容量的内存空间,再将老的数组拷贝到新的内存空间,因为这个操作不是并发安全的。所以并发进行append操作,读到内存中的老数组可能为同一个,最终导致append的数据丢失。
共享:slice的底层是对数组的引用,因此如果两个切片引用了同一个数组片段,就会形成共享底层数组。当sliec发生内存的重新分配(如扩容)时,会对共享进行隔断。详细见下面例子:
make([]Type,len,cap)
map的底层是hash table(hmap类型),对key值进行了hash,并将结果的低八位用于确定key/value存在于哪个bucket(bmap类型)。再将高八位与bucket的tophash进行依次比较,确定是否存在。出现hash冲撞时,会通过bucket的overflow指向另一个bucket,形成一个单向链表。每个bucket存储8个键值对。
如果要实现map的顺序读取,需要使用一个slice来存储map的key并按照顺序进行排序。
利用map,如果要求并发安全,就用sync.map
要注意下set中的delete函数需要使用 delete(map) 来实现,但是这个并不会释放内存,除非value也是一个子map。当进行多次delete后,可以使用make来重建map。
使用sync.Map来管理topic,用channel来做队列。
参考:
多路归并法:
pre class="vditor-reset" placeholder="" contenteditable="true" spellcheck="false"p data-block="0"(1)假设有K路a href=""数据流/a,流内部是有序的,且流间同为升序或降序;
/pp data-block="0"(2)首先读取每个流的第一个数,如果已经EOF,pass;
/pp data-block="0"(3)将有效的k(k可能小于K)个数比较,选出最小的那路mink,输出,读取mink的下一个;
/pp data-block="0"(4)直到所有K路都EOF。
/p/pre
假设文件又1个G,内存只有256M,无法将1个G的文件全部读到内存进行排序。
第一步:
可以分为10段读取,每段读取100M的数据并排序好写入硬盘。
假设写入后的文件为A,B,C...10
第二步:
将A,B,C...10的第一个字符拿出来,对这10个字符进行排序,并将结果写入硬盘,同时记录被写入的字符的文件指针P。
第三步:
将刚刚排序好的9个字符再加上从指针P读取到的P+1位数据进行排序,并写入硬盘。
重复二、三步骤。
go文件读写参考:
保证排序前两个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同的排序叫稳定排序。
快速排序、希尔排序、堆排序、直接选择排序不是稳定的排序算法。
基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序是稳定的排序算法。
参考:
head只请求页面的首部。多用来判断网页是否被修改和超链接的有效性。
get请求页面信息,并返回实例的主体。
参考:
401:未授权的访问。
403: 拒绝访问。
普通的http连接是客户端连接上服务端,然后结束请求后,由客户端或者服务端进行http连接的关闭。下次再发送请求的时候,客户端再发起一个连接,传送数据,关闭连接。这么个流程反复。但是一旦客户端发送connection:keep-alive头给服务端,且服务端也接受这个keep-alive的话,两边对上暗号,这个连接就可以复用了,一个http处理完之后,另外一个http数据直接从这个连接走了。减少新建和断开TCP连接的消耗。这个可以在Nginx设置,
这个keepalive_timout时间值意味着:一个http产生的tcp连接在传送完最后一个响应后,还需要hold住keepalive_timeout秒后,才开始关闭这个连接。
特别注意TCP层的keep alive和http不是一个意思。TCP的是指:tcp连接建立后,如果客户端很长一段时间不发送消息,当连接很久没有收到报文,tcp会主动发送一个为空的报文(侦测包)给对方,如果对方收到了并且回复了,证明对方还在。如果对方没有报文返回,重试多次之后则确认连接丢失,断开连接。
tcp的keep alive可通过
net.ipv4.tcp_keepalive_intvl = 75 // 当探测没有确认时,重新发送探测的频度。缺省是75秒。
net.ipv4.tcp_keepalive_probes = 9 //在认定连接失效之前,发送多少个TCP的keepalive探测包。缺省值是9。这个值乘以tcp_keepalive_intvl之后决定了,一个连接发送了keepalive之后可以有多少时间没有回应
net.ipv4.tcp_keepalive_time = 7200 //当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时。一般设置为30分钟1800
修改:
可以
tcp是面向连接的,upd是无连接状态的。
udp相比tcp没有建立连接的过程,所以更快,同时也更安全,不容易被攻击。upd没有阻塞控制,因此出现网络阻塞不会使源主机的发送效率降低。upd支持一对多,多对多等,tcp是点对点传输。tcp首部开销20字节,udp8字节。
udp使用场景:视频通话、im聊天等。
time-wait表示客户端等待服务端返回关闭信息的状态,closed_wait表示服务端得知客户端想要关闭连接,进入半关闭状态并返回一段TCP报文。
time-wait作用:
解决办法:
close_wait:
被动关闭,通常是由于客户端忘记关闭tcp连接导致。
根据业务来啊~
重要指标是cardinality(不重复数量),这个数量/总行数如果过小(趋近于0)代表索引基本没意义,比如sex性别这种。
另外查询不要使用select *,根据select的条件+where条件做组合索引,尽量实现覆盖索引,避免回表。
僵尸进程:
即子进程先于父进程退出后,子进程的PCB需要其父进程释放,但是父进程并没有释放子进程的PCB,这样的子进程就称为僵尸进程,僵尸进程实际上是一个已经死掉的进程。
孤儿进程:
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
子进程死亡需要父进程来处理,那么意味着正常的进程应该是子进程先于父进程死亡。当父进程先于子进程死亡时,子进程死亡时没父进程处理,这个死亡的子进程就是孤儿进程。
但孤儿进程与僵尸进程不同的是,由于父进程已经死亡,系统会帮助父进程回收处理孤儿进程。所以孤儿进程实际上是不占用资源的,因为它终究是被系统回收了。不会像僵尸进程那样占用ID,损害运行系统。
原文链接:
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免方法:
端口占用:lsof -i:端口号 或者 nestat
cpu、内存占用:top
发送信号:kill -l 列出所有信号,然后用 kill [信号变化] [进程号]来执行。如kill -9 453。强制杀死453进程
git log:查看提交记录
git diff :查看变更记录
git merge:目标分支改变,而源分支保持原样。优点:保留提交历史,保留分支结构。但会有大量的merge记录
git rebase:将修改拼接到最新,复杂的记录变得优雅,单个操作变得(revert)很简单;缺点:
git revert:反做指定版本,会新生成一个版本
git reset:重置到某个版本,中间版本全部丢失
etcd、Consul
pprof
节省空间(非叶子节点不存储数据,相对b tree的优势),减少I/O次数(节省的空间全部存指针地址,让树变的矮胖),范围查找方便(相对hash的优势)。
explain
其他的见:
runtime2.go 中关于 p 的定义: 其中 runnext 指针决定了下一个要运行的 g,根据英文的注释大致意思是说:
所以当设置 runtime.GOMAXPROCS(1) 时,此时只有一个 P,创建的 g 依次加入 P, 当最后一个即 i==9 时,加入的最后 一个 g 将会继承当前主 goroutinue 的剩余时间片继续执行,所以会先输出 9, 之后再依次执行 P 队列中其它的 g。
方法一:
方法二:
[图片上传失败...(image-4ef445-1594976286098)]
方法1:to_days,返回给的日期从0开始算的天数。
方法2:data_add。向日期添加指定时间间隔
[图片上传失败...(image-b67b10-1594976286098)]
当前题目:go语言reset方法,go get 语法
当前路径:http://scjbc.cn/article/hsddhp.html