上上周的时候给 ezio 做了一个调整,稍微修改了一下 TCPConnection
对外暴露的几个状态变化的事件。
起因是在写 example/chat-client 的时候,因为主线程单独跑了一个事件循环从 stdin
中读取用户输入,所以 ChatClient
以及内部的 TCPClient
是跑在另外的工作线程上。
因为那个时候 TCPClient
之对外暴露了 connection 和 disconnection 的事件回调(这两个事件还统一成了一个 on_connection()
),所以自然选择在 disconnection 的时候进行退出主循环的操作。
但是这个时候会出现:
ChatClient
,连同内部的 TCPClient
一起销毁。因为这部分代码跑在主线程上,所以不会和工作线程有任何 coordination。TCPClient
会在触发 on_connection()
来表明连接断开后会继续做一些内部清理工作;然而因为前面已经将 TCPClient
析构了,导致 UAF而当时为了解决这个问题,采用的 workaround 时,ChatClient::OnConnection()
在发现连接断开后,通过 RunTaskAfter()
的方式延后执行 EventLoop::Quit()
。
这个做法非常丑陋而且不可靠。
转到后端差不多也快三个月了,拿 golang 糊代码的时间算上自己平时写的一些练手 demo 加起来差不多也有一个月。
这将近一个月的时间过来差不多能体会到 golang 的设计精髓,那就是:simple & stupid, being convenient as the first class support.
换句话说就是:短平快糙猛,满口玻璃渣,怎么方便怎么来。
所以接下来不免俗地是吐槽 golang 设计的内容。
吐槽不考虑 PLT 上的设计,纯粹从日常堆业务逻辑出发。毕竟理论的东西我一个鶸也不懂,且 golang 的设计目的就是方便应届毕业生快速堆业务代码。
以下吐槽点的顺序为自己在实际中遇到的顺序逆序。
golang 里起一个 goroutine 很方便,但是目前感觉 goroutine 太过于 flaky,有点飘。一旦没用 chan struct{}
或者 sync.WaitGroup
”固定好“,就总有一种这玩意儿是不是已经脱离自己手心的感觉。
另外不知道是不是很多用 golang 的人之前都是 php / python 的背景,相当一部分人其实对 goroutine-safe 没有什么概念。不过严格来说这个不是 golang 自身的问题。
代码段
1 | func foobar() (bool, error) { |
是合法的,因为 ok
之前并没有被定义,所以这里 err
可以蹭着使用 :=
。
这篇 post 总结起来就是深入浅出。
The importance of knowing STL algorithms
能熟练运用 STL algorithms 是一个 experienced c++ programmer 的基本要求。
另外里面提到了使用 algorithms 的两个 pitfalls,其中一个是滥用 for_each()
,这个确实有点意思。
原本的计划是今天给 ezio 加上 SIGINT 的处理:自动退出运行的 EventLoop
,让程序自主正常退出;但是在实现 Windows 版本的过程中发现了一些问题,最后思考再三,决定放弃整个特性。
至此,我们整个系列宣告完结。
现在回过头往前看,是不是觉得其实这些底层的东西也没这么难?有时候只是需要一些基础和解决问题的方法罢了。
Rant:做业务才真的难呢,框架和流程都给你定死了,一坨又一坨用了几年的不明觉厉的封装,如果内部文档哪个不详,又没有熟悉的人带着你,基本就净在里面绕圈子了。