广度优先搜索

麻将胡牌算法(包括查听,查胡) package main import ( "fmt" ) func main() { list := []int{11, 12, 13, 14, 14, 15, 16, 12} // lists := combination(list, []int{}) // for k, l := range lists { // fmt.Printf("组合:%v===", k) // for _, c := range l.combin { // fmt.Printf("类型:%v 值:%v;", c.tp, c.values) // } // fmt.Println() // } m := outTS(list) for k, v := range m { fmt.Printf("打出:%v,可以胡%v\n", k, v) } } func outTS(list []int) map[int][]int { var ts = make(map[int][]int, 0) out := make([]int, 0) if len(list)%3 !

Read More →

redis集群学习

redis集群部署运行 以window为例子 首先修改配置文件 redis-cluster.conf 1、配置文件需要配置持久化类型,这里选择aof appendonly yes // 开启aof模式 appendfilename "appendonly.7001.aof" // aof名字 2、集群启动配置 cluster-enabled yes // 允许集群 cluster-config-file nodes-7001.conf // 集群配置文件,运行后自动生成 cluster-node-timeout 15000 // 集群节点响应超时 运行实例 进入redis目录下,运行redis-server.exe ./{“配置文件路径”}/name.conf 需要几个节点,就创建几个redis相关的配置文件,一般来说至少需要要3个master节点,每个主节点需要至少一个slave节点,因此至少需要6个节点 运行成功后只能算是开启了6个redis服务端,还不是集群 关联服务 6个服务端实例有了,就需要关联起来,通过使用 Redis 集群命令行工具 redis-trib 可以进行便携操作。 trib在redis源码中trib地址,将redis-trib.rb文件放到redis安装目录下。 trib是rb(rubby)类型文件,所以需要安装rubby运行环境,rubby安装地址。 在rubby目录下,安装redis驱动:gem install redis redis目录下运行:./redis-trib.rb create –replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005。 此时如果出现如下响应,表示集群关联成功。 Can I set the above configuration? (type ‘yes’ to accept): yes(这里输入yes表示同意设置) C:\Program Files\Redis>redis-trib.rb create --replicas 1 127.

Read More →

tcp异步

tcp异步框架学习 tao框架 evio框架 什么是同步异步 先讲讲同步,同步可以理解为串行,100个人要进入一个空间,可空间入口只有一个,这时候,人们只能排队进入,假设一个人进入需要费时1秒,100个就是100秒,人越多,效率就越低;这时候要解决效率的问题就需要用到异步了。 异步可以理解为并行,为每一个人开辟一个入口,这时候有n个人就会有n个入口,进入的时间永远就只需一秒,这样效率就大大提高了。 异步加锁的必要性 异步解决了进入效率的问题,但人们进入房间是需要做事情的,如果这个事件只是记忆某样东西,不对这个东西进行改变,这时候就没必要加锁,假如空间里面有一堆糖果,100个人里面有50个人的任务只是进来数当前糖果的,这时候就没必要加锁了,而另外50个人的任务是拿糖果,这就有必要加锁了。拿糖果这个任务可以分为两个步骤,先确认是否有糖果,有的话才拿,如果AB两个人通过要执行拿糖果的,AB都确认了有糖果,可是B比A手速要快,先一步把糖果全部拿走了,A再去拿的时候就拿不到了,这时候A的逻辑就会出问题了,他就会一直在那里拿糖果(可永远没有拿到的可能),但是加了锁就不一样了,锁相当于一个闸门,上锁后,只有一个人可以执行任务,其他人只能等待上个人执行完解锁后才能继续去抢锁执行任务。 线程池的概念 异步解决了效率的问题,使空间不再拥堵,但空间再大也会有上限,可是想要进入空间做事情的人是没有上限的,假设这个空间人气很高,一个庞大的人流量都想要进入这个空间做事,如果说为每个人都开辟一个通道,这时候这个空间将面临千疮百孔,濒临崩溃的局面。也许空间加糖果的例子可能还是有点抽象了,这里以银行为例子,银行相当于空间,每一个窗口相当于一个通道,事件相当于不同的业务,在人多的情况下,窗口越多,办理业务的效率也就越高,而对于银行来说,窗口也是有上限的,而且每开一个窗口都需要消耗一定资源(给窗口业务员发工资、窗口设备维护等等)。 线程池的具体设计 上面有提到过无限开启窗口的确定,就是资源消耗的递增,假设银行只有在每个月的最后一天人流量会暴增,为了这一天开启了很多个窗口来提高效率,可是其他的时间里,平均人流量很小,一到两个窗口就能应付,这时候其他的窗口就会无比空闲,假设你是一个精打细算的银行老板,你会容忍其他窗口的无所事事么,要知道维护这些空闲窗口是需要消耗的。 1. 设定一个合理的窗口数,不要为每一个人都开一个窗口,人多的话还是要进行排队,银行就是这样的。。。 2. 合理的窗口数虽然减少了开销,但是作为一个一毛不拔的我,还是觉得浪费了,毕竟在人流量极少的情况下,还是会有无所事事的窗口,这个时候就需要动态的增删窗口了;人流量小的时候,无所事事的窗口关闭,人流量多的时候,增加窗口,极多的时候,那就排队吧。 回归语言 任何事物都是讲究逻辑性的,语言也是符合上面两个例子的逻辑。空间、银行这些都可以看做我们的服务端,而来办理业务的人就是各种携带事件的tcp请求,而窗口就是routine(类型java线程,但比线程的创建消耗要小很多),业务就是你通过routine要异步处理的携带事件。 好的异步协程池 ants框架就是一个非常好用的,对上述所说的动态删减routine,控制routine上限,异步处理事件都有非常好的实现 以下就是个人参考ants框架的举例逻辑实现 // 主函数,模拟1000个事件,交给线程池异步处理,p就是协程池,限制上限10,通过push函数将任何丢到通道中 func main() { for i := 0; i < 1000; i++ { // time.Sleep(2 * time.Millisecond) p.push(Msg{ from: uint64(i), data: "haha", }) } fmt.Println("参与的worker数量:", len(p.workers)) time.Sleep(1 * time.Second) } //这里的push函数,导致的实际效果是每次是放一个事件进来等待空闲routine进行处理,一对多 //而ants作者的逻辑效果是一群事件在那里等待争抢空闲routine,多对多 //从逻辑性来开ants作者的逻辑效率会更高 type Pool struct { max uint64 workers []*Worker //存放工作者 chl chan Msg lock sync.

Read More →

tcp长连接压测遇到的问题

tcp长连接压测遇到的问题 问题1:在大量长连接下,会出现很多拨号失败。 、、、 dial tcp 192.168.31.232:6001: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 、、、 拨号失败的问题在于服务端响应不及时 问题分析:在大量长连接同时请求时,出现了cpu、资源调用阻塞,很多的连接在等待分配 解决办法:轮询创建客户端加上延时 问题2:部分连接成功的客户端,会在请求的时候得不到相应的响应 目前的模拟客户端设置的时1分钟的超时,在5000长连接的压测下,30s的超时设置,会出现n个超时,1分钟的超时设置,超时的客户端会减少 问题分析:估计也是资源占用造成的问题 解决办法:加大服务器内核 问题3:部分连接成功的客户端,请求后被告知连接被远程端强制关闭,但服务端却没有主动关闭连接的操作 客户端已经dial成功,但通过返回的conn进行write和read操作被告知连接强制关闭,但服务端没有任何close迹象 原因分析:dial是在第二次握手的时候返回conn,而服务端accept是在第三次握手的时候返回conn,也就是说握手只进行到第二次握手, 这是因为握手的时候有两个队列,一个syn队列一个backlog队列(accept队列),一次握手,cli告诉ser要建立连接,第二次握手,ser通知 cli等待确认连接,这时连接状态进入syn队列,第三次握手,cli通知ser确认连接,连接状态进入backlog队列。 以上就是握手的过程,syn和backlog队列有限制,如果在大量并发连接出现,连接数超过backlog的长度的连接,将会阻塞在队列外,一定时间没有进入到backlog队列,连接将会被丢弃,这就出现了客户端dail成功,而服务端却没有accept。 解决办法:修改服务器内核配置,syn队列上限: /proc/sys/net/core/somaxconn;accept队列上限:/proc/sys/net/ipv4/tcp_max_syn_backlog

colly源码包分析

基本用法 infos := make([]info, 0) c := colly.NewCollector() c.OnHTML(".content div .rprt", func(e *colly.HTMLElement) { title := e.ChildText(".rslt p.title a") author := e.ChildText(".supp .desc") message := e.ChildText(".supp .details") pmid := e.ChildText(".aux .resc .rprtid dd") id, _ := strconv.ParseInt(pmid, 10, 64) i := info{ title: strings.TrimRight(title, "."), author: author, message: message, pmid: id, } infos = append(infos, i) }) c.OnRequest(func(req *colly.Request) { log.Println("Visit:", req.URL.String()) }) c.Post("https://www.ncbi.nlm.nih.gov/pubmed", map[string]string{ "term": "kif15", "p$a": strconv.

Read More →

golang标准包分析—http

服务端 服务端是用来接收连接的,因此需要一个监听的逻辑 // 函数ListenAndServe用来开启服务并且监听,而这个 // 函数的核心就是tcp连接,通过net.Listen(param1,param2)得到listener // 其中param1是连接类型,可以有tcp,tcp4,tcp6......,param2则是服务地址:ip:port // 返回的listener是一个interface{}类型 type Listener interface { // Accept waits for and returns the next connection to the listener. Accept() (Conn, error) // Close closes the listener. // Any blocked Accept operations will be unblocked and return errors. Close() error // Addr returns the listener's network address. Addr() Addr } 只要实现了Listener的三个函数的结构体,都能作为返回参数,以param1=tcp为例子,将会返回TCPListener // TCPListener is a TCP network listener. Clients should typically // use variables of type Listener instead of assuming TCP.

Read More →

ssh连接

ssh连接服务器 ssh name@host // 如果默认端口不是22,则需要在连接的时候带上参数-P ssh -P 2222 name@host ssh上传文件以及下载文件 // 从本地上传文件 scp localPath/file name@host:/home/src // 意思是将本地路径localPath下的file文件上传到服务器的home/src文件夹下 // 从服务器下载文件 scp name@host:/home/src/file localPath // 意思是将服务器home/src路径下的file文件下载到本地localPath路径下 以上只适合linux系统,如果window想要使用,有两种办法 使用git bash,git bash可以使用ssh以及scp命令 下载pscp,pscp是window下操作的命令,替换scp可以进行相同操作,pscp需要添加到环境变量 pscp下载路径

干货达人网址链接

GitHub上优秀的Go开源项目 awesome优秀框架分享(英文版) awesome优秀框架分享(中文版) github上优秀的储存框架

golang标准包分析—bytes

bytes包对外提供的函数 这里将函数分为两类,一类是汇编(这种只需要明白用法就行),一类是使用代码实现的(这种需要好好学习) // Index returns the index of the first instance of sep in s, or -1 if sep is not present in s. func Index(s, sep []byte) int {```} 这个函数内部的核心函数是bytealg.Index(),此函数属于汇编类型,用处就是返回首个存在于s中的sep实例的索引,如果不存在返回-1 // Compare returns an integer comparing two byte slices lexicographically. // The result will be 0 if a==b, -1 if a < b, and +1 if a > b. // A nil argument is equivalent to an empty slice.

Read More →

golang标准包分析—archive

zip 使用方法 写 // 写到文件中 src,err := os.Create("/name.zip") if err != nil{ return } w := zip.NewWriter(src) // 给写入的文件写名字,Create()函数,默认的压缩方式是deflate,需要选择压缩方式可以用CreateHeader() // Store uint16 = 0 // no compression // Deflate uint16 = 8 // DEFLATE compressed f,err := w.Create("name") if err != nil{ return } //将内容写入相应的文件中,data是二进制字节流 _,err:=f.write(data) if err != nil { return } // 写完后,需要注意关闭w w.Close() err := w.Close() if err != nil { log.Fatal(err) } 读(常用就是解压缩) // OpenReader 打开要读取的zip,path:zip文件路径 rc ,err := zip.

Read More →