编程往事

其他

2004年:当CPU温和地走入那个良夜

开场白提起1994年,你会想起那时在世界电影史上都大放异彩的一年的,那一年国外影坛神仙打架,《阿甘正传》、《肖申克的救赎》、《这个杀手不太冷》等等横空出世,中国也有《重庆森林》、《活着》这样的佳作。而2004年在你印象里有什么记忆深刻之处呢?好像没有,2004年在大多人眼里是平平无奇的一年。然而却消无声息地开始改变了后来很多程序员的命运,一直影响到现在,尽管当中的很多人都不自知。这一切的源头都是CPU。摩尔定律与登纳德微缩定律摩尔定律(Moore's
2021年12月12日
其他

C++ Trick:什么时候需要前置声明?

经常有C++开发的小伙伴提问:C++中要使用类A时,什么时候#include
2021年12月8日
其他

C++为什么要弄出虚表这个东西?

ABI(适用于gcc和clang)。从C的POD类型到C++的类首先回顾一下C语言纯POD的结构体(struct)。如果用C语言实现一个类似面向对象的类,应该怎么做呢?写法一#include
2021年12月1日
其他

C++服务性能优化的道与术-道篇:google benchmark的安装与使用

如果你实现一个公共的工具函数,有多种实现方式,你怎么测试性能呢?是循环多少次,然后打印一下起止时间,计算耗时吗?这样当然没问题。但是每次都类似的需求,都会写很多冗余的代码来进行耗时统计,另外也缺乏灵活性。有没有方便的方式来测试呢?有,Google家的benchmark性能测试框架。编译安装google
2021年11月30日
其他

C++的lambda是函数还是对象?

关于C++的lambda是函数还是对象,这其实不是一个一概而论的问题。先说结论:对于有捕获的lambda,其等价于对象。对于没有任何捕获的lambda,其等价于函数!首先,很多C++程序员从lambda
2021年11月21日
其他

C/C++为什么要专门设计个do…while?

(false);下面言归正传,关于这个用法,其实我在之前这篇文章的条款7也介绍过了。C++代码简化之道(一)概括一下,函数(或方法)中一段顺序逻辑,依次经历1,2,3三个步骤,然后是其他逻辑(比如
2021年11月15日
其他

brpc小课堂:从StringPiece说开来

序言何谓StringPiece?StringPiece的常见使用场景源码剖析StringPieceBasicStringPiece模板构造函数容量相关函数数据修改函数修改其他字符串的函数数据访问函数比较函数查找函数截取子串返回string对象从StringPiece到string_view备胎转正API的差异如果你没有C++14/17序言在brpc源码的src目录下,有一级子目录名为butil。代码中的util目录一般就是存放常用的工具类或函数的地方。今天我们来聊一下butil/strings/string_piece.h(cpp)
2021年11月14日
其他

白嫖Github的Action做定时任务

废话开篇从大学开始我就有购买云主机的习惯,阿里云、腾讯云都用过。使用云主机的目的,主要是我在大学时代就厌倦了桌面Linux,所以回归到了Windows和Mac的温暖怀抱。但因为工作环境一般都是Linux的,我还是需要有一个Linux的环境让我可以在业余时间继续学习研究。另外我也尝试过自己搭建独立博客等等。刚开始的时候因为学生优惠,一年花不了几个钱。工作以后在腾讯上班,经常使用公司的月度福利(有腾讯云代金券)来给云主机续费,倒也不觉得贵。离开腾讯后我仍然坚持用腾讯云,每年续费。直到今年……我发现每年续费都要上千元,并且这只是一个十分低配的系统。1核、2G内存……
2021年11月5日
其他

STL中有哪些副作用或稍不注意会产生性能开销的地方?

STL中稍不注意会产生性能开销的地方STL容器的clear的时间复杂度不是O(1)可能很多人都不在意,在使用STL容器的时候,潜意识里面将clear()成员函数视为常量时间复杂度O(1)的。但是其实不然。我感觉可能是很多人都知道对于vector而言,clear()之后,修改了size()的结果,不影响capacity()的结果,因而得出clear()只是修改了某个标记,是常量时间复杂度的错误结论。其实C++标准明确指出不管是序列容器(比如vector)还是关联容器(比如unordered_map)其clear()成员函数都是线性时间复杂度O(n)的。因为只要执行了clear()就需要对其存储的元素调用析构函数,这个析构操作显然是逐个析构的。因而时间复杂度是O(n)。当然在实践中,也有个例。比如当vector存储基本数据类型或POD类型(比如基本数据类型构成的struct)的时候,由于其元素类型没有析构函数(也不需要析构函数),加之vector内部连续存储的特性,编译器的实现是可以在常量时间完成clear()的。Linear
2021年10月30日
其他

算法小白如何高效刷LeetCode?

心理建设篇在讲述具体的方法之前,先要明白一件事。凡事都分『道』与『术』。本问题下面大部分回答介绍的都是『术』。而对于刷LeetCode这件事,无论你看到多少高明的的方法,如果你不能持之以恒,都没有用。所有在刷LeetCode这件事上,他的『道』就是:如何能持之以恒的保持刷题热情。我认为『道』更重要。我先谈一下这部分。寻找标尺,让进步可衡量为什么王者荣耀有段位,有青铜、白银、黄金。以我个人的经验来看,这些都是刺激你持续玩游戏的游戏机制。通过段位,彰显个人的实力,没错,装逼是人类进步的一大动力。同时也让进步可以衡量。刷LeetCode也是同样,一般刚开始我们会关注解决了多少道题。更进一步,我们需要关心自己的排名。LeetCode也有排名机制。每刷一道题,就前进一点点。可以每周给自己做一个记录,记一下自己的排名。让自己重视排名。逐渐的自己就会把积极性调动起来,想让自己的排名越来越高,就是打排位一样。除了排名,你还可以每周记录一下通过率。寻找小惊喜,给自己正反馈坚持做每日一题,LeetCode每天都有一道题,完成后,你的打卡日历就会勾上一个圈。如果打满一个月就会获得一个月度徽章。另外LeetCode有很多“学习计划”,每个学习计划完成后也会有一个徽章。我有段时间就喜欢收集徽章,为了收集这些小玩意,会刺激自己持续解题。其实和游戏里面也差不多。学会游戏化学习。不要死磕,学会放弃开始刷LeetCode感到吃力是正常的。我这里说的学会放弃,不是说放弃刷力扣,而是说碰到自己无法解决的题目,不要死磕。赶紧看一下题解去学习,这没有什么丢人的。每个人都是从这个阶段过来的。就比如小学生无法做出高中生的题目,并不是因为小学生笨,而是因为中间有很多知识,小学生没学过。对于算法而言,自然也是如此。靠自己死磕,是很难想到很多前辈科学家们总结出来的算法。这时候去看题解学习也不为过。如果遇到特别难的题,看题解也不理解。也不用纠结。就隔着它。可以把题号记下来。过段时间再回顾。好记性不如烂笔头我是笔记强迫症患者……我现在刷LeetCode,每道做过的题,我都会记到Notion里。打上几个标签,方便回顾。记忆是有遗忘曲线的,不能因为你现在能做出一道题,就认为自己能永远做出来。小学时,老师就教导我们:好记性不如烂笔头讲完『道』,我也谈一下我的『术』。我这里不对具体的算法和数据结构题型做解析了,我主要给你指路。我伸手给你指路,希望你看见的是路,而不是我的手刷题顺序篇当然我不建议从头按顺序刷,我分为“正排”刷题和“倒排”刷题,两种策略。所谓“正排刷题”可以刷LeetCode上面的题单。我个人建议从《剑指Offer》开始刷。《剑指Offer》现有出了两册,在LeetCode上都有题单。建议从《剑指Offer》刷起,碰到不会的,可以看书中的讲解。根据书来刷题,当你刷完一本书后,常见的题目类型几乎都覆盖到了。当然同一种类型的题目数不胜数,重要是培养一下各种题型大概的思路。这属于“正排”刷题。“倒排”刷题,是打破常规,不根据题目类型或按照某种顺序来做题。玩的就是措手不及。比如坚持做每日一题。坚持一个月你就会见到各种各样的题型,有的甚至很刁钻。方便查漏补缺。另外如果有信心的话,可以参加一下周赛,进一步给自己惊喜。网站/APP使用篇自定义测试用例不要着急提交代码。多用测试用例自测。如果是提交之后发现某个case不过,调试的时候一定要在测试用例这里调试。不要用重复提交代码的方式调试。每次提交代码都会跑N多个case,时间慢。另外就是会降低你在LeetCode上的“通过率”高效安排刷题时间如果你是学生,那么恭喜你有一大把的时间用来刷题。但是如果你是已工作人士,则需要高效利用时间了。由于我经常做每日一题,而每日一题,是零点更新。有时候躺在床上没睡,就用力扣APP打开看一眼题目,如果题目不难,就直接用APP刷了。另外你也可以利用上下班通勤的时间、出去玩乘坐地铁、公交的时间来用手机看看题解,或者直接用手机刷。比如我坐长途车从家里回北京的路上就用手机刷过题。手机刷题,其实官方APP,有很多编程语言中的特殊符号的候选功能,可以加快不少手机输入的速度。另外你可以给你的输入法用自定义,加入一些常用的代码,进一步提高手机输入的效率。Trick篇修改函数参数leetcode的参数名,有时候很长,你可以改名字,减少输入的字符数。当然正常在网站上刷题有补全功能。但是改一下名字,还是简化不少。另外就是有两个例外情况是没有补全的:手机刷题(力扣手机APP可以刷题,但是没有补全功能)参加周赛(周赛IDE,无自动补全功能)调用待补全函数自身如果函数的参数是等价的,但是你根据某种策略,把他们分出来差别。但是你不确定哪个参数是满足的。比如这道:415.
2021年10月19日
其他

从旁观者到committer,我与brpc的故事

Apache是知名的开源软件基金会,旗下管理着众多流行的开源项目。如果你有给开源项目贡献过代码,那么你就可以称得上是一名开源项目的contributor。而committer则更进一步,这个是Apache基金会官方认可的头衔,表达了对于某个项目的活跃贡献者的一种认可。brpc开源后被捐献给了Apache基金会孵化,所以brpc也是Apache所管理的众多开源项目中的一员。今年9月,通过brpc的PPMC的票选,我成为了brpc项目的新晋committer,下面我来谈谈我和brpc的故事。早在2017年我就开始关注C++的开源RPC框架,当时只有Facebook的thrift和Google的grpc相对出名。但也没有到一统江湖的地步。这和Dubbo在Java领域的影响力还有很大差距。在每个重度使用C++的公司中,几乎都有自己的RPC框架,腾讯也不例外。在腾讯甚至几乎每个部门都有自己的RPC框架,SNG的spp,WXG的srvkit,MIG的taf(开源版名为tars),我之前所在的部门,也有名为middle的rpc框架。若干年后,腾讯内部出现trpc,这已经是brpc开源之后的事了(据说trpc从brpc中借鉴了很多设计)。同年,百度开源了brpc。但当时的我并没过多关注,总感觉国内的开源项目和国际上互联网巨头作品可能还是有不少差距。时间到了2018年,在腾讯带我们干活的组内骨干跟我们说:“别老看业务代码,可以学习一下百度开源的brpc。”但后来我还是忙于做业务,最终也没有把这句话放到心上。2018年我由于个人原因,从深圳来到北京。也跳槽去了百度,但是也没有过多接触brpc,因为我当时我在的团队(百度凤巢检索端)历史包袱严重,也有一套自己的RPC框架。所以我再一次和brpc失之交臂。但是我在学习本部门框架过程中,还是积累了很多通用知识的,为后来学习其他RPC框架也做了铺垫。另外当时我也有点私心,感觉brpc是开源的,什么时候学习都不着急,反而公司内部闭源的代码,是我在外面学不到的,所以当时精力主要做学习内部代码。我真正开始深入学习brpc是在2020年,没错,我再一次换了工作。彼时由于工作关系,我开始频繁使用brpc。我这才发现一个现代的RPC框架,和我之前看的RPC框架,在设计上有很大不同。一改我对于国产C++
2021年10月12日
其他

C++ STL容器如何解决线程安全的问题?

众所周知,STL容器不是线程安全的。对于vector,即使写方(生产者)是单线程写入,但是并发读的时候,由于潜在的内存重新申请和对象复制问题,会导致读方(消费者)的迭代器失效。实际表现也就是招致了core
2021年10月9日
其他

C++代码简化之道 (2):消除非必要的指针

作为C++程序员,肯定免不了和指针打交道了。一般我们使用指针都是为了避免不必要的拷贝,但有时候其实可以简化掉它。活用三目运算符先看一段例子,假设我们有一段老代码:
2021年8月2日
自由知乎 自由微博
其他

C++代码简化之道

我是极简主义者,崇尚简洁明快的代码风格,这也可能是我不喜欢Java全家桶的原因……当然我说的简洁是要建立在不降低可读性的前提下,即不影响代码本身的表现力。如果为求代码精简而让代码晦涩艰深同样不可取。本文会介绍10个条款,后续还会陆续更新相关的内容,请大家持续关注!1.
2021年7月26日
其他

“伪共享”凌乱记

本文属于并发编程系列,通过之前的文章我们了解到了CPU中缓存行的概念。简单复习一下就是缓存行是CPU读写缓存的最小单位,一般是64字节。另外当前CPU共有三个级别的缓存,从距离CPU内核的由近及远分为是L1
2021年4月7日
其他

百度工程师厂外生存指南

百度曾经一度被称为中国互联网的黄埔军校。这句话其实有两方面含义:一是说从百度走出来的工程师活跃在中国各大互联网企业中,对整个中国互联网的繁荣发展做出了贡献。二是说百度如同历史上的黄埔军校一般,为外界培育和输送了大量人才,但是自身却在逐步没落,暗示百度的人才流失严重。然而很多百度厂内高管常以『百度是中国互联网的黄埔军校』而自豪,这只是理解了这句话的第一层含义,却殊不知其第二层。高管们不对厂内人才大量流失的原因做反思,反而因为一句黄埔军校而沾沾自喜。着实让人唏嘘不已。Anyway,俗话说『干着SEO的活,操着CEO的心』,当然我也没资格评价大公司的管理制度,好好挣钱过好自己的日子才是王道。本文主要是写给从百度跳槽(或即将跳槽)到其他公司的工程师们。尤其是跳槽到小厂的工程师们,因为其他的大公司都有自己的基础设施,进去之后自然就能找到好的技术替代。百度已开源的库和框架首先,你要知道百度其实开源了不少东西,这些你都可以在厂外继续使用。下面收集了一些百度的开源项目。github地址百度github地址https://github.com/baidubrpc(厂外使用的也比较多)https://github.com/apache/incubator-brpcecharts(前端图表库)https://github.com/apache/echartsDoris(OLAP系统,内部叫Polo)https://github.com/apache/incubator-dorisBFE(应用层负载均衡网关)https://github.com/bfenetworks/bfePaddlehttps://github.com/PaddlePaddle大部分开源项目都可以在baidu账户中查看。但brpc、echarts等项目由于捐献给了Apache基金会所以不在baidu的账户中。bfe由于未知原因没有放到baidu账户中。值得一提的是深受百度做离线的同学所喜爱的bigflow也是开源的:https://github.com/baidu/bigflow当然由于开源世界Spark、Flink等大数据技术演进,bigflow或许已经过时。替换bsl(百度C++基础库)bsl是“百度STL”的意思,主要包含了一些百度自研的C++容器,有一些用以作为std容器的替代,另外有一些是补充(比如json)。在厂外可以使用boost
2021年4月3日
其他

指令重排序与内存屏障

从老版glibc的一个bug说开来之前我在公众号中,发表过这么一篇文章:这篇文章里面提到了老版本的glibc(2.13以前)中的排序函数qsort()有一个在并发时会出现core
2021年3月23日
其他

小议CPU缓存一致性协议MESI

buffer不等待其他CPU中的对应缓存行失效就忙别的去了。而其他CPU也不傻,实际上他们也不会真的把缓存行置为I后,才给CPU0发响应。他们会写入一个Invalidate
2021年2月20日
其他

bthread源码剖析(五): bthread上下文的创建

在之前的文章有介绍过调用jump_stack()函数进行bthread上下文的切换(bthread栈的切换),其中涉及了汇编语言。本文来讲一讲与之对应的另外一个操作:调用get_stack()进行上下文的创建(bthread栈的创建),并且同样会涉及汇编语言。其实涉及到上下文创建的有两处,一处是TaskGroup初始化的时候,另外一个就是TaskGroup在死循环获取任务执行任务的时候(在jump_stack()之前)会调用get_stack()。先看一下TG的初始化,在TC的create_group()中会调用TaskGroup::init()。TaskGroup::init()int
2021年2月9日
其他

bthread源码剖析(二): 工作窃取与TaskGroup的run_main_task()

上一篇文章,介绍了TaskControl(简称TC)的初始化逻辑、worker的基本概念,并引出了TaskGroup(简称TG)的主要函数:run_main_task()。在谈run_main_task()之前,我们先看一下TG的几个主要成员。TG的主要成员讲到TG先看TG的主要成员:
2021年2月2日
其他

bthread源码剖析(一): 基本概念与TaskControl初始化

bthread是协程吗?如果你使用过brpc,那么对bthread应该并不陌生。毫不夸张地说,brpc的精华全在bthread上了。bthread可以理解为“协程”,尽管官方文档的FAQ中,并不称之为协程。见:https://github.com/apache/incubator-brpc/blob/master/docs/cn/bthread.md若说到pthread大家都不陌生,是POSIX标准中定义的一套线程模型。应用于Unix
2021年2月1日
其他

过往工作中的一些趣事

点击蓝字关注我吧~腾讯篇腾讯BG各自为战,每个BG甚至某个部门都有自成一派的研发体系。我当时所在部门也不例外,它自己有一套从研发到上线的内部系统。当时我们写的代码提交之后都会触发云端的自动编译,编译出来bin供给后续部署上线。这套CI/CD的流程大家想必在各个公司都有体验。笔者当时利用这个自动编译平台的设计漏洞做过的一件趣事。由于多为C++模块,各个团队模块编译方式千差万别,没有统一的构建工具。所以每个模块(指一个代码库)需要在这个自动编译的平台网站上设置编译方式,比如make命令,或者指定执行一个shell脚本。因为你可能要在脚本中做一些准备工作才能让自动编译的机器正常编译,当然前提是把脚本也放到代码库中。当编译任务触发时,编译机上的脚本会用这个账户来下载代码,然后执行设置的编译命令来执行编译动作。最后将结果打包成zip,然后上传获取一个FTP地址。通常来说,代码仓库都是有权限控制的,即使是一个部门,也不会让所有源码默认对所有人开放,这不难理解。有趣的地方就出在这个自动编译机的原理上,自动编译的机器可以编译整个大部门所有团队的代码,当时他们是创建了一个具有极高代码权限的虚拟账户,用来下载代码。在我后来的其他工作经历中CI/CD的流程中,直线构建任务时,都是以触发任务的那个用户的身份来执行编译。换句话说也就是没办法下载没有权限的代码。本来我和这个平台也相安无事,直到后来。回说一些工作背景,我们组负责的业务是两年前开辟的新业务,整个后端都是从头架设的。初创之时(在我来之前)为了快速上线,其中一些基础模块是直接搬运的成熟业务中的模块,后来加以修改。后来我们这块的业务逐渐成熟,和之前业务的相关团队分道扬镳,代码和人员都慢慢独立出来。其中有个模块的代码是直接拿过来的,单独存了一份代码(也就是一份旧版代码),比较基础的模块,没有过多业务上的逻辑,我们只修改配置,并不迭代代码。但这个模块在之前的团队中后来又迭代许久,功能十分丰富。彼时他们的代码我自然没有权限访问,没有办法克隆。我曾和他们询问该模块最新代码,但是他们敝帚自珍,把我拒绝。这时候我想起了这个自动编译系统。它是允许每个指定自己指定编译脚本的,且是用高权限的账户来下载代码的。这可就有意思了,这是妥妥的“OS”注入漏洞啊,当然这是对内系统,外部是无法访问的。**请注意这不代表整个腾讯,只是我们部门用的自动编译平台当年有此BUG。**我呢,自然也不会用它来搞破坏,我只是一心为了工作。我找了一个我自己的模块,在里面放进去了一个脚本。然后在自动编译网站上设置编译命令为执行这个脚本。这个脚本除了正常的编译流程以外,还有一部分是调用svn命令(当时还未迁移git)去克隆那个我没有权限的模块及其依赖的代码,然后将源码复制某个目录中。后面被自动编译机打包,生成FTP路径。而我通过FTP下载zip包,最终剥离出了那个模块的源码……后来我虽然看过他们代码,不过最终没有给我们业务使用,想来想去,毕竟也名不正言不顺,权当学习了。一年以后,我们团队和他们达成了合作,他们给出了源码,并提供了技术支持,指导我们如何配置使用最新版的模块。其实我早已可以随时查看他们的代码了,在后来的工作中我再也没有遇到过这种漏洞。这权当是一则趣事。百度篇在百度工作期间,我所在的部门是对外号称“凤巢”的商业化广告部门。众所周知,在商业化部门,做数据分析是必不可少的工作,即使我是C++后台开发也不例外,因为我们日常上线的feature都关乎着CTR、CPM等广告指标。对于日常的数据分析,内部有一个在线的数据分析网站。这个网站的后端存储是基于Spark的。我们可以在这个网站上输入SQL,来查询数据。还可以导出成文件,或者转储到HDFS。当然这里SQL是Hive/Spark的SQL,尽管很像关系型数据库的SQL但是支持的语法会更多样些。在大数据领域、BI领域常用的DB都是列式存储而不是MySQL那种行式存储的。为避免一次查询的数据量过大,所以这个网站也有同时查询的任务个数的限制(多了会排一会队)和单次最多只能查询三天数据的限制。题外话:如果是行式存储要避免查询查询过多,一般是限制返回的行数,也就是让你自己写limit,offset。当然有其他途径可以跑MR任务在Hadoop集群一次性导出更长时间范围的数据,但是集群太慢,排队太多,跑个小任务完全没必要。所以一般可以在这个在线分析网站上查询,但是蛋疼的是,只能三天三天的查,如果要查询一个月的数据,只能分成10次查询,每次修改WHERE条件后面的起止时间,然后导出了10次查询的结果。某日在组内工作群里,一个同事被安排查一两个月的数据,他说很不好办。靠人工三天三天地查询,经常这样太费时间。我多嘴说了一句,不用人工,其实可以写程序做到自动化查询。然后被问:“怎么实现?你帮忙写一个?”得……祸从口出。大话已出,搞吧。我为什么说有办法自动化呢?按理说我们可以和这个网站交互,输入SQL,点按钮查询,最后网页能自动把结果渲染出表格,应该都是有API的,内部网站反爬虫功能都不强。话不多说,给Chrome按F12吧,找找找,果然找到几个HTTP请求。打开Postman做测试,发现是需要鉴权的,不然直接给发请求会报错。尝试是Chrome中把Cookie复制出来,塞到Postman的Header里,OK,成功拿到结果JSON。在理论上验证确实可行之后,我开始改写成python脚本。首先将复制的Cookie写入到文件中,供脚本读取。第一版脚本功能如下:读取文件中的SQL语句,其中WHERE的起止日期是变量(可以用python的字符串format功能,方便后续替换)。脚本中指定好查询的时间范围。脚本执行时会自动以每三天为一个单位生成一条有效的SQL,然后携带Cookie
2020年12月13日
其他

叫板面试官:请不要再问我海量数据题!

点击上方“蓝字”关注我们面试官:老鸟一个大文件,包含5亿个整数,求中位数应聘者:小鹅这题不难啊。排序,找出中间行的数字即可面试官:老鸟请审题,是一个大文件。不能装进内存里应聘者:小鹅5亿个int也就2GB,什么机器内存这么小?面试官:老鸟是2G么?你怎么算的这么快?应聘者:小鹅很简单,面试的时候,快速口算内存占用有技巧。我先问一句,你学过英语吗?面试官:老鸟废话,当然学过应聘者:小鹅和中文数字习惯不同。英文数字在朗读和表示的时候是三位一组的。1,000,000,000
2020年11月24日
其他

实践解读CLOSE_WAIT和TIME_WAIT

POSA)的默认端口,所以这种网络工具直接显示成了那个协议的名称。客户端pid为74135。当然,我其实知道我是用telnet连接的,只是为了查pid的话,ps
2020年11月21日
其他

C++ Trick:不使用friend,怎么访问private成员变量?

想知道怎么不使用friend,访问private的成员变量?有方法,但不鼓励……方法一#include
2020年11月19日
其他

Goroutine并发调度模型深入之实现一个协程池

并发(并行),一直以来都是一个编程语言里的核心主题之一,也是被开发者关注最多的话题;Go语言作为一个出道以来就自带『高并发』光环的富二代编程语言,它的并发(并行)编程肯定是值得开发者去探究的,而Go语言中的并发(并行)编程是经由goroutine实现的,goroutine是golang最重要的特性之一,具有使用成本低、消耗资源低、能效高等特点,官方宣称原生goroutine并发成千上万不成问题,于是它也成为Gopher们经常使用的特性。Goroutine是优秀的,但不是完美的,在极大规模的高并发场景下,也可能会暴露出问题,什么问题呢?又有什么可选的解决方案?本文将通过runtime对goroutine的调度分析,帮助大家理解它的机理和发现一些内存和调度的原理和问题,并且基于此提出一种个人的解决方案
2020年11月11日
其他

大四那一年

0x00“吃完饭,去外面散散步吧。”说话人是HomKai,与我同在腾讯实习。2015年,深圳八月的傍晚。腾讯大厦周边的马路上,行走着两个男人,一胖一瘦。路边有零星几个商贩,叫卖着熟玉米、茶叶蛋等小吃。“你说,如果咱们不会敲代码的话,现在会不会和他们一样啊?”HomKai又开口了。“这……,说不好,或许吧”我不好回答,想来如果假设成立,即便我们不是在路边摆摊,也会是从事其他劳力的工作。HomKai与我是老乡,同届,同在南昌读大学,同是程序员。另外一个共同之处就是我们的父母都是北方土生土长的农民。想到这里,HomKai刚才的假设便不足为奇了。我们继续走着。夕阳如血,两个外乡人的背影消失在钢筋水泥之中。0x01“大四的同学都赶快回来上课,不然期末挂科,后果自负”九月下旬,某个工作日的午休时刻。辅导员在计算机系的大群里吼着。没错,我们大四上学期还有课。班里的同学也在盛传XX老师每节课都点到,而老师只能容忍三次缺勤,超过这三次,直接挂科。而这周就是上第三次课了。对于学校的种种制度我有力吐槽却无力改变。无疑,返校该提上日程。难熬的八月过去了,在焦虑与紧张的情绪中,经历了实习生留用的考核。彼时,大厂缩招、阿里拥抱变化等消息搅动了整个秋招市场。互联网就业寒冬的说法不绝于耳。天气转凉,毕业生们的心也随着天气一起变凉了。这个月初,鹅厂HR发了留用通知,心情放松许久。回首一路,自己无疑是幸运的。有人说找工作也要靠运气,虽有一定道理,却不敢苟同。我觉得这样说更贴切:找工作也要看缘分。0x02南昌,十月。“回来了?”“回来了。”“你终于回来了”“是啊”“后天有科目三考试,两点半过来练车!”科目三教练突然电话催练车。遥想六月初,考过一次科目三,很不幸,挂掉了。此后心里一直耿耿于怀。如果说大学是我们从学校到社会的过渡阶段的话,那么驾校无疑是进入社会前的一次小规模演习了。从科目二到科目三,从教练到学员身上体会了各式各样的社会习气。今年三月,科目二练车,中午,一辆车,四个人。“四个人,今天还有没来的,但是下周科目二考试只有三个名额,所以现在就是你们努力的时候了,谁练得好就谁就去考。”教练在车外趴着车窗抽着烟说道。显然教练口中的“练得好”是主观的,而不是客观的。下午,厕所。一个男人提着裤子正要走出来,被我硬挤了进去。一包烟塞到教练兜里。“不能要,不能要。”“拿着,拿着。”这已经是第二次送烟了,一周以前也送过一次。对于这些社会规则我并不熟练,我知道自己还很笨拙。此后的几天,同车的几个女生把各种驾车技巧练的很熟,教练依旧骂我练得不行。一周之后,我参加了科目二的考试。而那些女生却只有一个参加考试。幸运的是,那天我一次通过了科目二。先烧香,后拜佛。科目三的佛不仅是教练,还有考场上同车的安全员。去实习之前参加过一次科目三的考试,虽然拜了佛却还是因为没发挥好,没有通过。这次实习回来,教练竟然比我还急叫我去练科三。两天之后,第二次考科目三的我,配上天时地利人和,终于通过。何为天时,上路考试时没有遇到上下班高峰。何为地利,路上没有遇到突发的车辆和行人。何为人和,安全员没有故意一脚刹车踩挂我。0x03双十一,凌晨。买了一部iphone
2020年11月8日
其他

C++ Trick:小心,子类隐藏父类成员函数

学习面向对象的语言,了解继承是必不可少的。您可能觉得这太基础了,大家可都是老“996”了,还用介绍封装、继承、多态那老三样吗?😌哎,您别着急。本文讲的是一个C++语言的小Trick,您或许了解也或许不了解,各位看官请细听分说。按常理来说,如果父类的成员函数是public的,那么子类应该也能直接调用父类定义的函数,所谓的“继承”也便是这个含义。口说无凭,手上见真章,说有这么两个类,它这样,这样,这样……啪啪啪,你甩给我一段代码:#include
2020年11月7日
其他

C++ Trick:宏函数与模板类之殇

这是一个小trick。虽然不难理解,但是可能经常会忘记,导致代码返工。看这段代码:#include
2020年11月3日
其他

大学期间Linux C++后台开发这条线怎么走?

joy,从SMS到Linus。从开源运动的兴起到无处不在的Linux。这些故事不仅可以帮你产生学习的兴趣,也会让你学习到Unix/Linux背后的一些知识与设计哲学。我推荐看一下这本《Unix
2020年11月2日
其他

疑难杂症录:C++代码出现内存泄露?不是吧…

前段时间做一个需求,需要用到一个本地词典文件。该词典原始文件超过2G,在服务启动的时候加载到内存中,并且保持词典数据的热加载,也就是不停服更新词典数据到服务进程的内存中。之前有同事在其他项目中有热更新词典的代码,我就直接拿来用了。这是典型的双Buffer词典。也就是程序运行期间,内存中会同时维持两份词典:一份前台词典供运行时各处理逻辑检索,另一份是后台词典,在检测到目标文件修改时(通过检查文件mtime判断的是否更新)。在词典数据更新时,重新解析加载,最新的数据储存到后台词典中。最后两个词典做0
2020年11月1日
其他

1024忆往昔:我是如何走向计算机这条路的?

初入大学经过多年的奋斗,2012年我终于一脚踢开一所大学的门,它便是南昌大学(以下简称难大)。当然说一脚踢开校门太夸张了。我们学校可是号称拥有亚洲最大校门的,好不。踢门?门都没有。亚洲最大校门就是我校的一号门,让人印象深刻的是,校门口有一座雕塑,一位女神一手托鸽,一手捧书。一手象征着和平,一手象征着智慧,我校学子美其名曰:读书顶个鸟用。书呢???书呢?哈哈,当然没有啦,刚才说的不知道是哪位前辈学长造的谣。所以当众多新晋学子怀着对传说的朝圣之心,来到一号门时,发现传说是假的。这给他们年轻的心灵上了关于大学的第一课,那就是:不要相信学长学姐。后来传闻说有人给女神正名,让谣言止步。所以女神像又有了新的名字:女人玩鸟。话休絮烦,因为南昌大学是江西省的。江西有些地方的方言是l、r不分的。比如军训的时候,我同学跟我说:我好乐啊,好乐啊……我心想:你乐啥呢,难道江西话乐是形容词。你说你很开心?后来才知道他原来说的是好热啊。有了这个经历,我就对l、r不分见怪不怪了。开学伊始,各种大班会。一个江西某地的辅导员给我们讲课,大家昏昏欲睡。突然他说了一句:大学期间,大家一定要学会浪!瞌睡中的同学们瞬间打了个冷颤。只有我懂老师心,老师是说:大家一定要学会让(浪)。瞅瞅你们这一个个没见过江西人的样子!大一上:恍恍惚惚我一看不愧是大学啊,太自由了。我一定要洗心革面,不能再做一个死读书的书呆子了。那第一步怎么做呢?自然是要加入一个社团了!我虽是电子系的,但通过看电影,我对黑客很是充满好奇。我毅然决然地投了我们学校的某IT工作室(当时一度分不清,以为程序员就是黑客~)。出于隐私保护的需要,我肯定不会告诉你这个工作室叫家园网。然后笔试我就被刷掉了。后来我争取到一个『霸面』的机会,面试当晚,我的名字在面试名单的末尾。等到大概晚上九点半以后,终于轮到我了……难道我的黑客之路就要从此展开了吗?细节省略。我依旧没过面试。若干年后回忆起来,很是感谢某工作室,哦不,是命运的不收之恩。因为当时他们那里的技术栈是.Net。接着学校又搞了一个计算机基础考试,分数高的学生除了可以免修那个学期的计算机基础课,还有一个小灶福利:每周末可以上一个web编程课。不出意外,那个学期我老老实实地去上了计算机基础课。后来回忆起来。我当时室友是免修这门课的,他们编程课学的是VB……我再一次感谢命运不收之恩。彼时学校又出现了一个考试,选拔学生进入中兴实验班和理工实验班。考得是高中的知识,又一次做了炮灰。我严重怀疑我们学校是定要让我在这个小小年纪就意识到:我注定是要输在起跑线上的。后来的我,就真的走向『正轨』了,和万千普通的大学生一样了。和同学打打LOL,也和一群学长折腾创业,自己也去做校园代理做推销卖衣服。后来发现我对这些也着实没有天分。开黑打LOL被同学喷到心里崩溃:“谁守的中路,我靠。会不会玩呀,被人打爆了,莫甘娜怎么玩的。”去大四的寝室楼发传单推销正装。我一进门,刚说了一句,就被轰出来了。门Duang的关上了。我只能在门外暗骂“诅咒你们考不上研究生,找不到工作!”大一的第一个半年就这么浑浑噩噩的过去了,这个学期的时候上了C语言的课。但是刚上大学也无心学习。挂了一门工程制图的课。C语言考前突击复习了一下,勉勉强强过了及格线。有些事情回忆起来,总觉奇妙。我们考试成绩是寒假回家之后来公布的,如果挂科寒假结束就要回来补考。当时回家的时候,我很不放心C语言,感觉可能也挂了。就把课本拿回家准备寒假复习。接下来就要给大家介绍一下改变我人生命运的一个寒假啦!!(傻逼脸)充满巧合和意外的寒假后来得知C语言没有挂,事情本来也就这样了。直到一个挂科的同学在问问(当时QQ的问问还有人用)上提问“为啥printf的变量不需要&,而scanf则需要&呢?”我在空间里看到了这条问问动态(现在空间好像没这功能了),我知道的C语言知识不多,但偏偏这个我是知道的。就回答了。不一会收到了他的赞扬
2020年10月24日
其他

谈谈腾讯和百度的C++开发环境

笔者先后在TB待过,主要做C++开发工作。今天来谈一下两个公司的C++开发环境。其实不管是哪个公司对于如何开发都没有太大限制,在保证不泄露代码的安全前提下,选择自己喜欢的开发方式就好。但是肯定每个公司的前辈程序员们还是有一定的选择偏好的,所以后来的程序员也慢慢被同化。免责声明:腾讯BG众多,各个部门的技术体系和研发流程自成一体。不同部门,不同BG之间差异都很大。本文所介绍的是笔者当时(2019年之前)所工作的一个部门,当时周围比较常见的开发环境。另外谈到开发环境,不仅包含IDE,还有其他很多很多的工具。腾讯由于之前很多很多年腾讯的办公电脑都是Windows(18年开始才有MacBook的选项),入职时可以申请一个台式机和笔记本。都是Windows。开发机是Linux,需要ssh登录。IDE(开发+阅读)所以C++的程序员长期都是在Windows下办公,腾讯使用最多的IDE就是SourceInsight。SourceInsight开发效率其实并不高,但是作为阅读源码而言,真的是神器。甚至有老一辈的同事给SourceInsight用hook的方式做了一个牛逼的插件,支持了更多的功能,使得代码阅读的效率更上一层楼。外面也有其他人做过类似的插件,但感觉还是有一点点差距。图片来源网络,仅作示例同步当时比较常见的开发方式就是在Windows上用SourceInsight进行开发。然后同步到Linux开发机上。同步方式多种多样,有用samba挂载Linux开发的目录到Window上变成虚拟目录的,我比较习惯的是WinSCP,可以实现自动同步。当时开发网的Windows电脑和Linux开发机,可以用户名密码登录,无需用token(只有生成环境的Linux登录需要token),所以可以直接让WinSCP之类的工具记住密码。版本控制相当长的时间,腾讯都是使用SVN做版本控制的,Windows上下载那个乌龟SVN,有图形化的方式进行各种操作。当时公司内部也有git,貌似是魔改的gitlab。但是用的不多,后来好像有在推,不知道现在情况如何。代码的对比和合并使用BeyondCompare比较多。通常就是用BeyondCompare打开两个窗口,每个窗口打开一个版本,然后比较找出红色的文件,再逐行进行合并或修改。图片来源网络,仅作示例C++版本腾讯各个BG几乎各自为战,不管是框架还是工具都没有统一标准。对于C++的版本有的部门升级到了g++编译器,支持了C++11。但也有很多部门还使用的C++98/03。美其名曰:稳定安全。编译与包管理编译大多数情况下还是手写Makefile的方式,当然有一些通用的Makefile模板,倒也不需要太花时间。对于包管理由于C++没有Maven、npm、pip那种开源方案,在腾讯内部也还是没有高级的方式,只能保证开发机上安装的公共库(自建、第三方库)和远程编译机以及生产环境上完全一致。这样Makefile写的各种链接目录才生效。离开腾讯后,发现IEG某部门其实有研发过一个C++的构建工具,名为blade,语法与bazel类似。并在github上开源。尽管如此其也只是替代了makefile,在编译环节达到了简化,但并没有向Maven,pip一样实现依赖包的自动下载。百度后来来了百度,大家都是用MacBook,也就没有了SourceInsight。开发方式就是用iTerm直接SSH登录Linux开发机进行开发。并且百度技术话语权比较强,svn迁移git,C++版本升级都会从公司层面强推。开发:vim
2020年10月12日
其他

小议C语言标准库排序函数qsort曾经的bug

背景曾经在某厂工作期间,发现大量C++项目的代码,都在用qsort()而非std::sort()来排序。不知道是出于某种特殊的动机,还是仅仅是历史原因。这倒也罢,紧接着我发现所有C++的Server项目,在main函数中靠前的位置都有一段特殊代码。用qsort给一个个数超过1024的随机数数组做一下排序。一时不明就里,百度一番后才发现qsort在多线程中调用会有bug,需要在多线程逻辑开始之前做一次排序来避免。问题描述但是,这仅仅是旧版的glibc。gblic
2020年10月8日
其他

C/C++:堆栈面面观

学习C语言,我们都听过堆(heap)和栈(stack)的概念。也是C/C++码农面试的常见考点,今天带大家来深入浅出一下。本文写于大四,写作初衷也是来自于曾经的面试经历、大学课程所学以及各种网络资料,融合《CSAPP》的读书感悟总结而成。需要注意的是:有些地方“堆栈”这个词特指的是栈,而不是堆和栈。命名约定:本文中堆栈一次出现的地方,指的是两种东西,而非一种。在数据结构中,我们也听过栈和堆这两种数据结构,当然和我本文要讲的东西是不同的概念。不过数据结构中的栈(算法、数学意义上的一种抽象),和本文中的栈(实际存在的存储区)有一共同之处就是FILO
2020年10月5日
其他

人生是一条蛇,它咬着自己的尾巴

1奥罗波若回首2018年,我首先想到的是一个图腾:一条咬住自己的尾巴的蛇。这个图腾最早出现在古埃及,后来它广泛流传,传入到印度教、古希腊,也出现在北欧神话中。其名为奥罗波若(Ouroboros)。象征着宇宙循环,无始无终,开始即是结束,结束亦是开始。其实人生常常就是这样,任凭时间推移,生活却总在某个地方回到原点。2风雨屋檐2018年4月在公司内网的论坛上,看到一个帖子:提问什么时候你感到青春已逝?回答所谓青春已逝,大概就是当风雨来时,抬头一看,已无屋檐。低头一看,自己已成屋檐的时候吧。几天之后,组会上得知一个消息,犹如晴天霹雳:“同事老孟即将离职”。老孟是个全能,组内业务无一不精。他在入职一年后便迅速成长为组内骨干。两年前我毕业入职以后,几经辗转来到这个组,那时开始就是老孟带我们做事。我们组年轻的同事很多,基本上都是同一时期入职的,老孟经常给我们拆解产品需求、做设计。也会帮我们出主意,帮我们和PM怼方案,帮我们处理线上问题,给我们的粗心大意擦屁股。在组长眼里,老孟是骨干。在我们年轻同事看来,老孟就是大树,就是风雨中的屋檐。他帮我们顶住了很多压力,长期以来,我们都很依赖他。虽然我们也经常半开玩笑地怪他做的太多了,导致我们自己没有得到锻炼。但是谁都不想没了老孟,不然我们可能更糟。但这次是真的。3舷梯之上再谈一下我自己和我所处的部门,我不以偏概全,肯定并非整个鹅厂都是如此。我所在的团队经营着一个边缘业务,缺少用户,没有请求量。做的业务属于第三方支付行业。早在刚工作的时候,我就发现,在这里工作越久,就越来越离不开这个行业了,而这个行业安身立命之本、职业发展技能更多的倾向于业务逻辑上的一些套路,而非一些计算机、纯技术的东西。常常自嘲“if
2020年10月2日
其他

如何理解互斥锁、条件变量、读写锁以及自旋锁?

锁是一个常见的同步概念,我们都听说过加锁(lock)或者解锁(unlock),当然学术一点的说法是获取(acquire)和释放(release)。恰好pthread包含这几种锁的API,而C++11只包含其中的部分。接下来我主要通过pthread的API来展开本文。mutex(互斥量)mutex(mutual
2020年9月22日
其他

高山仰之可极,谈半同步/半异步网络并发模型

本立道生:基础知识导入所谓『网络并发模型』,亦可称之为『网络并发的设计模式』。『半同步/半异步』模式是出镜率很高的一种模式,要想解释清楚它,我要先从基础讲起。熟悉的同学可以跳过本节。1.1
2020年9月21日
其他

C++之我见:重剑无锋,大巧不工

首先声明,编程语言没有银弹,要懂得因地制宜,随机应变。陷入语言之争是无意义的。但我也认为对于程序员而言,学习和使用哪门语言是有个人偏好的,偏爱哪个自然也无关乎对错。据我感觉至少80%的C++程序员不是为了找工作才学的C++,因为学习C++对很多人来说ROI难成正比。论就业,Java的市场需求肯定比C++的多。论学习速度,Go学习没多久,就能手撸一个性能还不错的网络库。而C++呢?学习时间长,旧语法还没精通,新语法又开始层出不穷。并且还有各种安全隐患,程序员一不小心就会踩坑。你以为我要劝退了?不不不。毕竟我也是C++程序员啊,虽然我不劝入,但还是想表达一下我对C++的观点,讲一讲我与C++的故事。我个人大学时期的编程语言学习经历是这样的:C
2020年7月15日