深圳公司广告片制作新网站做seo 的效果
2026/3/9 17:51:31 网站建设 项目流程
深圳公司广告片制作,新网站做seo 的效果,wordpress国际主题,去掉wordpress页面的分类归档在上一篇文章和这个之间还有一个41-用户业务封装#xff0c;这一块我觉得主要就是OOP封装思想的体现#xff0c;没有涉及过多的Go语言特性#xff0c;所以就略过代码解析了。这一篇对应的是在线用户查询和修改用户名的业务逻辑#xff0c;因为代码比较简单#xff0c;流程…在上一篇文章和这个之间还有一个41-用户业务封装这一块我觉得主要就是OOP封装思想的体现没有涉及过多的Go语言特性所以就略过代码解析了。这一篇对应的是在线用户查询和修改用户名的业务逻辑因为代码比较简单流程相似合并在一篇中解析。代码是在进行业务封装的基础之上的。本期课件视频42-在线用户查询43-修改用户名代码packagemainimport(netstrings)typeUserstruct{NamestringAddrstringCchanstringconn net.Conn server*Server}func(this*User)Online(){this.server.mapLock.Lock()this.server.OnlineMap[this.Name]this this.server.mapLock.Unlock()//广播当前用户上线消息this.server.BroadCast(this,已上线)}func(this*User)Offline(){this.server.mapLock.Lock()delete(this.server.OnlineMap,this.Name)this.server.mapLock.Unlock()this.server.BroadCast(this,下线)}func(this*User)SendMessage(msgstring){this.conn.Write([]byte(msg))}func(this*User)DoMessage(msgstring){ifmsgwho{//定义通讯规则如果用户输入who则表示查询在线用户this.server.mapLock.Lock()for_,usr:rangethis.server.OnlineMap{onlineMsg:[usr.Addr]usr.Name在线...\nthis.SendMessage(onlineMsg)}this.server.mapLock.Unlock()}elseiflen(msg)7msg[:7]rename|{//定义通信协议如果用户以rename|XXX这种格式输入则表示要修改用户名newName:strings.Split(msg,|)[1]_,ok:this.server.OnlineMap[newName]ifok{this.SendMessage(当前用户名被占用\n)}else{this.server.mapLock.Lock()delete(this.server.OnlineMap,this.Name)this.server.OnlineMap[newName]this this.server.mapLock.Unlock()this.NamenewName this.SendMessage(更新用户名成功this.Name\n)}}else{this.server.BroadCast(this,msg)}}funcNewUser(conn net.Conn,server*Server)*User{userAddr:conn.RemoteAddr().String()user:User{Name:userAddr,Addr:userAddr,C:make(chanstring),conn:conn,server:server,}//启动监听当前user channel的goroutinegouser.ListenMessage()returnuser}func(this*User)ListenMessage(){for{msg:-this.C this.conn.Write([]byte(msg\n))}}逐行解析这两个功能主要涉及的就是DoMessage方法中的if分支。this.server.mapLock.Lock()因为要对OnlineMap进行遍历而这个DoMessage方法是在协程中执行的因此是并发环境。Go 中的map不带锁不是Java那种ConcurrentHashMap因此读写要上锁for _, usr : range this.server.OnlineMap这句是对map 进行遍历range 是Go语言的关键字它会根据你遍历的对象类型返回不同数量和含义的值。相当于比Java的iterator 封装级别更高的指令对于Java来说每一种容器的遍历代码是要自己写的但是Go 把它们都封装成了range关键词编译器会根据具体遍历的对象执行遍历并返回每个元素的副本。比如map 返回的是两个值K, V。如果要忽略返回值则需要用_下划线占位。注意for i : range slice表示只拿索引_, ok : this.server.OnlineMap[newName]这是Go 语言中处理 Map的一种语法通常被称为 “comma ok” 断言。ok 代表着一个bool 类型的值。在Go 中访问map 中的Key会返回两个值一个是Value如果不存在是零值一个是布尔类型表示是否存在存在时true。当前代码表示不关系返回的具体值而是更关注是否存在。delete(this.server.OnlineMap, this.Name)delete() 和make()一样是Go 语言的内置函数作用是删除map 中的key。如果key 不存在什么都不做也不报错。而且这个函数没有返回值一些问题为什么 SendMessage 是安全的内部执行的是 this.conn.Write()。非 Channel 阻塞conn.Write 是直接将数据写入 TCP 缓冲区。虽然缓冲区满了也会阻塞但它不依赖另一个 Goroutine 的配合。在并发编程中有一条铁律持锁期间绝对不要执行任何可能导致永久阻塞的操作如无缓冲 Channel、远程网络请求等。对于onlineMsg只发送在线信息给当前用户this.SendMessage(onlineMsg) 为什么不能是this.C - onlineMsg这个是我自己写代码的时候的直觉this.C - onlineMsg是一种跨协程的同步行为在持有全局锁时做这件事极其危险。可能会造成死锁。这里C是一个无缓冲channel, 即写入是阻塞的直到读取发生。读取指的是ListenMessage在另一个协程里跑的。那么如果在持有 mapLock 的时候去写一个可能导致阻塞的 chan而此时ListenMessage因为某种原因阻塞了无法读取那么mapLock 这个全局锁就无法释放这个服务会卡死。什么是死锁两个或多个进程协程在执行过程中因争夺资源而造成的一种互相等待的现象若无外力作用它们都将无法推进下去。不是只有传统的经典死锁两个锁互相把自己锁死了解不开才叫死锁。学术上死锁必须满足四个条件互斥mapLock 只能被一个协程持有。占有且等待DoMessage 占有了锁同时在等待 Channel 写入。不可剥夺锁一旦被占有除非自己释放别人抢不走。循环等待A 等 B 读 ChannelB 等网络或 A 释放锁后产生的后续动作。如果在 range 循环遍历 Map 的过程中执行 delete 操作会像 Java 那样抛出 ConcurrentModificationException 吗不会。在 Go 语言中在 range 循环里 delete 当前 Map 的 Key 是绝对安全的不会抛出任何异常。Java 报异常是因为在for 循环中低层对map 的遍历有一个modCount值比较如果值不相等则抛异常。但是Go在range设计的时候就考虑到了这一点Go 在开始 range 循环时并不是对整个 Map 做了一个快照而是通过一个专门的迭代器结构体来跟踪进度当迭代器移动到下一个“桶”Bucket时它只关心当前桶里还剩下什么。如果你刚刚删除了某个桶里的数据迭代器只会简单地跳过它继续寻找下一个有效数据。此时只能说明在同一个协程内部边删边查实不会报错的但是在并发场景下不能一个协程删除另一个协程查询。此时要对被并发协程访问的map上锁。今天遇到一个主要的问题是并发模型的问题。其它的疑问不是很多。写到今天的时候已经对Go语言的简洁有所领悟了因为发现代码已经可以上手了……这要是Java那还差得多呢……

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询