GithubHelp home page GithubHelp logo

blog's Introduction

编程往事

[详情]

博文

[专栏]

[分类]

分类

使用的issue 的 label 作为分类

公众号:编程往事

分享我的学习和工作经历,以为一些技术随笔。提供大学生学习和就业指导。

blog's People

Contributors

guodongxiaren avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blog's Issues

也谈C++:重剑无锋,大巧不工

也谈C++:重剑无锋,大巧不工

我向来观点编程语言没有银弹,要懂得因地制宜,随机应变。但作为编程语言的使用者(程序员)是有个人偏好的,偏爱哪个自然也无关乎对错。

据我感觉至少80%的C++程序员不是为了找工作才学的C++,因为学习C++对很多人来说ROI难成正比。论就业,Java的市场需求肯定比C++的多。论学习速度,Go学习没多久,就能手撸一个性能还不错的网络库。而C++呢?学习时间长,旧语法还没精通,新语法又开始层出不穷。并且还有各种安全隐患,程序员一不小心就会踩坑。你以为我要劝退了?不是。毕竟我也是C++程序员啊。虽然我不劝进,但还是想和你聊一聊我与C++的故事以及我的观点。


我个人大学时期的编程语言学习经历是这样的:

C -> C++ -> Java -> C++ -> C -> C++
刚上大学,课本里学的第一门编程语言就是C语言,本来我也没太感冒,后来我对刷题产生了兴趣,就用C语言在hduoj刷了很多题。这期间编程的基本功力大涨。后来感觉刷题的边际效益比较低了,因为我们学校也没有acm集训队什么的,自己好几天研究一道题太不值当的,容易走火入魔。然后就学C++,看了面向对象的部分,学语法倒也不难,只是没找到感觉。每天对着黑黑的控制台程序没意思,当时移动开发特别火,我就自学安卓编程了,这时候主要是用Java,学习安卓的过程之中,我突然对面向对象理解更深刻了,然后回过头去看C++,感觉通畅了很多(好像学习C++都需要其他语言辅助……)。

这时候我突然想做点桌面端GUI的东西,Java的桌面太丑了,MFC的语法太烂,我就学习了一下QT。哇,开始叹服C++也可以这么优雅。但是后来,不管是我学习安卓开发还有QT开发,感觉很多时候都是在搭积木,遇到了不知道怎么实现的问题,百度一下就能找到答案,然后照(拷)猫(贝)画(粘)虎(贴)就能做出来。时间久了我心里总感觉哪里不对,那就是太空中楼阁了。这和内心的声音相去甚远,我想更多的了解一下底层,了解一下原理,而不是搭积木这般。然后我就又开始学C了,开始学Unix C编程,逐步逐步地了解操作系统,了解内存,了解网络,去探寻我心中的真相。

当然也仅仅是了解,只是比之前深刻些了。然后再翻看专业课的课本,不同课程的知识和自己自学的串联起来了,豁然开朗,心中暗爽。学计算机不再像是集邮一样,把知识概念一件一件纳入进自己脑袋,而是发现知识本身可以有很多关联,自己揉搓在一起会产生奇妙的化学反应。

这个过程下来,颇有古人说人生三种境界的感觉:

看山是山,看水是水;
看山不是山,看水不是水;
看山还是山,看水还是水

看到这,你可能会觉得落脚点怎么到C了。不是说C++么?你喜欢C,那你选择C就好啦。

我想说:谈C++,谈C是绕不开的话题。C++对C的兼容是C++的包袱,但也是C++的亮点。我可以在C++中无缝地使用C的**,去直面内存,直面OS,直面网络。不需要借助虚拟机或者解释器什么的。并且在这基础之上,我还能享受到一些高层语言的便利。

再谈回C++本身。在对C慢慢了解深入以后,我对C++的学习也重新开始了。像另一位答主所言,C++真的是给人一种造物主的感觉。我在大学时候说过类似的话,我说:C++给我一种上帝般的快感。比如别名、运算符重载,在Java中就见不到(当然python中也有),这给我以极大的舒适。除此之外你还能“自定义”关键字,比如QT中的Q_OBJECT(当然,这其实是一个宏)。各种编程范式,你想用那种就用哪种(当然,这可能也是被诟病的地方),面向过程、面向对象、函数式。平心而论,C++也并不是无所不包,比如就没有反射(虽然自己也可以手撸一个类似的),没有热加载(也可以用dlopen搞个类似的)。

除此之外呢?模板元编程。这个是一种非C++作者或者官方设计的,而是从C++模板语法中衍生的”,由于C++模板自己图灵完备,所以说其是另一门编程语言也毫不为过。然而这个玩法是“民间”发掘出来的(当然后来的C++11等标准在官方层面也给了元编程更多支持,这是后话了)。你还能不感觉自己是上帝么?

虽然我选择了C++,但是C++博大精深,并且新标准也在不停扩充,我感觉想精通是不可能了,这辈子都不可能了,要一直学习下去,虽然很多语法特性在工作中是用(不)不(让)到(用)的。但是这就是我们学习C++的乐趣吧。学Java的话,学完语言,就要学各种框架了,学习如何花式写XML。学Go的话,学完Go是不是就要学Rust了,学完Rust呢?当然我也不是在鼓吹C++啦,我讲的只是个人的感受。比如夏天的时候,别人都喜欢吃西瓜,但我不爱吃西瓜,也不能说我有问题是不?每个人都有自己的爱好。有些人就喜欢精通各种语言,在简历上写一长串,这样没有什么问题。请允许我自由地表达自己的观点。

又说了这么多,好像还没点题。

当年杨过断臂之后,偶遇大雕,邂逅剑魔独孤求败埋剑之剑冢。剑冢有四:

第一柄剑长四尺,锋利无比,剑下石片下写着:「凌厉刚猛,无坚不摧,弱冠前以之与河朔群雄争锋。」
第二片石片上没有剑,下面写着:「紫薇软剑,三十岁前所用,误伤义士不祥,悔恨无已,乃弃之深谷。」
剑魔独孤求败的第三把武器:「重剑无锋,大巧不工。四十岁前恃之横行天下。」外表黑黝,剑身深黑之中隐隐透出红光,三尺多长,共重八八六十四斤,两边剑锋都是钝口,剑尖圆圆的似是个半球。
第四个阶段才是渐入化境,第四柄木剑,石片上文字道:「四十岁之后不滞于物,草木竹石均可为剑。自此精进,渐入无剑胜有剑之境。」

从一到四,并非是剑本身优劣从低到高,紫薇软剑未必胜过四尺长剑,同样玄铁重剑也未必会比紫薇软剑更能克敌机先,而第四柄木剑可谓四剑中最弱的。但是四柄剑依次排开,金庸老先生所要展示的并非是剑本身之优劣,而是展示持剑人(也就是独孤求败)自身武功修为之变化。杨过虽然有此奇遇,但并没有得到武功秘籍,只是拿走玄铁重剑。然而后来横行江湖,被称为神雕大侠之时,仪仗的却又并非此剑,而是自创的黯然销魂掌。最终玄铁重剑直接送给郭靖夫妇,被融化成屠龙刀倚天剑了。对他而言,并不可惜,因为彼时,他已然达到独孤求败的第四境界。

编程语言亦是如此,不同的编程语言,只是不同风格,不同特质的剑而已。初学者或者有经验的程序员们,常在剑冢流连忘返,而忽略了自身修为的提高。在我看来C++就是玄铁重剑,所谓重剑无锋,大巧不工。重剑无锋,是说剑刃是钝口,而且剑尖都没有(只是一个半球)。大巧不工,是说这柄剑并没有经过工匠的精心雕琢。这种剑本身杀伤力并不大,而且又因为是重剑,操作难度极大。但是如果你能熟练地挥舞玄铁重剑,那么你自身的内(编)功(程)修为也会逐渐臻至化境,以致于后期能达到『不滞于物,草木竹石均可为剑』的境界,什么编程语言都可以快速掌握,各种逻辑抽象,编程范式都可以轻松应对。
image


有趣的是,回看独孤求败给四柄剑留的字:三十岁前、四十岁前、四十岁后……这生命历程像极了程序员呢。希望我们能干到四十岁后把!

另外我真不是无脑吹C++的,Python也是一门很优秀的语言呢。不、不、不,我不能这么说话。Java和Go也都是很优秀的语言呢。

PHP:你怎么这次不cue我了。

我认为学习什么语言这并不冲突。喜欢哪个就去学习就好了,谁都不会限制你只学一门啊。当然要是说工作语言的话,那就要再综合考虑了。程序员毕竟是要恰饭的,但如果工作中常用的语言恰好是自己喜欢的,那么就好像你喜欢一个妹子,而她也恰好喜欢你。尽管要达到这种完美,可能要花费十六年。

吐血、、、关于小Q的穿越问题

原写作时间 2013-03-24

吐血、、、

昨天参加腾讯马拉松,当然没报什么晋级的希望,只望能多增加一点参赛经验。第一道题小Q穿越问题。讲的是小Q,和女友相约穿越,但是两人一个穿越到古代,一个穿越到未来。问题就是给你2013-03-24.输入穿越天数,问你他俩分别穿越后的日期……

我写了40分钟,写完。提交WA。郁闷。改吧,改了很久,总是看不出错误。我想可能是测试数据太少造成的。我就想搞点正确数据测试。我就用百度到excel可以计算日期加上天数后的日期。我就搞excel。一会果断关掉excel。因为我短时间内不可能上手这个日期计算问题。又百度到win7自带的计算器可以实现日期计算。于是一组一组的测试。先用计算器测出加上某个天数后的正确日期,再用我的程序测试。N组结果一一符合。我想是不是天数太少了。因为电脑的计算器只能加最多999天。于是
又百度到一个在线测试的,我把加上10000天的结果都比对了,是一样的,我想是不是vc不标准造成的,我写了某些不正确的语法,只有在vc通过,而在杭电却不通过。于是把我能想到的可能错的地方,一一修改。但结果都是WA。期间还换了c++的提交方式。(我使用c语言写的代码)。最终一个小时后无果,依旧WA了11次。再看其他题也没时间,也没心情了。

今天下午,翻开自己写烂了的代码。承认自己写的很烂。没有注释其他人几本是看不懂的。当然我自己是看的懂得。。。我浏览了一遍,还是看不出错误。于是大修,删了很多东西,把大部分运算抽象成函数。在我继续改的时候我发现一个地方,判断的时候是if(m<0).我想是不是应该是<=0呢。<0可能会出现日数为零的情况吧。。。我也没敢确定。只是试试。又找到最初的代码。改了一下。在杭电那里提交。(马拉松的题目在比赛后都挂到了题目的36页)刷新一下Accepted。

吐血、、、、


后记 2017-09-12

四年多以前,真的从未敢想过今后能去鹅厂工作。

拾遗与填坑《深度探索C++对象模型》3.2节

《深度探索C++对象模型》诚然是一本好书,该书作者也是《C++ Primer》的作者,一位绝对的C++大师。该书中存在的大大小小的错误一直为人所诟病,但这仍然不妨碍称其为一本好书。本文志在填坑。

3章2节 Data Member的布局

背景介绍

访问区(access section)即是指private、public、protected下面的代码区域。当然在类中同一种访问区可以多次声明,视作多个访问区,如:

class Point3d {
public:
    // ...
private:
    float x;
private:
    float y;
private:
    float z;
};
// 该类有4个访问区

本节重点讲述的是在同一个访问区中声明的数据成员只需符合 较晚出现的members在class object中有较高的地址 这一条件即可。换言之,并不需要连续,再换言之,数据成员之间编译器可以穿插其他所需的东西,如虚表指针或边界调整的填充字节等。注意该条件是说同一访问区内。如果不同访问区呢?不同的编译器厂商会做不同的调整,有的会把同种的访问区合并,有的则不会。如果你想知道你的编译器针对同种的不同访问区做了什么,对数据成员布局做了何种调整,可以采用代码验证。好的,重点终于来了。

错码

为了验证上述的猜想,作者写了一段代码来检测两个成员的顺序。

template<class class_type, class data_type1, class data_type2>
char* access_order(data_type1 class_type::*mem1, data_type2 class_type::*mem2)
{
    return mem1 < mem2 ? "member 1 occurs first" : "member 2 occurs first";
}

access_order(&Point3d::z, &Point3d::y);

等等,先停一下,你会说:刚才那个Point3D的类,x,y,z这三个成员可都是private啊,他这个外部的函数可以直接访问吗?呵呵。你说的对,大师犯了这个错误。来吧我们把访问区都改成public

By the Way, 大师的代码测试的不是对象的内存布局,而是直接测试的类的内存布局。

&Pont3d::z这是直接对的成员而非其对象实例的成员来取地址,实际上它获得到的并不是地址,而是成员在类中偏移(offset)。

继续,或许大师当年的编译器是可以通过的。很不幸,在我的机器上报错了(g++ (GCC) 4.8.5 20150623):

invalid operands of types ‘float Point3D::*’ and ‘float Point3D::*’ to binary ‘operator<’
return mem1 < mem2 ? "member 1 occurs first" : "member 2 occurs first";

矛头直指这个比较操作。。

可能是目前的C++标准或者G++编译器自身不支持指针地址和类中offset的比较运算符。或者大师的代码本身就存在问题。真真假假,这点就不得而知了。

改之

最简单的测试方案就是:

干嘛非要测试类中数据成员的先后顺序,直接测试对象中数据成员的先后顺序不久行了嘛

此时Point3D的三个private都已改成public。

    Point3D p;
    cout<< (&p.z < &p.y)<<endl;
    printf("%p\n", &p.z);
    printf("%p\n", &p.y);

输出:

0
0x7ffffd2d0458
0x7ffffd2d0454

其实到了这里,你该得出什么关于编译器如何调整数据成员布局顺序的结论,早就可以得出了。。不过那早已不是本文的重点,毕竟不同编译器有自己的实现自由,探究这个并无太多意义。。

再来直接打印一下类中成员mem1和mem2的值看看。

// 返回值也先改掉。
template<class class_type, class data_type1, class data_type2>
void  access(data_type1 class_type::*mem1, data_type2 class_type::*mem2)
{
    printf("%p\n", mem1);
    printf("%p\n", mem2);
}

输出结果:

0x8
0x4

这两个如此简洁的地址就是类中offset了(可以看出和指针确实差别挺大,短了好多)。
不过我感觉大师代码中那个模板用的当真漂亮,所以还是想着让大师的**继续发光发热下去,用来测试你的编译器咋处理的。遂改之。咋办?类型转换呗:

// 方案一 报错
return (char*)mem1 < (char*)mem2 ? "member 1 occurs first" : "member 2 occurs first"; 
// 方案二 依旧报错
return static_cast<char*>(mem1) < static_cast<char*>mem2 ? "member 1 occurs first" : "member 2 occurs first";  
// 方案三 还TM报错
return reinterpret_cast<char *>(mem1) < reinterpret_cast<char *>(mem2) ? "member 1 occurs first" : "member 2 occurs first";  

。。等会。看来天亡大师(的代码),强制类型转换是行不通了。。哈哈,如果你看到这里,你还是非要做一个比较操作(不通过对象),让控制台直接告诉你谁前谁后。。那么来吧,带大家一起继续脱裤子放屁。

union Cmp{
    float Point3D::* mem;
    long offset;
};
template<class class_type, class data_type1, class data_type2>
const char * access_order(data_type1 class_type::*mem1, data_type2 class_type::*mem2)
{
    Cmp cmp1 = {mem1}; // 初始化cmp1的第一个成员mem
    Cmp cmp2 = {mem2}; // 初始化cmp2的第一个成员mem

    return cmp1.offset< cmp2.offset?"member 1 occurs first" : "member 2 occurs first";
}

终于看到了member 2 occurs first,,代码调通了。不过丑的一笔。


后记:

代码段中类的数据成员的顺序和实例化后对象中数据成员的顺序是否具有一致性呢?这点我不确定,或许应该是吧。实例化操作应该就是栈中(或堆)模塑了代码段中的类模型,然后进行了初始化。而编译器自己添加的那些东西,那些调整工作在代码段中的类模型中就已完成了。我是这样理解的,希望大家指教。

[译]C++20: 协程一瞥

原文: http://www.modernescpp.com/index.php/c-20-coroutines-the-first-overview#h6-1-2-c-standard-library-including-c-14-amp-c-17

个别地方翻译的不好,勿怪。

C++20提供了4大特性,刷新了我们对于现代C++编程的认知:概念(concepts)、范围库(the range library)、协程(coroutines)和模块(modules)。关于概念和范围库我已经写了一些博文。现在让我们来看一下协程:
image
我想用这张图来展开对于协程的深入讨论。

协程是这样一类函数,它能在运行期间挂起和恢复,并且能保存状态。C++中函数的进化步步深入。我在C++20中当成新知识来解读的这一特性其实是非常古老的概念。Melvin Conway发明了术语协程:coroutine。在1963年,在他关于编译器构造的出版物种首先引入了这一概念。Donald Knuth也成过程(procedures)是一种特殊的协程。

在C++20中,新关键字co_awaitco_yield给C++的函数扩充了两个新概念。

  • 通过co_await表达式,使得挂起和恢复一个表达式的执行过程成为可能。如果你在函数func中使用了co_await表达式,然后执行auto getResult = func() ,即使函数的结果尚不可用,也不会阻塞调用。代替了资源紧张的阻塞,你拥有了一个资源友好的等待。
  • co_yield表达式允许你写一个生成器函数(generator function)。生成器函数每次都返回一个新值。生成器函数是一种数据流,可以从任意你想获取值地方的获取值。数据流可以是无限的,随之而来的,我们处在一个惰性计算(lazy evaluation)的时代之中。

在我展示一个生成器函数以彰显普通函数和协程的不同之前,我想先谈一谈函数的进化!

我与插入排序二三事

原写作时间 2013-03-27

关于排序的算法有很多。作为初学者。我在掌握了冒泡排序后掌握的第二个排序算法是插入排序。一个多月前看了一些资料,了解了排序的**,然后自己摸索出了代码的写法。并一直这样写了这么久。直到今天看了《算法导论》的时候,才恍然大悟,原来自己一直写的插入排序并不十分正确。虽然**是相通的。但是运行的效率却相差很多。

比如一个数列。用数组表示。a[n]。
我写的插入排序是这样

for(i=0;i<n;i++)  
{  
    scanf("%d",&a[i]);  
    for(j=0;j<i;j++)  
    {  
        if(a[i]<a[j])  
        {   
              t = a[i];  
             a[i] = a[j];  
             a[j] = t;  
        }  
}  

 这样写是一种边初始化赋值编排序的写法。如果是处理一段已经序列。则直接写成

for(i=1;i<n;i++)  
for(j=0;j<i;j++)  
{  
    if(a[i]<a[j])  
    {   
        t = a[i];  
        a[i] = a[j];  
        a[j] = t;  
    }  
}  

以上两种方法第二个for语句也可以改成

for(j-i-1;j>=0;j--)  
{  
    if(a[i]<a[j])  
    {  
        t = a[i];  
        a[i] = a[j];  
        a[j] = t;  
    }  
}  

看到这里你会发现这里也是用的插入排序的**。只不过关键是在插入的处理上。我的算法比正统算法差了好多。大家都知道计算机的数据插入无法直接像加、减、乘、除、赋值那样一步到位。正规的写法是:

for(i=1;i<n;i++)  
  
 t=a[i];  
for(j=i-1;j>0;j--)  
{  
     if(a[j]>t)  
     a[j+1]=a[j];  
 }  
 a[i+1]=t;  

 
假设一次赋值运算的时间为1,然后在最坏的情况,逆序的时候,我原来的写法需要移动的次数分别为1、2、3……n-1。一共是n*(n-1)/2次。每次移动实际是三次赋值运算,时间为3倍n*(n-1)/2。而正规的的写法移动次数分别是1、2、3、……n-1每次移动做一次赋值运算。最后的“插入”也是一次赋值。所以时间一共是n*(n-1)/2。所以我原来的写法效率与之相差太多啦。
 
怎么样,同样的**(额,其实是不完全相同),写出来的程序效率还是不同的。【以上内容仓促写就,或有讹误。】
关键点在于两者在于“插入”方法的处理上。我有这样一种设想,就是用链表的方式存储元素。插入的时候直接修改指针。时间效率或许会有提高。我也没验证。不过即使我的设想是正确的,可以肯定的是那将是一种牺牲空间的时间优化法。


后记 2017-09-13

现在看来当时写的分析比较拙劣。实际时间复杂度中的常数系数的大小是基本可以忽略的。

那些年我看过的日剧:《风林火山》

故其疾如风,其徐如林,侵掠如火,不动如山,难知如阴,动如雷霆。 ——《孙子兵法·军争篇》


既然看了这么久,所以决定写点什么纪念一下。于是撰了此文。主要目的还是给自己留点念想。看电视剧就像自己经历的人生一样,如果我们对过去发生的事没留下一点印象,那么感觉起来这些日子就像是白活了。
《风林火山》是我入坑日剧的早期看的剧,也是我看的第一部“大河剧”。那是在大学的时候看了五个星期终于看完了这部剧。庆幸自己当初看了这部剧,让我对大河剧产生了好感,从而打开了新世界的大门。 《风林火山》是日本2007年推出的年度大河剧。在日本,NHK电视台有每年播出一部时代剧的传统,日本的时代剧就是古装剧的意思。《风林火山》正是第46部。

img

在日本战国乱世之时,著名战神武田信玄在行军的旗帜上书写了这几个大字,从而使“风林火山”一词广为人知。的确,风林火山虽然来源于**,但在**历史上一直没有多大知名度,首度将这一词语从孙子兵法中提炼出来并加以推广的,正是日本人武田信玄,然后这一词语的热度从日本回流到**,**才开始频繁出现这一词语。 《风林火山》电视剧改编自同名历史小说,原作者井上靖。该电视剧的拍摄正是为了纪念井上靖诞辰100周年。全剧共50集,从武田信玄的少年时代开始,一直讲述到第四次川中岛战役为止。谈到日本的战国时代,不得不提的两个人就是号称甲斐之虎的武田信玄与号称越后之龙的上杉谦信。虽然这部剧是以甲斐国的视角展开的,但这部剧的主角却并非是武田信玄,而是他的军师——山本勘助。

山本勘助与其他影视剧的主角有很大不同,他是一个独眼,跛脚的邋遢形象。其实电视剧并未刻意丑化他,只是原原本本地还原他的历史面貌罢了。不过在**这种主角的造型还是很少见到。**的导演们似乎总在照顾“心灵脆弱”的**观众。比如《天涯明月刀》中的傅红雪,在古龙的原著小说中是个不仅跛足而且患有羊癫疯的形象,观众们很难和电视剧中的钟汉良联系起来吧。剧中山本勘助始终如一的信奉着“摩利支天”。摩利支天是佛教中的护法神,在日本广有声望。

虽然人们常说日本的历史剧都是村民械斗,因此对大河剧嗤之以鼻。但是即便如此,我认为就当是看一下械斗的套路又有何不可呢?我感兴趣的是剧中的历史故事,乱世之中,各国之间合纵连横的谋略和行军打仗的兵法诡道。剧中让我印象深刻的情节颇多: 起初堪助是个落魄武士,但是出于对兵法的热爱,他一心要仕官。在妻子美津被甲斐国馆主(即国君)武田信虎所杀之后,堪助先后欲仕官骏河的今川义元、相模的北条氏康以及信浓的真田信隆,为的就是和武田家对抗,手刃武田信虎,然而却屡屡不得志,后来因缘际会竟仕官武田家的武田晴信。从今川义元到北条氏康再到真田幸隆最后到武田晴信,这四个人对于堪助的好感度是逐个递增的。

今川义元对山本勘助基本上全无好感,甚至极为厌恶,瞧不起。当时我就感觉今川义元这人狂妄自大,迟早会被堪助杀掉。果不其然,在电视剧后半段,堪助的一手巧妙的激将法,借助今川义元厌恶堪助这一特点,所以没有采纳堪助的建议而导致自己被织田信长所杀。

北条氏康并不厌恶堪助,对堪助也还可以但是却也不肯重用堪助,只是派堪助去他国做个细作。堪助自然也是不开心了。

为了杀死武田信虎,堪助来到信浓,遇见了真田幸隆,真田幸隆还是比较欣赏堪助的,堪助后来也多次帮助他。但是当时的真田信隆虽然家大业大,却也只是一介地头武士,并无与甲斐的武田对抗的实力。

在武田晴信流放生父武田信虎之后,堪助决心仕官武田家。武田晴信是堪助最后仕官的大将。也是让堪助充分发光发热的人。只有他看穿了堪助的真意,看到了他的诚心以及才华。一开始就给了他较高的官职。

武田晴信(武田信玄)演得也不错,从十几岁演到四十几岁。随着角色年龄和身份的变化,演员的谈吐举止也随之变化,恰到好处。

剧中涉及到大量的战争,也是一大看点。花藏之乱时,山本勘助和其兄山本贞久身处两个对立的阵营,最后贞久一方战败,勘助想放兄长逃走,贞久却执意不走,而是让堪助为其介错①。这就是当时战国乱世之时克尽忠义的表现了。 海之口大战,是山本勘助第一次在战场上运用计谋,正是他的计谋使得一向只崇尚武勇的武田信虎吃尽苦头,从而不得不选择退兵。但是当在信虎退兵后,他的儿子武田晴信(后来的武田信玄)担任殿后工作,晴信在猜到海之口的守兵一定在为武田军退兵而松懈的时候,连夜发动奇袭。顷刻间以300人攻下了其父8000人都未能攻下的海之口城。

上田原之战是武田晴信自领兵以来初尝败绩。而这场战斗中武田家两位重臣板垣信方和甘利虎泰战死。这是由于先前的战斗武田晴信从未战败,甚至恐惧失败。所以开始变得骄横自大,以致像其父一般穷兵黩武。板垣信方之死是属于自杀式的,他的目的便是以死相谏。最终他的死,触动了晴信,改变了晴信对于战争的观念。另外一提,扮演板垣信方的演员演得不错的,而你想必也很熟悉他,他就是千叶真一,就是电视剧《风云》里的雄霸。

当然最惨烈的战斗就是电视剧最终回的与宿敌上杉谦信的第四次川中岛合战。山本勘助战死。除此以外,晴信之弟武田信繁及重臣诸角虎定也死于这场战斗。 武田晴信之弟武田信繁本来是其父武田信虎认定的继承人,在武田晴信流放了信虎之后,晴信以及家中诸位老臣都在担心信繁对此事的不满,然而信繁一番声泪俱下的陈述表明了自己一直以来对于大哥的心迹。那个桥段回想起来确实十分感人。信繁从此以后为了大哥也是克尽了忠义。

剧中除了山本勘助、武田晴信、真田幸隆和板垣信方以及宿敌上杉谦信外的重要角色还有很多。值得一提的一个角色就是平藏。这是个备受非议的角色,是一个虚构的小人物,目的大概是用小人物的视角描述大时代背景。平藏原本也是甲斐国人,深爱着美津,然而美津喜欢的是堪助。同样是由于美津的死,平藏和堪助一样走上了对抗武田家的道路,然而他们两人最总却走出了截然不同的路。后来堪助仕官武田家,但平藏还是继续和武田家斗争着,基本上武田每一次攻击的目标,都是平藏所处的阵营,从海之口开始,然后是诹访,接着村上义清的阵营,最后是越后的上杉谦信的队伍。他和堪助一样信仰着“摩利支天”,这也是他和堪助一直以来的羁绊。在最后一战的川中岛战役中,平藏背后中箭倒地,而在战斗结束后他从战场上爬起来,嘴里喃喃着厌恶打仗了,要回家安心照顾孩子,然后又倒地了。这时在尸体旁捡拾战利品的老婆婆阿福出现,剧中前面有交代阿福经常会在战场上救助那些不想死的武士。后文没有表述平藏的结局,但可以想象他受到救助之后痊愈,然后回到越后家中与家人团聚的场面。

此外还要说明的一点是这部剧的翻译工作,是日史译组和琵琶行字幕组联合完成的哦。这两个组都是经常翻译日剧的字幕组了。也足见重视程度。

①所谓“介错”是日本武士在切腹的时候,在身后为他补上最后一刀的人。因为切腹这个过程不仅要把刀插入腹中,还要继续横向地割一下。这个过程相当痛苦,所以在身后的介错之人会在切腹者最痛苦的时候将他砍死,来减轻他的痛苦。一般介错之人都是切腹的武士最为信任之人。

我的2015:行走篇

原写作时间 2016-01-12

2015前程似锦”这是2015年年初的时候我发的一句说说。这一年委实经历了很多,也成长了很多。即遭受过苦难,也享受过喜悦。开拓了视野,进一步清晰了目标。上个学期末的时候,就想好好写写自己的故事了,但是那段时间太忙,期末,接着课设,然后马不停蹄地跑到深圳开始实习。这后来也曾数度提笔,虽胸有千言,但终不成文。终于攒了一年的故事才发一篇。

寻找实习

三月初学校开学后,我就着手开始找暑期的实习了,这个目标是我在大二的时候,就计划好了的。因为我自感自己水平不够,项目经验不足,如果直接在大四参加秋招应聘的话,不会找到好的工作。所以我选择了一种曲线救国的策略,如果能找到暑期实习(难度应该比秋招低),然后再在大四参加秋招,这样我的能力和项目经验都有增长。当然如果在暑期实习就找到了好的公司的话,那么参加实习生的转正考核,应该也比直接参与秋招要容易地多。这就是我认为我能拿到一个好的offer的完美计划。

我不了解前几届学长们在大三的时候干什么,我也不想去了解。我只能管好自己,做好自己,我的目标是Linux相关的C/C++开发。海投,关注各类互联网公司的暑期实习信息,把它们的招聘网站都保存在浏览器书签中。各类招聘网站也投简历,简历一改再改。坑爹的南昌,好公司都不来的,笔试、面试地点只能投武汉。

在CVTE网上评测(好多行测题,坑)通过后,通知去武汉面试,不巧正赶上科目二练车(当时即将考试,自己渣得很),最终放弃没去。终于阿里内推,接到电话面试。一面过,二面挂。这次面试经历虽然没过,但是真地发现了自己很多知识盲点与不足,开始发力补足。开始看开源项目源码,开始深入了解C语言相关的内存布局的知识,开始看《程序员面试宝典》,这本书前面内容还好,后面越看发现错误越多,大家不要盲从。。这些努力,时间很紧,但这些零碎的进步也为后面的成功埋下伏笔。

转眼间,时间已到四月份,彼时很多公司好像我的简历都不过(小米,京东,等等。。)这期间也参加了腾讯和阿里的笔试(阿里内推挂掉还可以投普通的实习招聘),然后收到了蘑菇街去武汉的笔试通知,4月10号,一大早做了南昌到武汉的动车(这是我第一次去武汉,也是大学第一次在校期间出远门。果然我太宅了。),下午在华科听宣讲会做笔试。晚上在华科对面小宾馆煎熬地等电话,终于十一点多通知第二天面试。第二天,当我兴冲冲地跑过去的时候,结果一面就挂了。之前我阅读过蘑菇街的开源项目,改过小bug,之前以为他们很崇尚开源,还有很多对蘑菇街的鸡汤。本来我就想往这方面和面试官扯,面试官问我想去他们公司做什么,我就说想做这个项目。结果面试官说了一句,这是我们公司业余时间做的,没有全职。。心中顿时一万只草泥马奔腾。。也不能全怪面试官了,确实有一些技术问题没有答好(面试真的有时候看运气),虽然我投的C++,但我准备的C++知识都没用到(没问),他们不太需要C++(Java和PHP已经制霸**)。这天是4月11号,星期六。本来华科的朋友想面完请我吃饭的,但我挂了之后,一怒之下就买火车票回南昌了,期间在武昌站各种fuck(果然我太不成熟了,不针对任何人哈。)。这是我第一次跑这么远来面试,呜呜。

然后4月13号下午同学陆续收到腾讯的面试短信(貌似腾讯笔试没怎么刷人额),我有点慌了,我没收到呀。。直到晚上十点才收到短信。。好吧买票去武汉。4月14号又坐上了去武汉的火车,你要知道这离蘑菇街挂掉只隔了三天!!!我这是多大的勇气去面腾讯惹(主要是同学们都去面了,我要是不去,显得我好像笔试没过一样)。。在武汉待了三天,经历三面,最终拿到暑期实习offer。具体腾讯面试的情况,请阅读这篇博文《2015腾讯暑期实习武汉站面试经历》。经历了很多波折,好辛苦拿到一个实习offer,后来我才知道,我们学长们很少有这么疯狂找实习的经历(很多是在南昌本地找个实习)。近来咨询我找实习相关事宜的学弟学妹越来越多,有从我这届开始,学弟们有很多都开始准备大三下找暑期实习了,敢于走出大山,去大城市找实习了。不期然成了开风气之先者。

在拿到鹅厂暑期实习的offer之后,也收到了5月份阿里巴巴武汉面试的通知。不过我并没有再去面,原因后很多。其一:阿里巴巴主要是Java岗,C++极少,虽然招聘职位有C++,但进去之后很多都是要转Java的,,倒不是我有我讨厌Java,这两门语言我都学过(C/C++更深入些),只是目前我更喜欢C++,我是想先好好打磨好一门编程语言,以后有精力或者有需要再去深入了解其他语言。其二:我究竟不是武汉本地学校,每次跑武汉面试(除了路费,可能还要住一晚)实在是花销挺大(我很穷的。。)。其三 :我是个知足常乐的人。。

实习之路

7月10号,我踏上了南下的实习之旅。这是第一次来深圳,乡下人进城啦。之前4月份在武汉等offer的群里水群,结识了一些友爱的小伙伴。。后面过渡住房住完以后,也是在友爱的小伙伴带领下在宝安区找到了一个还不错的窝。我实习了总共将近三个月,很巧的是,几乎和“**好声音”同一步调的。之前这节目宣传的是7月10号开播,后来不知道为什么推迟了一周,最后10月7号总决赛。而我最后是10月8号结束实习的。。呵呵。

虽然在实习,也一直在琢磨怎么更好地拿到转正的offer,这时的压力比找实习的时候更大了。开始我是不怎么想再海投其他公司了,毕竟C++的互联网公司不好找了。鹅厂也不错,努力争取通过实习生考核才是王道。但是事情发展的太突然了,8月份刚开始一周,公司就通知开始考核,虽然来了将近一个月了,但基本是学习阶段,代码都没写多少,一下子就慌了(本来组里给我的计划是九月份进行考核的)。这时我真怕最后无法转正,所以就不再把鸡蛋都放一个篮子里了,又开始悄悄地海投起来(毕竟在实习,不能太张狂)。彼时在实习生圈子中,各种考核难度大、留用几率小的言论甚嚣尘上。

考核流程中,从考核启动,再到导师、leader(组长)提交考核评价。这中间只有8天左右的样子。真是急死我了,中间还有两天去惠州部门旅游。。虽然两天不用上班,但也真是食不知味、睡不安枕,不过不得不说玩得挺开心的,吃的不错,住的五星酒店也不错,还抢了不少红包……旅游回来就是周五下午了。周末我必然是在公司忙着敲代码,紧赶慢赶终于把几个功能实现了,简单测试了下。。后面快到考核截止日的时候,又听说其实时间没那么死,所以leader当时也没提交评价。心里好忐忑额。。然后导师告诉我要做ppt在组内答辩一次,leader再评。好的。又是连续几天作战,写ppt,周末又耗在公司了,我之前确实没有做ppt的基因额。。憋了好几天,终于搞出了40页的ppt。哎。某个下午,ppt演示,答辩,考核over。。
人事已尽,其余听天命。

后来听导师说,leader在听了我答辩之后,对我印象不错,以前是我和他没怎么接触,所以他不怎么了解我(实习岗位的leader不是面试我的leader)。好吧。我心安了。不过这不并不意味着,我接下来的生活就轻松愉快了。工作还是要继续,每次开会的时候都会发现自己的不足。工作也经常累得喘不过气,太多不懂的东西了。。基本上从八月到九月,我晚上十点下班就成了家常便饭……

九月初,“拥抱变化”的一则通知在阿里校园招聘的网上亮出。不仅许多参加了笔试的同学很难获得面试机会,并且连阿里自己的实习生都很难留下。彼时,阿里缩招的消息已经在网上炸开了锅。大概是由于八月份的股市震荡,专业名词叫资本寒冬,后来又传出来今年是“互联网行业的寒冬”,各大公司缩招的消息层出不穷。数阿里最甚,主要原因是阿里校招的内推开始的极早,早就发出了数百offer,本来计划是校招一共招3000,后面传言是缩减为400。各种阿里实习生找下家的QQ群异常火爆。。九月初我竟意外收到阿里电话让我去广州现场面试,八月份我参加校招内推的时候面到二面以后,内推就结束了。这时候阿里校招的笔试是没有参加的,收到电话之后虽然也有些激动,但是我最后还是没有去面。。首先面试时间是周一,工作日额。。我实在不太会编谎话去请假面试。另外既然传出了缩招的消息,想必去了也很难通过(我承认是有点怂),最后还是老问题,我还不想转Java。。先玩几年C++,玩腻了再换呗。。到后面发现缩招确实是真的,之前阿里在内推的时候已经发出去的offer是不能单方面撕毁的,所以阿里就拉低了这批人的工资,6k,8k都有。这是一种羞辱。。逼一部分人主动退出。

后面我盘算着,国庆节回来10月8号就离职吧。所以9月30号就是我的最后一个工作日了。9月25号星期五晚上,我和leader说了离职时间以后,我本以为未来几天可以歇歇了,结果……leader说要走了,那就再做个ppt做个总结吧。我:好的。这个周末又赶紧跑来公司,做ppt,整理文档。关键是上个月,我汇报过一次了,这一个月,其实也没做太多东西。所以还要多写点代码。把写过的代码再好好优化、测试一下。我上次答辩暴露的问题,再整理一下,修改一下。。为了在内容上突出这一个月我没偷懒(其实这个月堕落了些。)而绞尽脑汁。好吧。

终于,即将尘埃落定,在汇报前一天晚上,一切都准备就绪。当我即将下班的时候,我把本地的代码提交上去。结果出了问题。。擦,不是吧,这么背。本地运行的好好的。结果线上会出问题。。赶紧找了测试的实习生基友过来帮忙。。折腾了好久,大概发现问题在哪了,天色已晚,我赶紧回去了。。第二天一大早,六点多钟,我没等班车(班车八点)就坐公交来了公司,开始处理问题,问题已经找到了,解决还需要一点点时间。九点多钟。OK,终于成功。赶紧去吃了个早饭。。这时最后一个工作日,哎,真是醉了,下午组内汇报。。虽然我功能实现了,但是暴露出来了很多设计上的问题,各种设计不合理,还有考虑不周。除此之外在其他方面也暴露了问题。。。这让我知道我未来的路还很长,同事也安慰我说,发现问题是好事,工作很长时间,发现不了问题,那才不得了。。我想想也在理。。除此之外,还交心的谈了一些其他东西,比如我和他们座位比较远,组里和我联系不多,让我受委屈了。导师说有时候吃饭忘了叫我……这时真的好感动。 

总的来说。实习三个月,快乐与压力并存。。我的很多同学,在后来看我拿了offer,总觉得我很幸运。但是都没有看到我多少次十一点钟才到家(租的房子),这里面又有多少次是头痛着回到家的。

“选择比努力更重要”,这是我的座右铭。有些人可能觉得不能理解,他们认为努力更加重要或者认为做选择是件十分容易之事。其实不然,选择常常要伴随着巨大的勇气,还有敏锐的洞察力。比如我个人时常絮叨的转专业啦、一改再改的技术路线啦、退出学校某实验室啦,不去考研去找工作啦等等等等。每个人都应该结合自身状况做出适合自身发展的选择。我不能说我没有做过错的选择,很多选择在一开始我也不知道会通向何方,但我会不停地观察不停地修正。。我也不能说我自身的选择有多么优秀,我只能说这更适合我。我并不会鼓吹找工作就比读研更好,也不会宣扬做后台就比前端更有前途这种话,我认为这都没意义。。关键不是要找出一条容易成功的路,而是找出适合自己的路。 

后来,同学、朋友包括网友,喜欢让我推荐书籍。经典图书我也看过,想必我不说他们也应该知道。但我并不迷信这些经典图书,我同样看了很多不知名的书籍,很多已经叫不上名字。通常我都是想学什么或者遇到什么方面的问题就去图书馆找书,只要里面的内容能帮到我,我就借走。通常不可能整本书都帮到我,甚至其他部分会写的很差,但都没关系,我就只看有帮助的这部分,看完可能就还回去了。这样的书籍我是实在叫不上名字了,太多了。有目的性的去阅读,学习效率是很高的。


后面将感悟部分单独成文:我的2015:感悟篇

2015腾讯暑期实习武汉站面试经历

原写作时间 2015-04-24

不得不吐槽一下腾讯的面试短信。在面试前一天(13号)晚上十点半才收到,通知14号下面四点半面试。我赶紧去楼下打印了两份简历。后来看了一下列车时刻表,其实也不用太赶。第二天坐上十点半的动车从南昌出发去武汉了。细节不表了。

先介绍一下我自己是南昌大学的,非985,不是很有名气的211。在面试腾讯之前也有过两次失败的面试经历,虽然失败过两次,但也掌握了不少经验,不只是技术方面的,还有面试技巧方面的。所以说有面试的机会,大家都应该去参加一下,即是过不了,经验也是蛮宝贵的。在去武汉的动车上,我心里也是没底,总结了自己的三大软肋:

  1. 学校一般。(非985高校。武汉高校众多,除了华科武大以外,其他学校也是蛮不错的)
  2. 没项目经验。(这点不仅是软肋更是硬伤)
  3. 本科。(实际上本科生还是应该有自信才好)

我面试的岗位是后台开发。不过此后台非彼后台。很多人一听到后台,就以为是web后台:java web、php什么的了。腾讯的后台指的是Linux服务器开发。涉及C/C++网络编程等技术。总体来说,两个面试官还不错,问的问题也比较基础,大概是因为我是本科生的缘故吧。其实我也有没答出来的。但是他们似乎也并不要求百分百正确,没那么严格,就让我过了。所以说他们人都比较nice。听说其他后台开发的面试官还有考察英语的(为我的面试官默默点赞)。

一面:leader

leader低着头:说说你的项目经历

我惊了,我没项目经历:……没,之前学android的时候做过app,学Qt时候做过计算器,现在Linux
C/C++倒是没做过。(我报的岗位是后台开发linux c/c++)

leader:哦,都是图形化的东西,后来怎么不学android了。

我:后来发现对于偏底层的东西更感兴趣,应用层开发不太……

leader:很多人觉得底层就比应用层的好,实际也不是。学着学着android,突然就讨厌android了,是吧。

我:没……,也不能说讨厌吧。就是不知道为什么就喜欢C/C++了。

**        接着都是对着简历问的。**
leader念着我的简历:熟悉常用Linux编程API。笑着说:那你说说你会用哪些API

我瞬间头脑风暴:基本的open啊、create、read、write。进程管理的fork、vfork。还有……
一下子不好列举了,顺口说了个:退出exit,还有带下划线的退出(_exit)

leader打断我:说说带下划线和不带下划线的区别

我:不带下划线的会刷新数据流缓存,比如你有打开的文件,如果用exit,就能保证在退出的时候把缓存区内容写入文件。而带下划线的(_exit)则不会。实际上exit更推荐使用,但带下划线的(_exit)效率更高

leader:说说fork。它的子进程和父进程的内存空间如何

我:内存空间不共享,子进程直接copy的父进程的内存空间。比如你一个父进程中的变量被修改了,在子进程中这个变量不会变

leader:fork返回值大于0表示什么

我:当前进程是父进程啊。这个值就是子进程的id

leader:返回值等于0呢

我:子进程

leader此时诡异的笑着说:等于-1呢

我:那就出错了啊。

leader:说说进程和线程的区别

我blablabla大概讲了一下,凭着操作系统课仅存的一点记忆,就谈了一下进程包含多个线程啊,进程是资源分配的最小单位啊,线程的调度的最小单位啊之类的。后来leader问我关于两者存储区相关的内容,哪些东西是共享的,哪些是私有的(线程有自己的私有栈和私有全局变量)等等。我这里答得并不好。

leader:假如有多个进程同时对一个文件进行写操作,会出现什么问题

我:……写入的数据就不理想啊,达不到你想要的效果……这个不是进程安全的

leader:你怎么知道我想要什么效果。。

我:比如你想依次向里面写数据。但你实际多个线程写入的时候得到的数据是错落的(自己实在无法很好的描述……)

leader:那你怎么解决这个问题

我:锁。。额不对。我知道线程有互斥锁(mutex)。进程貌似没有啊。。

leader:这个不知道了吧。。

我:恩。。。

我心想面试官真是打破砂锅问到底一个问题无限延伸,从开始的介绍API,到最后如何解决安全的进程读写。。其实是一条线牵扯出来的问题,我到这里终于戛然而止,他诡异一笑,似乎也是因为把我问住而感到满足。

leader:接着说说你用过的其他API吧

我:还有信号相关的,比如signal注册信号啊,raise、kill发射信号啊等等。其他的还比如说网络编程的几个函数

leader:说说网络编程服务端的几个函数调用的顺序

我:bind……

leader笑了一声:上来就bind???

我:哦哦哦,socket,先调用socket函数获得套接字。然后是bind、listen、accept。这时候客户端connect

leader:奥,接着你说说Linux里面常用的数据传递的方式

我疑惑了一下:数据传递?是说IPC是吧

leader:对,并说说它们各自的特点

我心想:这是腾讯笔试的时候考过的,当时就是凭着自己的理解填的,万万没想到面试还会问这个,所以没有准备和整理过标准的解释。。这里还是要凭自己的感觉说一下

我:先说管道吧,命名管道或者叫知名管道(fifo),它把数据存在文件里,实现了一个数据的持久化。非命名的普通管道(pipe)可以用于数据量比较小的数据传输吧,可以即取即用,多用于组合多个命令,灵活性很大。信号的话呢,可以实现一个异步的功能吧……

leader:说说什么是异步,如何实现的异步

我:异步就比如说,你一个费时的IO操作,我不去等待他完成,而是去做其他事去了,接着等IO操作完成了发一个比如SIGIO的信号通知我,我就在接手,大概就这样吧

leader:接着说其他IPC

我:剩下的就是系统五(system v)的几个IPC了:消息队列、信号量、共享内存。信号量就是一个操作系统里的概念,PV操作。当进程资源有限的时候可以通过信号量来完成某种操作,还可以同步。

leader:具体说说这个PV操作。比如你有一个资源数量有限,有进程申请的时候就减一,释放的时候就加一。数量的为0的时候如果要申请就要等待。啊。对了,刚才说到的多线程读写可以用信号量来实现同步操作啊。这样答对么

leader想了想,说:恩,也可以实现,不过实际上我们一般不这么用,有更轻量级的实现方案

后记:后来面试完我搜了一下我来发现fcntl这个函数可以实现文件锁。另外还有flock函数。。前几天还看到这个了。当时就忘了,只想着给进程加锁。。其实是给文件加锁啊。

这时候他接了个电话,叫我出去等。。然后一会就又叫我进来了。

leader:刚说到哪了?

我:IPC啊,信号量说完了。另外还有消息队列,一个队列,先进先出,没什么好说的(实际上真的忘了如何说了。突然头脑混乱发现命名管道和消息队列都是先进先出的,如果他问起来有什么区别的话,我还真不好答。于是一笔带过了)。还有一个共享内存,这个是效率最高的一种IPC了。

leader:为什么效率最高

我:因为其他进程直接直接可以访问别的进程的共享内存空间啊。根本不用什么数据传递什么的。

leader点点头

我:最后一种IPC就是socket,适用于网络编程

leader:你这都是从《Unix网络编程》书上看来的吧。书的内容你倒是记得清楚。

我笑了笑:《APUE》、《UNP》都是入门经典嘛。
(心想:这几个解释不是从书上看来的啊。《UNP》那本书没看多少。。)

leader:网络编程中也会用到一些IO多路复用的函数,你知道吗

我:……知道名字。selec/poll/epoll。具体怎么用就不知道了。只瞻仰过这几个函数。

leader:……

        到此第二次知识延伸结束

leader:说说C++的特点。

我:效率高啊。

leader:效率高。是相对Java说的吧,你说说为什么比Java效率高。

我: Java首先它用了虚拟机啊(JVM),还有就是C++有指针操作啊,这个效率很多,Java直接去掉了指针。另外Java是一种安全的语言,里面各种类型检查。C++很多地方没有类型检查抛弃了安全性,获得了效率。(另外Java还有包括GC这种浪费效率的东西,我还没答,面试官就继续发问了)

leader:和C语言比较一下。

我:C++继承了C语言的优点。效率高就是从C语言那来的。另外它还比C语言增加了面向对象,模板等等这些东西。面向对象多了一层抽象,增加了代码的可读性,也实现了代码复用,可以减少编程的工作量。

leader:说下面向对象的多态。

我:这个多态呢,我理解是有广义和狭义两种认识。广义上来说,重载和模板这种也算多态,属于编译时多态。狭义上来说,动态绑定,比如虚函数啊,子类对象给父类指针赋值,这种是运行时的多态。很多地方普遍说多态就单指的是运行时多态。

leader:动态绑定是虚函数吗?

我懵了:是吧。。动态绑定就是虚函数实现的吧,它是以虚函数表实现的。

leader:说说这个虚函数表。

我:……我可以画一下吗?

他说可以。面试的都有一张白纸。我就开始画,然后开始解释。后来它给我举了基类子类的例子让我画。我之前看到过虚表的图的,就画出来了。还给他解释基类里面有一个指针指向这个虚函数表。而这个虚函数表是顺序存储的,不是链式存储的。后来又给了我三个有继承关系的类的对象,让我判断到底调用了谁的函数。还是虚函数问题。

        到此第三次知识延伸结束

我简历上写着:熟悉TCP/IP协议族,熟悉常用数据结构和算法

接着对着我的简历说:说说TCP三次握手。

我啪啪啪解释了一遍这个过程。具体描述就不表了。接着他又诡异的笑了一下:说说为什么是三次,而不是其他的次数。

我心想这个问题之前学计算机网络课程的时候,考过。当时花了点时间,大致描述出来了。反正就是多次握手,多一次保证吗。但是现在让我答,我没时间一点点的推导了,就说:我描述不好,再画一下吧。我画了三次握手的图,连SYN和ACK都画上了,还有+1。但是也没描述好,他也说我没讲明白。我心想跪了。又问了一下和udp的区别,面向连接什么的。我说不好准确的定义,就是按自己的理解答的。他继续针对我回答的细节继续发问,跟我钻牛角尖。。我是真的无语了。。心凉了。

接着换下一个问题:说一下快速排序的过程。

我就给他讲了一下第一趟排序的过程。笔试题面试题很常见的问题。不过他接着问:说一下第二趟。。
我其实还真没考虑过第二趟,因为平时也不好用代码实现快排。。都是qsort()、sort()。这第二趟,开始卡主了后来推理了一下,也说出来了。关键就是第二次如何选取新的基准,如何进行递归(或循环迭代)。

leader:恩,那分析一下他的时间复杂度。

我:N*logN。

leader马上笑了:你这是背下来的。给我分析一下为什么是N*logN。

我无语中。。大致给他分析了一下,之前确实也没做好快排功课。他再次跟我钻牛角尖,说我哪里没说清楚。我继续无语……

        第四次知识延伸结束(实际上并没有很好地让他继续把问题延伸下去。。囧)

他说:恩,我十分认可你对书本上内容的记忆能力。但是你虽然记住了这些概念,却没有去挖掘为什么是这样。

我心想:坏了。该打道回府了,这个评价不怎么高啊。算了,反正很多从南昌来的今天都回去了,我还是也回去吧。但是现在五点多了。还能回南昌吗。要不住一晚再走吧。

leader:写一段代码吧。统计一棵二叉树中只有一个孩子的结点的个数。

我问了一下:可以用全局变量吗? 

他说:不限制

这个还是很简单的。。啪啪啪就写出来了。给他看了。

leader:今天就到这里吧,如果有后续面试的话,再通知你。

我:奥。谢谢。请问多久会有面试结果。

leader:两三天吧。

我:奥。那我回去了,我从江西来的……

leader:什么,从江西来的。他看了一眼我的简历:南昌大学。你说你回去了是什么意思?回武汉还是南昌。

我:南昌啊。

leader:回南昌?你要是明天面试怎么办。

我:你不是说两三天吗,如果有二面我再坐动车回来。

leader:两三天,两三天也有可能是明天啊。

我愣住了。心想:两三天包括明天么。我说:那我住一晚,明天再走。等等通知。

leader:我的建议也是住一晚。

我:。。。。


从leader房间出来,一查微信里的面试状态,果然已经显示到了复试环节。后来晚上收到了复试短信。第二天(15号)下午两点半复试。赶紧开始准备,把一面暴露的问题,整理的了一下。又对之前不太熟悉的内容进行了一下深入的挖掘。因为涉及到很多Linux的问题,我需要亲手在Linux系统上测试才行。但是宾馆里的电脑显然是Windows系统的,幸亏我有一台云主机,虽然好久没登录了,然后我在Windows上下载了一个Xshell,通过ssh远程连接的云主机上。哈哈,我就有Linux系统可以用了,期间各种man,还有各种编码来测试Linux环境编程的几个API,一直到了半夜一点才睡。

第二天上午又各种整理问题,知识点:linux、TCP、算法等等。下午我到了等候的地方,其实并不紧张,我想不论二面结果如何我都不算输了。能到二面,已经很不错了。


二面:总监

面试官:先介绍一下自己

我:我来自XXX………………

面试官:做过什么项目没有。

我心想:天呐,没有项目经验果然是硬伤啊。一面能混过来,二面恐怕真的要折戟了,都说二面是技术压力面。。没项目经验的我真是难搞。

我就又把安卓做过app谈了一下。

他当然对安卓不感冒。问:Linux上C/C++的项目做过吗?

我:……没啊。这个这个不怎么好做出项目来。。(呜呜)

        开场白结束……

面试官:讲一下链表和顺序表的区别。

这个问题很简单。我blablabla……关键点就是数据结构本身,以及查询和插入删除的效率。另外还谈谈链表能利用零散内存之类的。

面试官:C语言的存储区了解吗,说一下堆和栈的区别。

我:堆,malloc的就是堆上的内存啊。函数内部的定义变量,非静态的变量,就是在在栈上啊。而且栈上的内存,在函数结束后会自动释放,而堆不会。并且它们的地址空间的增长方式不同,栈是从高到低,堆是从低到高。

面试官:如果数据量比较大,那么应该存在堆里还是栈里比较好。

我:堆啊。栈的空间有限制啊,很容易爆栈啊。

面试官:你遇到过爆栈吗?什么时候?

我:定义一个比较大的数组,有时间就会提示爆栈。

面试官:编译器提示的吗?

我:恩。还有递归层数太多也会爆栈。

面试官:栈有最大空间的限制?

我打断了他:对啊。因为占地址空间的增长方式可以看出,它上面是封顶的嘛。

面试官:你说说栈允许的最大的空间是多少。

我:……这个没研究过,应该是几兆吧,一兆或两三兆的样子。

        语言能力考察完毕

面试官:奥,不知道是吧。你Linux用的怎么样?

我:还好吧。Ubuntu和CentOS都用过,挺喜欢的。

面试官:你喜欢用这个系统还是?

我:开始我是喜欢用这个系统,后来慢慢地开始喜欢上Linux上面的C/C++开发。

面试官:那你说说socket这个过程。

这个问题一面我回答过了,不过这次我回答的更好。因为一面结束后我又整理总结了一下。在回答的时候不止单纯地谈函数本身,还穿插一下TCP的三次握手。比如到客户端connect的时候,服务端accpet就会返回一个套接字。这是三次握手就完成了。

面试官:如果一直没有connect连接,accept这个函数会怎么样?

我:会阻塞啊?

面试官:阻塞肯定是一种不好的现象,那么你有什么办法解决吗?

        其实对于这个问题,可选的解决方案有几个,我不知道他问的重点是什么。给套接字设置非阻塞模式可以方式accept阻塞。这是应该不是他问的重点。我想得到的答案应该和高并发有关,比如用信号实现异步,或者使用pthread库的函数实现多线程。但这些我都不熟,我就说:有个IO多路复用(一面结束之后我好好恶补了这个IO复用)

面试官追问:IO复用你用过吗?

我:……没,但是我有了解过那个函数,比如select、poll和epoll。

面试官:描述一下select这个函数的过程。

然后我就开始边说边比划
我说:比如说你是内核,我是用户进程。select函数有几个参数,写的fd(文件描述符)、读的fd、出错的fd。然后我要一次一次地像你轮询检车这些fd的状态。对了select还有个参数是时间。select它的效率不如epoll高……

面试官:epoll效率为什么比select高。

我:epoll是用了回调函数啊,我把fd和回调函数丢给你(内核),然后我不管了,你去检查fd的状态,就绪的时候就执行回调函数,然后再把结果返给我。另外select还有个最大的fd数量限制是1024……

面试官:那为什么要有这个限制呢?

我:这个……凭我的理解吧。select每次调用都要把fd从用户态复制到内核态,这应该是一个效率很低的操作。那么如果对fd的数量不加以限制的话,这个系统的效率肯定很差。

本来我还想接着谈谈epoll的水平触发和边缘触发,但感觉自己恐怕也描述不好,就没提这个。面试官倒也没问。

Linux环境编程考察完毕

面试官:平时编程用什么?

我:gcc啊。

面试官:调试呢?

我:gdb啊。然后写完之后我通过同git保存到github上。

面试官:如果你想调试一个文件,gcc编译的时候要加什么选项?

我:-g啊!

面试官:说几个gdb里面的命令。

我:start啊。n和s啊。

面试官:n和s的区别。

我:s会跳到函数内部,n不会。其他的命令比如disp显示一个变量值、p打印一次变量的值。等等。

面试官:恩,那程序有的时候会出现段错误,你有没有分析过这个错误文件。

我好像看到过,段错误,核心转储会有一个core文件什么的。但我也没分析过啊,就回答:没分析过……出现段错误,我就改程序去了。囧。

面试官:奥。那你Linux里面的常用操作熟练吗?

我:还可以吧。你说的是命令吧。

面试官:那查看当前系统进程有哪些。

我:(内心OS:太基础了)ps aux

面试官:接着查看进程名中包含abc的。

我:加个grep吧,我写一下。(拿了面前的纸开始写):ps aux|grep -E "*abc*"。你是想查这样字串吗?

面试官:可以。那这样查找的话,也会把查询的这条grep这条命令本身给显示出来,你能让查询命令的输出不显示这条命令本身吗?

我去……前几天才看到过类似的。这么巧就问到了。我接着写:ps aux|grep -E "*[a]bc*" 加一个方括号。

面试官:原理是什么?

我:……原理我倒是没研究过。之前我是查看指定pid的进程的时候,加个方括号就能屏蔽掉grep本身。原理应该是个正则吧,我也说不好(方括号确实是正则,但这个正则如何实现了屏蔽命令本身的功能,我真就不得而知了。其实另外一个合理的解答是适应 -v 选项过滤掉grep本身)

面试官接着问:继续,统计一下有多少这样的进程。

我疑惑了一下,心想 wc -l是可以统计文件内的行数的,把前面grep的结果写入文件,再用wc -l肯定是可以实现的。但是感觉太low了。这样是两步命令。我又忘记了wc到底支不支持管道。然后我自己念叨:wc -l。可能不是?

这时面试官说:wc -l难道不是统计吗?

我:奥奥奥。(面试官人还是很nice的)经历一点波折,我后来写了出来。ps aux|grep -E "*abc*"|wc -l

Linux基本操作考察完毕

面试官:你平时上网做什么?

这个就随便谈了。
我:CSDN、github逛地比较多。在CSDN上喜欢写写博客。
扯了一会CSDN和github

 第一次闲扯结束

面试官:计算机专业的基础都学了吧,数据库学过吧。

我:恩。学过(心想这样问,恐怕是要问第几范式的问题了吧)。

面试官:用数据库做过东西吗?

我:上课做实验我用的就是MySQL。

面试官:奥,比如一个表很大,如何提高查询效率?

我脱口而出:拆表。

面试官:除了拆表,这里不考虑拆表。其他方法。

我也是好久没复习数据库了,竟然说了个”存储过程“

他说:存储过程能提高查询效率吗??

我突然恍然大悟:索引啊,建立索引。

面试官:你说说你用过的索引。
我:主键索引、唯一索引。非空……哦不,非空是约束不是索引。

面试官:恩,约束不是索引。你们平时做的东西数据量应该不大吧,也会用到主键索引吗?为什么。

我:会用到啊,用主键这是一种规范吧。每次都会写primary key的。

面试官:那你说说索引为什么能提高查询效率。

我:索引是用了哈希(hash)吧。

面试官:索引是hash实现的吗??

我楞了,好久没研究数据库了,觉的是hash啊。突然想起了mysql里面可以手动选择索引类型的有hash和B+树。

我就说:不对,索引它有两个方式啊。hash是一种,另外还有B树/B+树。

面试官:说说B树和B+树的区别。

我……这个只有大概印象,简单敷衍了一下。

面试官:不记得了是吧。那说一下hash的时候处理冲突的方法

我:拉链法啊,开放定址法啊。开放定址里面有什么线性探查法啊、平方法啊之类的。

         数据库考察完毕(涉及算法和数据结构)

面试官:排序算法你熟吗?说一说。

我:常用的有七个吧:冒泡、插入、选择、快排、归并、堆排序,另外还有个希尔排序。

面试官:时间效率最高的是哪些算法?

我:快速排序、归并排序、堆排序。它们的时间复杂度是 N*logN。

面试官:描述一下快排。

又是快排。这是比一面的时候说的要好一点。吃一堑长一智嘛。面试官对我的回答也表示赞同。

面试官:你拿纸写一下,给你两个整型变量,在不引入第三个变量的时候去交换它们的值。

这个简单,我说:异或啊。

面试官:写下来。

我啪啪啪写了出来:

a = a^b;  
b = a^b;  
a = a^b;  

面试官这时候说了一句话:你做过这方面训练是么?

我不知道他说的这方面是哪方面,指的是刷面试题?还是说位操作啊。我不知如何回应,就说:我之前有看过这个。

面试官:还有一种方法是用加法实现的,你会吗?

我:加法。有点……印象。

面试官:这个没看过了吧。

我:等会,我推导一下也能写出来。

然后就简单推导了一下,写了出来:

a = a + b;  
b = a - b;  
a = a - b;  

面试官:这两个哪一个好?

我:第一个啊。异或效率更高啊。

面试官:不考虑效率问题,第二种实现还有一个问题,你知道吗?

我:会溢出吧。

面试官:第一步加法的时候,是吧。所以实际我们使用的时候还是采用第一种方案。

我:恩。

        算法提问完毕

面试官:你们什么时候放假?

我:……大概七月中下旬。

面试官:实习时间很短啊!

我:一个多月吧。

面试官:不到一个月。

内心OS:感觉不妙啊,他们肯定希望实现时间越久越好

面试官:你们大四有时间吗?

我:有啊。

面试官:学校让你们出来实习吗?

我:不限制啊。可以实习。请问可以从暑假到大四一直连着实习吗?

面试官:我们公司非常鼓励这种行为啊!

内心OS:……果然是廉价劳动力

我简历上写了意向事业群是TEG。他就问我是不是冲着TEG来的。我说也不是啊。其他的事业群也可以,只要不是让我做移动端就行啦。他说:那肯定不会,肯定是做后台。

        第二次闲扯结束(后来知道他不是TEG的,是CDG的,而我最后被录到了CDG)

接下来有点冷场,貌似没什么可说的了。

接着他又说:那这样,再问个问题。比如一个班级有50个学生,求至少两个人生日相同的概率。

想了一会确实不会。

他说:再想想,说个思路也好。

我:……不会。概率学的不好。

心想。大风大浪都过来了,最后竟然是概率题,难道在概率这里折戟?

       后来面试完,百度了一下才发现。其实很简单的。只要求它的逆命题(所有人生日都不相同的概率)再用1去减掉就行了。

面试官:那你写一个链表逆置的代码,写关键部分就行了。

没想到会考链表这么low。没准备链表,倒是准备了二叉树。细节记不准确了,写的时候涂涂改改,不过后来也写出来了。

        编码能力考察完毕

这时候时间也差不多了,我该走了。又问了一下他复试结果什么时候出,他说一两天吧。

我说我明天可能回去了(我感觉二面过的几率不怎么大,毕竟有些题目还是没打出来,比如概率题,还有B/B+树)

面试官:那如果面试你能赶过来吗?

我:可以吧。南昌到武汉动车大概三个小时。车站到这里不到一个小时。如果你们是下午面试的话,我上午过来,还是赶得及的。

面试官:这个具体面试时间是系统发的,不确定。不知道他们HR……那这样,如果你到时候赶不过来,一定要和HR联系。

我:恩。

心想:我哪里知道什么HR的电话啊。但我也没敢问。后来所幸的是,一出酒店用微信查状态就看到进入HR面试环节了。晚上就收到了短信,通知16号上午十点半面试。总的来说,二面并不算技术压力面,依据基础。


三面:HR

HR面其实都是扯淡。一切问题都是纸老虎。HR一般没有刷人权力。虽然有人在HR面之后也会挂掉,但这并不是HR刷的。据我的了解是在三次面试结束之后,HR要和前面两个面试官对你进行综合的评价,然后再进行排序,择优录取。当然了其实面了HR之后挂掉的我感觉真的不多。前两面很重要,一面的leader就是你以后的leader(这个其实也不完全一致),二面的总监也基本上是你以后的总监。之所以为什么被调剂,实际上有时候面试你的面试官是随机分配的,虽然在网申的时候有让你填写意向的BG(事业群),但实际上并不一定是这个BG的人来面你。

十点半进去面试,十一点出来。我就直奔武昌火车站了。手机买好了票,下午三点开,在车站坐了蛮久,七点多到南昌(这车还算快)。没买动车,买的普通车硬座。因为来一次武汉交通住宿都花了蛮多钱了,不过这是投资,还算值得。


后来等了8天之后(4月24号)下午终于接到了录用的电话。在这8天里也是经历了各种心里上的煎熬,从查询微信状态开始,到后来看到别人陆续接到电话,自己也是不淡定的很。期间在等offer群里各种水,和大家群聊也算是煎熬的一周里最好的慰藉了。

后记

2018.4.21
如果把大学生活,比作一幕戏剧的话,那这三天的面试经历,真的算是大结局之前的高潮了。感谢当年那个虽懵懂但不惧世俗,顽强拼搏的自己。

水题

原写作时间 2013-04-02

这几天,为了赶快冲击ac100题的记录。刷了很所水题。尤其是杭电第11页。昨天一晚上刷了五道。今天中午又一道。已经98道题了,清明节前,应该能到100题。刷题很爽,但是刷水题我心里总是不那么快乐。不那么舒服。换来的不是喜悦,而是更多的空虚。

有人说刷一百道水题,不如刷一道难题。诚然。我以后会少刷一些水题。多刷一些难题。还有就是数据结构感觉难度越来越大了,或许是结构体,与指针没有用好的缘故吧。这几天想做一做数据结构的题目。数据结构这是基础。很重要的。

水题,甜美的毒药。

转专业的事不知怎么办了。文件上没有明文规定说挂科不能转。但是有很多人说是不能转的。哎 。或许我是学不了计算机专业了。但是学习通信也没什么不好,毕竟南昌大学通信还是很强的。我对通信还不是很了解,但我希望它能多一些编程的东西。

关于语言,我总想学学java或者python。但是时间又不够。还是先抓好基层的算法吧,毕竟我想学的东西太多了,SQL数据库也是想学的,昨天得知一个英语专业的文科生同学在考计算机二级的ACCESS,额,我顿时感慨万千,是不是什么人都会编程了。发现计算机二级证书是越来越不值钱了。什么人都要考一下,都可以考一下。

时间感觉越来越不够用了。我有挂科的预感了。

还有就是今天lcy说他不搞c#和ASP了。不搞后台了。额。呵呵(苦笑),我们班上的技术男又少了一位?真不知道为什么,游戏真的有这么大的魅力?我不知道。

社交网络这部电影很好看,可惜这样的电影太少了。

记一次阿里电面经历

原写作时间 2015-03-20

昨天下午(3/19)三点多钟,接到了一个杭州的电话,是阿里的。问我是否方便聊聊,我说我在上课,四点下课。然后他就四点多钟的时候又打了一次过来。

1. 项目经历

上来就问我有无大型项目的经历,不好意思,我说无。。。又问我代码量如何,我说之前有经常刷ACM的题目,所以代码量还可以。

2. C语言变量

问:“函数中的局部变量保存在哪里?” 
答:“栈”
问:“函数中的局部静态变量保存在哪里?”
答:“静态区。。”
问:“局部静态变量和全局静态变量有不同吗,不同点在哪里?”
答:“。。没太大不同,都存在一起。。”
问:“不是问的存储位置,其他方面呢?”
答:“哦,可视的范围不同。全局静态变量全局可见,局部静态变量只有函数内部可见。”
问:“全局变量和全局静态变量有何不同”
答:“存的位置是挨着的,要说不同的话,也是可视范围吧,全局静态变量仅在当前文件内可见,全局变量是该项目所有文件可见。”

3. 联合(union) 

问:“知道联合吗?”
答:“union”
问:“和结构体有何不同?”
答:“联合的每个成员的拥有共同的起始地址(共享存储空间),而结构体为每一个成员单独分配空间。”
问:“union这样设计的目的是什么(union有何用途)?”
下面我就赶快头脑风暴了一下。。绞尽脑汁地的表达自己的拙见。该部分内容你可以无视,我觉得自己扯得也有点远。。
        “这样设计节省内存空间,有时候在某个特定的情况下,我们只需要用的某种特定的类型,如何像结构体那样则浪费了存储空间。在以前的时候Linux编程(POSIX)中IP地址的结构体(struct in_addr)就是一个联合(也可能是结构体成员是联合),比如成员是4个元素char数组,两个元素的short数组,或一个int等等,这样我们就能依据不同的网络类型(A类、B类、C类)来自由的获取该地址的网络号或主机号(比如,要获得一个网络的网络号。若是一个A类地址,我们就读取char数组第一个元素。B类地址我们就读取short的第一个元素来)”
当然了现在的struct in_addr 里面实际上只是包含一个整型的结构体了。不是联合了。上面关于in_addr和联合的说法是从《UNP》上看来的。。

4. 算法

4.1 大数相加的算法

问:“如何实现两个数的相加(超过了long long这些的范围了)?”
答:“用一个字符数组来存储数字,然后依次遍历每个字符,通过减‘0’字符的方法转换为数字,再逐位相加。。。”
这是比较经典的大数算法。但他其实没等我说完就打断我了
问:“这样当然可以,但是这种方法效率很低,有没有高效的方法”
答:“不会了”
问:“再想半分钟”
答:“真的不会了(对自己也是无语,求网友告知算法)”

4.2 其他算法

问:“你还了解哪些算法”
答:“大部分是学数据结构涉及到的算法,BFS,DFS,最小生成树,最短路径等等。hash也算一种算法吧,还有排序算法。其他的比如像并查集这种数据结构也算吧。”
关于算法我没敢多提,因为我也怕他深入地问下去,好久没搞算法了,这次没准备,肯定会跪。
不过他也没深入的问下去

5. 书籍

问:“你没有项目经验,那你读过什么经典书籍吗?”
答:“C++ primer,Think in C++也读过一点。(其实读过一点的经典书籍还有很多。。)”

6. const指针

问:“声明一个常量指针,指向一个整型,但指向的地址不可变”
哎,这个我知道是重点,也是容易混淆的知识点,前几天我还特地整理了一下。不过,给我点时间我自己慢慢梳理一下可以答好的,他这一问,我才发现我还是掌握不牢固。
答错了。他又指导了我一下。
正确的答案是:int * const a。
const int * a(int const * a)是指向的整型的值不可变,指针本身可变。


总结一下,速记方法:关键的是const与星号()的位置。int永远在星号左边的。记成“反转”就行了。可以忽略到int。那么就只有两种形式
const * a和
const a。表面上const * a const在星号前面应该是修饰指针的,但是要反转记忆一下,它是修饰变量的。即变量是常量。

  • const a表面上,cosnt在a前面应该是修饰变量的,实际上它是修饰指针的,即地址是常量不能变。
    以上仅仅是速记的方法,并不是C语言设计者的设计意图。。。

7. 内存对齐

问:“比如你malloc了一段内存,它的地址不是内存对齐的,如何实现8字节的内存对齐?”
答:“一个预处理的那个#pragma可以实现(#pragma pack(8))”
问:“这是用编译器来实现,有没有软件方式?”
接下来是在他的提示下,我大概猜测了一下回答的。
答:“先判断malloc的内存地址是不是内存对齐的”
问:“如何判断?”
答:“8字节对齐,那么内存地址应该是8的倍数,可以%8(对8求余)”
问:“这会涉及到除法运算,效率比较低。”
答:“那就用位操作,可以按位与,前面几位是0后面三位是1,哦,我说的是二进制(十进制7)。然后判断值是否为0”
问:“如果结果是没有对齐,该如何对齐呢?”
接下来就完全是我的臆测了
答:“那就给这个地址指针加一下,差多少就加多少,可能还要依据指针类型进行一些转换。”(答的不好。不过他也没提反对意见,就下一题了


后来我自己手动敲了一下代码,需要注意的问题是指针是不能直接进行求余或位操作的,进行指针到int类型的强制类型转换是失败的。可选方案如下:
如果是C++的话,使用reinterpret_cast

long pp = reinterpret_cast<long>(p); // p 是char *类型  

如果pp是int型(reinterpret(p))则会报错提示丢失精度(gcc 64位)。
二面的时候面试官又问了同样的问题,不过问的细节更多,他说可以用static_cast<>来转换指针为整型。我后来试了一下发现不可以。。会报错的。所以我尝试了reinterpret_cast<>
如果是C++的话,就:

int pp = reinterpret_cast<int>(p); // p是char *类型  

C语言虽然没这个功能,但其实要想比较指针地址是否是8的倍数,实现还是比较简单的,指针类型是无法指针做&操作的。但是我们可以进行一个小转换:

//a 是malloc的返回值,char *类型  
if ((a - (char *)0) & 7)  
{  
....  
}  

当然这段代码C++也可以用。
要注意的是malloc的返回值最好要强制类型转换为 char *:

// 比如分配一百的个字符的空间。  
char *p = (char *)malloc(sizeof(char)*(100+8)); // 多分配8个字节的空间,为了以后的偏移留足空间。  

虽然理论上malloc的返回值可以转化为任意指针类型比如:int *。但是要注意到指针的加减操作,所偏移的单位是指向类型的大小。比如:

// 如果p是int *类型  
p += 1// p向后偏移1*4个字节(int是4个字节)  
// 如果p是char *类型  
p += 1// p向后偏移1*1个字节(char是1个字节)  

很明显char *类型的指针偏移的精确度更高。这也是为什么我们通常把malloc返回值转换为char *而不是int *的原因。


8. 回调函数

问:“C++中如何实现回调函数”
回调函数,挺熟的名字,callback。。。但是具体是个什么意思还真不好说。记得在安卓里面见到过。就扯了一下安卓。。
问:“那么在C++中该如何实现呢”
接下来,确实也是运气。脑袋里冒出个函数指针,就脱口而出了,说了个一般的函数指针用法。貌似说对了。
答:“函数指针吧,先什么一种类型的函数的函数指针,然后你可以自己去实现这种类型的函数,然后再把这个函数作为参数传递给函数中(参数是函数指针的函数)。”

9. 内存分配原理

问:“有没有看过内存分配管理的源码?比如malloc之类的。”
答:“没有啊,那大概是汇编吧”(记得大概是Linus说过早期的malloc是用汇编实现的。现在就不知道了。)
问:“也不是涉及具体语言,就是内存管理的算法了解吗?”
答:“没看过这方面的不了解。。”
然后问题就结束了。现在想想他的意思大概是要我从操作系统的知识方面谈一下内存管理的算法,比如扫描一下,哪里未使用的空间就分配出去之类的。

后来问我有什么问题。我基本没啥问题。问了点弱智问题。
问:“是内推的你们会打电话过来(在某群里找了个内推。。)还是所有在官方申请实习的,你们都会打电话过来?”
答:“一般所有申请的都我们会打过去。”


后来第二天打来第二个电话,二面。。不过二面挂了。。


后记 2017-09-24

这算是我人生第一次面试吧。让我认识到了我的不足,在面试结束后得以针对性地补齐只是短板。失败并不可怕,怕的不是失败,而是不能发现自己的问题。

我的2014:迭代的岁月,重构的人生

原写作时间 2015-01-05

1. 不破不立,破而后立

又是一年,过去了,回望去年的“我的2013”征文活动还历历在目。如今又到时间给2014做个总结了。这一年,我深刻体会了,不破不立,破而后立的概念。拿技术来说,2013的时候,上半年我用的语言是C,在钻研数据结构和算法,下半年的时候,用的语言是Java,学习Android的app制作。2014开始的时候,我以为我以后就是个Java程序员了。但是世事无常,未来的发展,总是你我所不能预料的。

三月份的时候钻研了一段时间的Java性能优化,翻阅过许多这方面的书籍,浏览过国内外相关网站,谷歌了几篇论文。值得一提是,一篇论文里面的一个观点,我在测试的时候,发现并不能提高Java程序的运行效率,就用蹩脚的英文给论文作者的邮箱里发了封邮件。也没抱太大希望,结果没几天,竟然收到了回复。大意是说:“这个写的很早的一篇论文了(long long ago),这么长的时间Java的编译器,发生了很多变化,编译器本身可以做很多优化工作了,之前的程序代码上有一些优化方法,并不会带来性能提升了,因为编译器帮你做了。” 嗯,虽然没什么干货,但是我惊叹于国外程序员的敬业,如果是国人,十几年前的论文被翻出来,指责了一番,那么肯定不会鸟你,觉得你无理取闹。

同样是二三月份,时值学期伊始,百废待兴,无聊就用Java给Android做了个打地鼠的小游戏,后来上线了百度手机助手。下载量很低,但是我自信心满满,然后还去图书馆接了几本游戏设计的书来读,四月份的时候,参加CSDN的一个活动得了奖,奖励一本技术图书,我选的就是《Cocos2D-X游戏开发技术精解》。这时我认为我以后会去做游戏了。

游戏热很快退烧,后来开始学习的就是Qt了,最早接触Qt是2014年春节期间,后来呢,在用Java的兴趣退潮以后,我开始拾起C++。Java这种语言,说实话没有C++复杂。但是我发现更喜欢C++,它给人一种强大的自由度,有人喜欢Java那样带垃圾回收,没有指针,类型安全等等便利特性的语言。但是C++,虽然麻烦一点,不过我觉得我能做得更多,指针的妙用,自己对内存全权把关,重载操作符,甚至自定义关键字(实际是宏,如 Qt 中 Q_Object )。为了学好这门语言, 我决定学一门C++的框架。在boost、cocos2d-x、Qt、mfc中我最终选择了Qt。顺带一提,Qt的读音实际是发单词cute的音,而不是国人习惯上的读法:Q、T。cute就是可爱的意思,在学习之后,确实发现了它的可爱之处,不仅跨平台,而且它的架构设计的很美,相反的,我很不喜欢微软MFC的那套架构。Qt不仅充分利用了面向对象的**,还涉及了很多软件工程的概念以及模式。此外我学习更多的就是C++这门语言本身了,我时常发出感叹:咦,C++还能这样啊。

要学好一本语言,单纯地看语法书是不行的,要多编程,多思考。所以最好是学习一下这门语言的一个框架。Java的Android、SSH,C++的Qt、boost,Python的Django等等都是很好的框架。光阴荏苒,由于我开始玩linux,暑假的时候带回去一本Linux C编程的书,当时只是对make和makefile比较好奇,这本书里有这个内容就从图书馆借出来了。

无心插柳。暑假的时候,拿起这本书,开始学习Linux C 编程的其他概念。比如进程管理,fork、exec函数等等,文件管理,文件描述符,各种操作等等。由于上半年开了“操作系统”课,这时候,学起来,感觉在一点一滴地印证曾经学过的概念,心中暗爽,果然各种理论还是要作用于实践的。Linux系统相关的概念令人着迷,之前很多东西都是云里雾里的,现在开始慢慢探究一些本质的东西,当然了,C语言,在用的过程当中,蛋疼的地方也是不少的。少了C++面向对象的那层封装,暴露在眼前的是一大堆函数,思维理解记忆的复杂度都有很大提高,这还不包括C语言本身的trick。不过,我并不讨厌,也不抵触C语言了。

我整个编程语言的学习之路是C —— C++ —— Java。然后又是从Java —— C++ —— C 。自己想来着实好笑,从面向过程到面向对象,我开始讨厌面向过程的繁琐。然后我竟又从面向对象返回面向过程。这时我并不反感面向过程编程了,当然也没不厌倦面向对象,只是深刻理解了一个“物尽其用”的道理,但更像一个返璞归真的道理。如今是“看山还是山,看水还是水

古人说:用人如器。是在讲用人的时候,要依据这个人自身的特点,安排到合适的岗位上去。其实 用编程语言又何尝不如器呢?每个语言都要自己合适的岗位,语言本身并无高低贵贱之分的,不过程序员对于不同的编程语言却有好恶之别。语言之争我很早就摆脱了,但我到底好哪个语言呢?这长久以来的探索,慢慢水落石出。曾经我认为是C++了,但其实应该是C/C++。C语言自有其长盛不衰的道理,这两门语言虽然很像,但应该区分开来,因为他们各自的职能是不同的。尽管C++在语法上是兼容C的,但你并不应该用C的**来写C++,同样的C语言有些地方也是C++所不能取代的。

到了,2014年第二个学期开学的时候,我开始努力学习C了,除了用于Linux编程的POSIX API外,我还在学习C语法本身。呵呵,时常会这样想,如果当初我没有去经历Java,没有花功夫去学做Android的app,而是一门心思放在C上,或许现在一定略有小成了。不过呢,时间不能倒流,有些事只有经历过,才能懂。没有经历过,你总想去尝试,不尝试的话,就不知道自己喜不喜欢。所谓横看成岭侧成峰,远近高低各不同。每一种编程语言也是如此,要识得庐山真面,一定要亲自去攀登,去仰望,去俯瞰。

千淘万漉虽辛苦,吹尽狂沙始到金”。年轻就是资本,年轻人什么没房,没车,没钱,没事业,但是有的是时间。年轻就要去尝试,勇于碰壁。曾经学过的Java,Android,包括Qt,现在都碰得不多了,想到当初也是花了大把时间的,但是人生就是如此,用于舍弃,有舍才有得,固步自封必将走投无路。不破不立,破而后立。要想获得大智慧,就要经得起大折腾。代码是需要重构的,人的**、认知、生活也是要不停重构的。

2. 开源照进生活

从去年11月份注册了github,但是真正开始使用github是2014年二三月份的样子,开始我也是一头雾水,在Windows上使用github的客户端,来管理代码,尽管是客户端,但是在配置的时候也遇到了很多麻烦。原因在于我对git的很多原理和概念不够清楚。后来慢慢熟练了,当我开始频繁使用Ubuntu系统的时候,我终于了解了ssh协议,了解了git的各种命令。开始在终端使用git命令来管理代码。感觉和客户端比起来,一个字——酷。然后Linux使用的越来越多,陆续学到了很多命令,日常管理也没问题了。

在github上,有一种很通用的文档编辑语言——markdown。开始我看到别人那些README.md的文件,我也是一头雾水,不知道怎么实现的那些效果,后来花了两天的时间,来恶补这门语言,在github上对于markdown语法各种测试。github上的markdown与一般的markdown是有区别的,github对其做了一些功能提升,比如复选框列表、代码高亮、表格等等,称之为github flavor markdown(简称GFM)。然后我在csdn上发表了介绍markdown的 博文,并且github上建了一个仓库,去演示效果。无心插柳,结果现在star还挺多:README

六月底,学期末的时候,我在github上建立了一个组织,是我们学校的开源小组。我想聚集更多的人来一起交流Linux,交流开源理念,交流各种技术。暑假的时候我开始在贴吧发帖,在其他群里宣传,慢慢地聚集了一些人,当然我们并不是社团,我觉得开源小组就是一个互相学习,互相交流的地方,不想像其他社团那样太官僚化。尽管我们没有线下活动,一些交流都是在线上,但我觉得这样就够了。开始我选择IRC为大家交流工具,后来发现很多人都不习惯,所以还是建立了QQ群,来聚集大家。现在这个开源小组没什么动静,开学以后交流的少了很多,当然这是题外话了。

同样是在暑假,我开始学习使用Vim,很早就听说过它,编辑器之神,但是一直没有兴趣,因为用惯了VC那种一站式编程,编译的工具。现在由于敲命令敲的多了,就不想把手抬起来,去摸鼠标了。然后学习了Vim之后,几乎所有事情都在一个终端里完成了。感觉 perfect。github上有一个repo(仓库)是Vim的配置文件,直接wget下来他的安装脚本,再执行,就能用,非常easy,我也给他提交过几次PR(pull request),修复了一些.vimrc文件里的bug,增加了一些功能。此外呢,我还给CSDN的CODE翻译过开源有关的文章,后来发现Linux**在github上的仓库,专门用于翻译各类文章的,先认领文章,然后翻译完成提交PR,合并后,过一段时间会发布到Linux.cn官网上,我的英语很蹩脚(囧),不过当时我也是乐此不疲的看自己翻译的文章被发布,被其他网站转载,不过下半年开学后,时间少了,参与度不高。

十月份的时候,开始玩云主机,开始是买了一个月的阿里云主机练练手,后来因为github的学生开发包申请到了DigitalOcean的国外云主机(花了5美元,可以用十个月)。在终端上用ssh(Windows上用Xshell)连接到云主机,就能管理,完全是字符界面,通过敲命令来管理。这感觉真是——酷酷酷。在上面我搭建了很多环境比如LAMP,还有Nginx,vsftpd等等。大部分都是通过源码编译的方式,安装的。虽然源码编译的方式,耗时较长,但是我喜欢这种感觉,尤其是编译过程中遇到各种各样的问题,然后我把问题一个个解决掉的时候,perfect的feel。

3. 热情过后的百味人生

在2013年,我对编程的兴趣可谓空前绝后。平时也没什么娱乐。代码对我而言就是娱乐,到了2014年,当初的热情已然不再了。并不是所我不喜欢代码,而是这一切开始变得像吃饭喝水一样平淡,平常。白开水虽然没有什么味道,但却又必不可少。不管是什么事,都会有这么一个过程吧,所有的热情都会归于沉寂。从这个层面来讲,生活的格局也在重构着。开始花比之前多的时候在其他方面上,比如看视频,看动漫,看杂书。高中的时候,我素来是偏爱文学和历史知识的,高中时差点冲动地不学理科,去学文科。大学之后,对这些接触的不多了。

历史方面,开始涉猎日本历史,大部分都是通过看日剧了解的。日本战国的武田信玄、上杉谦信、织田信长、丰臣秀吉,德川家康...这些军事人物都是之前不曾了解的,上半年,我看了《风林火山》这部剧,里面的各种军事计谋、合纵连横使人叹为观止,《天地人》从历史的脉络上来说可以看作是《风林火山》的延续,所讲的就是在《风林火山》结局“川中岛”之战之后的事,不过叙述的主角不再是甲斐国的武田家,而是武田宿敌越后国的上衫家的一段兴衰。其他方面,我还了解到了新选组的冲田总司、土方岁三、近藤勇、斋藤一。这里面我最喜欢是冲田总司了,他年纪在新选组里面是比较年轻的了,但是论剑术,确实组内第一高手,一个翩翩美少年,据说十几岁就获得了天然理心流(所学的剑术流派)的免许皆传(日本剑术流派最高称谓,表示熟练掌握了该流派所有剑术)。

可惜死于肺痨。在日本,很多民众都是“新选组迷”。在明治维新的时候,新选组是保皇派,是守旧的一派,最终他们的人生当然是被历史的车轮碾压。他们被称为日本历史上的最后一批武士。从历史的角度讲,他们是落后的,是失败的。但是从人性的角度讲,他们是绝对的胜利者。在那个年代,不管是武士、农民甚至是上流社会的贵族,都不一定能够理解所谓的文明开化的新时代到底是什么意思。大家都是普通人,没有大智慧,不能认识到历史发展的必然性,也是很正常的。这批武士只是在坚守自己那个年代的君君臣臣,坚守那个年代的身为武士的尊严,明知不敌,还要拼死一战。在《新选组血风录》最后一集,当土方岁三在箱馆单枪匹马冲入敌阵,被一排长枪打到在地的时候,确实令我唏嘘不已。

十一月份的时候,由于在CSDN一位博主的博客里,了解到了电视剧《苏轼》,后来我就找到PPTV上的资源来看,画质很差,但是我还是坚持看完了。了解了苏轼的百味人生,在苏轼的一生中,他所涉猎的领域十分广泛,并且在其他方面也开创了多个历史先河,值得一提的是,**历史上的文字狱就是苏轼被卷入的“乌台诗案”开的先河。看这部剧呢,我也纠正了之前的一些错误认知,以前我知道苏轼是深陷以王安石与司马光为代表的新旧两党的争斗之中,并且被新党打压,卷入了乌台诗案。但是,当初打击他的并不是王安石,那时候,由于王安石用人不当,所以新党已经不能由其掌控了,王安石被罢相后,吕惠卿上台,是他搞出了乌台诗案。可笑的是,在旧党重新执政后,苏轼写的一篇贬吕惠卿的诏书(当时拟诏书,是苏轼职责所在)竟然变成了千古名篇,不仅在当时引得天下文人传抄,就连现在也薄有名气,使得吕惠卿当真落得个遗臭万年的下场。不过好景不长,苏轼对旧党也是正见颇多,所以又不容于旧党,因而一贬再贬,最后不仅过了大庾岭,甚至被贬到海南。当时的海南还是尚未开化的蛮夷之地(汉人蛮人杂处)。

在看完《苏轼》后,我接着看了一部历史正剧《贞观之治》。很奇怪这些历史正剧网上的资源都不多,画质也很差。据说是广电对这类题材的电视剧,审查很严格,貌似《苏轼》曾被禁播三年。之所以看《贞观之治》而不是更有名的《贞观长歌》,是因为“长歌”更像一部风月剧,并且虚构地成分很大,对历史的考究也不精细,从网友的评价来看“之治”的口碑更好,布景,服饰都尽量还原唐朝风貌,“长歌”为了吸引现代人眼球而不够真实。当代许多古装剧,你不看剧情根本无从区分朝代,演得唐宋也穿明清的衣服。而《贞观之治》则不同,比如这部戏里面没有床,只有席子,没有椅子,当时他们坐的那个器具叫什么,我也不得而知了,很多时候,人们是席地而坐,或跪坐地上。因此如今日本民众的生活习惯,日常起居,我们就不会奇怪了,因为**的唐朝大致也是这样的。还有一个多年以来的误解,也被这部电视剧给纠正了,那就是李世民的四弟是李元吉,而不是李元霸。很多隋唐的小说里描述李元吉是李家老三,这是不对的,而且历史上根本没有李元霸这种逆天的人存在,李世民的三弟是李玄霸(可以认为是李元霸的原型),因为描写隋唐的小说(比如《隋唐演义》、《说唐》)都是成书于清代,所以要避康熙皇帝的讳(康熙名玄烨),因而改为了李元霸,但是历史上李玄霸也没有小说中这么吊炸天的,玄霸和元霸唯一的相同点是他们都死的早。唉,再看看近几年的电视剧《隋唐演义》以及剧本拖沓、不断续拍的《隋唐英雄》真是渣的可以,误导了多少观众。我认为这些历史翻拍的时候要注明真实的历史是什么样的,剧中哪些地方虚构了。可笑的是,《贞观之治》这类描写真实历史的电视剧被管制的很严格,播放量很低。像《隋唐英雄》这样完全娱乐大众的电视剧却大肆地充斥荧幕。

动漫方面,2014年最大的收获就是以伊藤开司为主角的“赌博系列”,包括《赌博默示录》、《赌博破戒录》、《赌博堕天录》以及《赌博堕天录 和也篇》。前两部动漫化了,并且电影化了,藤原龙也主演的(吐槽:藤原龙也演了好多动漫的真人版啊,其他的还有《死亡笔记》夜神月、《浪客剑心》志志雄真实)。虽然“赌博”系列的画风一般,或者说画风比较“有个性”,但若论剧情的话,不得不承认当真是神作。每一场赌博都跌宕起伏,扣人心弦。赌博过程比较烧脑,各种心理战和阴谋诡计。除此之外,也见识到了人性。普通人卖友求荣,有钱人的麻木凶残。比如铁骨桥上的人推人,还有皇帝牌(E Card)那局,用眼睛和耳朵做赌注,后来的面纸盒抽签一局,开司输了,就被砍掉了手指。漫画第三部中,开司在赌局当中,因为钱不够,就向兵藤和也借钱。和也猥琐一笑,拿出了一份人体器官价目表。以开司所借钱款的数额来看,所有的器官基本上都用上了,所幸的是开司赢了那一局。在“和也篇”开篇,开司要和和也赌一局,和也带开司来到一个地方。那里的场面令开司毛骨悚然,因为和也已经为开司准备好了坟墓和墓碑。

年底了,把网络剧《毛骗》和室友又温习了一遍,不仅搞笑,而且见识到了各种骗人手法,惊叹与骗子门的头脑,对他们而言,骗人不仅是技术更是艺术,尤其是每集结尾渲染得和柯南一样,解开谜团。不过不得不吐槽的是,第二季第15集快一年了还不更新。

4. 念念不忘,必有回响

新的一年开始了,以前常说光阴似箭,现在我说岁月迭代。2014年和2013年相比,生活发生了很大变化,技术在变,知识在变,认知也在变。社会在变,世界在变,人在变。外在的在变,内在的也在变,我们要做的不是以不变应万变,而是以万万变应万变。重构现在,筑梦未来。2015年,大三还有一个学期,下半年将大四了。暑假要找实习,这直接决定着毕业以后能不能找一个好的工作。大学呢,虽然遗憾很多,但是没有任何后悔,我在努力,我在学习。过去的这一年,我笔耕不辍,博文一直在写。12月的时候,申请到了一个博客准专家,我自己都觉得诧异,因为我明白我差得还很远,不过这也算是对我一直以来坚持写博文的一点告慰吧。我还要继续努力,继续加油。
我相信:

有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

更相信:

念念不忘,必有回响

五月末,写在大一即将结束的时候

原写作时间 2013-05-25

光阴似箭啊。一晃这半年就过去了,这个五月我也不知道是怎么过来的了。感觉五一节才过去没多久的样子。考前一个月了。渣渣的学习成绩我觉得有必要好好补一补了。这一个学期,都在忙着学习编程。数据结构和算法。确实掌握了不少知识了。期间还摸索过 java 和 python。两种都挺不错的。尤其是 python。但是没有过多的精力去学习。暑假时候学习吧。不过最近开始从 c 转型 c++了,原来我就想,要迈出这一步会很难。曾经我也不知道我是在执着些什么。总在暗地里对于 c 和 c++ 的优劣较较劲。。或许是先入为主的影响吧,而且两门语言很相似。所以我一度拒绝接受 c++。但是最终我还是迈出了这一步,编程语言无罪。不要去争议两门语言的孰优孰劣。都学学好了,看情况使用吧。两者在不同的领域有着各自的优势。

报了北大的暑期选修课,ACM竞赛指导课程。北大郭炜老师授课。貌似挺有名气的一个人。去北大或许会花不少钱吧。其实也就在那里待个十几天。食宿自理。并且由于是 c++ 语言授课。所以接下来的一个月我要熟悉c++操作,以及它的数据结构。

还有个事,就是交完钱,选完课有个上传照片的流程。换了很多浏览器,换了很多照片都不行。提示我分辨率不符合要求。上传失败……我保证是符合他237X178的分辨率的。后来网上说北大的网络系统用的还是ie6的内核。所以其他的浏览器不会成功……无奈。我只有找个ie6了。自己的电脑因为有ie9的缘故,所以安装ie6是失败的。失败了很多次,急死了。周末也就是今天去了图书馆。快速的找到被几乎所有人冷落的windows2000的老爷机。如获至宝啊。一打开电脑查看ie版本果然是ie6。哈哈。后来网速虽然很慢,但是一击就中。直接成功了。哈哈。

原来总是抱怨图书馆怎么不把电脑都换成win7旗舰,留着windows2000做鸟啊。现在感觉图书馆这个伏笔留的真是妙啊。。

知我者,知乎也

我知乎小记录

zhihu-shield

日期 里程碑
2020.03.16 专栏《后台公论》2000关注
2020.03.23 3000关注
2020.04.02 创作等级LV7
2020.04.12 10000收藏
2020.04.13 4000关注
2020.04.28 5000关注
2020.05.05 10000点赞
2020.05.06 6000关注
2020.05.17 7000关注
2020.06.28 10000关注
2021.10.24 创作等级LV8
2022.11.13 创作等级LV9

🙏 欢迎关注:

https://www.zhihu.com/people/guodongxiaren


指尖上的暑假

时间是2013年8月14,这是我大一的暑假。距离我开学还有两个星期。感觉有必要记录一下。总结起来就是code,code。

第一部分

这个暑假是我过得最忙碌的暑假吧。不过也很充实,虽然暑假也学了些的东西了,但仍总觉得自己水的很。。

七月份,在北京呆了两个星期,因为报了个北大ACM的暑期学习班。住我亲戚家里😳。每天早晚一个小时倒三班地铁:5号线(蒲黄榆)——10号线(惠新西街南口)——4号线(北大东门)。老实说,当时学到的东西不多,我没带电脑去,老师讲的我总是跟不上思考。后来就慢慢放弃听了。期间两次比赛,个人赛,组队赛。个人赛不幸的是本人竟然0题。或许是太久没有A题了吧,郭老师当时明明说了新加了一道水题,为了让大家不要A出0道题,可我偏偏就没A出来。查了半天没找出错误来。第二周的组队赛现场组的队,是和中山大学的两个人。那两人比我要强好多的。起码STL要比我熟悉些。😂。最后A出一道题,还有一道也是测试很多用例没问题。但就是WA(好像是超时,记不清啦)。第一周周末,在北京玩了两天。***,故宫,景山,北海,人民大会堂,然后第二天是颐和园,清华,圆明园。脚上起了一个泡,坏掉一个拖鞋(不过还能穿)。哎,学生票确实便宜。👏。

回家后呢。开始在android和算法之间左右开弓。确实同时做好两件事情比较困难。

关于acm,庆幸的是下载了很多北大的课件,而且我当时虽然很多没听懂,但也做了笔记。所以慢慢的就学到了更多的算法。比如并查集啊,kruskal,prim,dijkstra,简单hash,线段树,还有个入门的dp题(最大子序列和)。不过我还有很多计划要学的啊……

android呢。也学了些吧。算是入门了。但是这种工程型的东西我是第一次接触的。还有很长的路要走。

对了,昨天七夕,前天睡觉睡得晚,到了凌晨,也就是七夕的凌晨。当时我竟然不知道有流星雨。错过了。不过凌晨的时候。我报名了软考。接下来三个月有目标了。呵呵

第二部分

值得一提的是,这次北京之行的一个意外的收获,就是我想考研了。:trollface:。这是我原来十分抵触的想法啊。。或许这个改变是因为北大的缘故吧。不是贪恋名校,更多的是我对IT行业的认识更深了,本科阶段我再努力的学习,自学,实践,做再多的项目,考再多的证书,其实有些东西对于未来来说我还是会欠缺的。前面我所说的那些在本科阶段我要做的事情或许会在我毕业时帮我找个还算满意的工作。但是我以后整个职业的发展都会欠点火候。。并且在IT行业,有些时候,有些东西并不是经验所能取代的。比如我本科毕业,工作了三年。有了三年XX的工作和开发经验。而一个当时刚毕业的研究生没有这种经验,听起来我或许优势更加明显。但是研究生或许开始的时候不强,不起眼。但是人家以后整个职业的发展道路和我是有很大不同的,他可以进入公司的核心部门,而我不能。只能做普通的应用层开发。而且,应用开发的技术更迭太快,以后我或许真的会被年轻人淘汰,也说不定。。

原来我说不考研,主要是对职业发展认识不清,误以为经验能代替一切,误以为工作经验的本科生总是会比没经验的研究生要强,其实有时候不是这样的。

原来我说不考研,是我总误以为研究生真的都是烟酒生。还有就是我从来没有拿北大清华的研究生毕业生和有工作经验的本科生做比,一直以来潜意识里只是拿自己学校的研究生在和有经验的本科生作比较。

其实对于大多数人来说,即使明白了这些道理,也不一定要考研的。。这就设计到一个人的职业期望与薪资期望的问题了。。我原先也总是拿自己和社会上的培训机构相比。刚开始工作的时候有五千到八千之间的收入,就很满足了。确实是的,本科毕业能有这样的工资确实很满足了。但是人是不断成长的,培训机构出来的学生以后做个五年十年或许工资还是这个水平,涨幅不大。但是对于一个本科毕业生来时五年十年以后还只是这个水平,我是不满足的。这里只是说我的个人想法。我总想能挣到更多的钱,这时候,研究生学历的必要性就凸显了。有时候人的目光确实要看长远。

还有就是,IT行业技术更新太快,应用层技术层出不穷。平台依赖性强,商用框架周期短。如果平台倒了(比如symbian),那么还要着手去学习新的平台技术。不要说什么以前的时候打好了功底,即使平台倒了,换个平台照样能东山再起。或许有些道理,但是我想说人真的是会变老的,学习新技术永远是比不上年轻人的精力。频繁的学习各种流行技术,真的是很累的。那时候我也疲于学习了。而如果不是学习这些应用层表层的技术,而是研究的深层的,或者较为底层的技术,这才是核心的技术。比如百度会招很多的IOS,android的开发人员。但是百度的核心依旧是搜索。而在早几年android还没流行的时候,招的或许就是塞班的开发人员。不变的依旧是搜索。十年之后,谁有能保证IOS或者android平台能依旧长盛不衰呢。就像十年之前没人会知道今日android之火爆一样。


后记 2017-09-14

缅怀这个热情似火的暑假,敢想敢做,说走就走。记得当时在北京借助在亲戚家里,亲戚问我以后想去哪工作。我不好意思地说“想去中关村……”,然后咧嘴一笑。现在不知道算是完成了梦想,还是不算呢。
后来我真的是有想过读研的,但是因为大一的时候挂科,所以我保研没有希望,考研太苦,还要影响自己学技术的时间,只能无奈找工作了。
当时口口声声说想读研了,不想做应用开发的程序员,谁知最后还是走上开发的道路,每天也是写着业务逻辑。

国际信用卡那点事儿

基本概念

和国内信用卡一致,信用卡安全用卡要保护好几大要素:卡号手写签名CVV2过期时间。有卡交易的时候签名是重要凭证。而对于无卡交易(比如网络支付的时候),CVV2和过期时间则是重要的要素了。过期时间好理解,简单提下CVV2

CVV,CVV2,CVC,CSC,CSN,CVN

信用卡有个很重要的概念是CVV2,就是我们经常在卡背面看到的三位数字:

image

常有人简称为CVV,后来便以讹传讹了。所谓的CVV其实写在卡片磁条(磁道)中的,是不可见的二进制信息。用于线下有卡交易,POS机会去读取。其实不管是CVV,还是CVV2其功能都与我国身份证号最后一位一样——校验码。可以校验出卡的真实性,有效性。

另外CSC,CSN,CVC等等都是CVV2的同义词了。所谓C就是Card或Code缩写,S就是Secure,N是Number,V是Verification。组合的方式有很多了。

值得一提的是,与大部分卡组织将CVV2印刷在卡背面的后三位数字的做法不同,美国运通卡(American Express)是印刷在卡正面,并且是4位数字。

卡组织

在谈论海外信用卡的时候,卡组织是一个绕不开的概念。卡组织即我们听说过的有VISA、MasterCard(万事达)。

image

除了上述两大寡头以外呢。还有Diners Club、JCB、American Express以及**银联四大信用卡卡组织。**银联,**最(唯)大(一)的卡组织,正是由于我们用的卡都是银联卡,导致我们大众可能常常忽略银联这一组织,而只关注发卡行了。所谓卡组织就是完成多家银行之间的清算业务与实际的资金划拨。谈到清算又是一个很长的概念了,这里不再展开了。

拒付

英文chargeback。一直感觉中文翻译不够贴切。拒付一词听起来让人感觉是交易发生时,持卡人拒绝付款的意思。实际不是。拒付指的是:信用卡交易发生后,持卡人向发卡行对这笔交易提出异议,申请退款的行为。信用卡被盗刷时,或者购物时遇到商品损坏、货不对版等情况下多会发生拒付。

当然拒付这种事只会发生在海外,天朝并无拒付一说:

银行卡管理办法 第七章 第五十四条 第四款规定
持卡人不得以和商户发生纠纷为由拒绝支付所欠银行款项。

因此拒付是“万恶”的资本主义国家用来保护持卡人权益的,在欧美国家有一套相当成熟的拒付处理机制。当然申请拒付是有时效的,VISA和MasterCard的时间窗口都为120天。整个拒付处理过程可能是耗费相当长时间的,其中涉及角色众多,包括:持卡人、商户、发卡行、收单行以及卡组织。一图胜千言,下面以Visa为例,盗图一张来描述整个处理过程:

image

EDC

在谈论海外支付的时候,可能会经常遇到这个词,不止针对信用卡,也适用于借记卡。全称为:Electronic Data Capture 或 Electronic Draft Capture。咳咳。其实就是POS(Point of Sale)的另一个叫法。。所谓的EDC Machine就是POS机。。

image

DCC

即Dynamic currency conversion(动态汇率转换)。DCC通常发生在持卡人跨境消费的时候。因为跨境交易存在一个汇率问题。

和借记卡不同,信用卡消费有一大特点是:先交易,后付费。如果是借记卡,那么也没太大异议。但是信用卡,则有一大问题。那就是交易日与账单日之间的时间

窗口,汇率是波动的!比如你在境外购买了美元标价的产品,用依据当天的汇率折算为等价人民币进行了付款,而在信用卡账单日的时候,汇率变啦。由此诞生了一个叫DCC的东东:

DCC交易就是将当地货币实时转换为持卡人的记账货币,以此来降低持卡人在交易日至还款日之间的汇兑风险。但是DCC的汇率通常不太合算,DCC的本质,就是把原本商户承担的一部分费用,直接转嫁到消费者头上,所以一般商户都是乐于DCC交易的。

据说DCC是澳大利亚的一家机构开发出来的。对于它的这种行为,就好比:“老乡,快开门,我们不拿群众一针一线。。咦,你家有个女儿”

使用多币种的信用卡可避免被DCC,如果你的卡片币种包含当地币种,那么即支付的时候选择使用当地货币支付即可。但是奸商们通常是乐忠于DCC的,因此常常在持卡人不知情的情况(可避免DCC)下,被强行DCC。

其实国际上支持DCC的信用卡只有Visa和MasterCard,其他卡组织(包括**银联)发行的信用卡都是不支持DCC的,但这不代表这些卡在跨境交易的时候,不存在一个币种转换的问题,凡是货币转换,必有手续费(货币兑换费)。比如你的卡片支持美元,但是你去泰国购买了标价泰铢的商品,那么就会转换为美元(另加了汇兑手续费)来支付。但其手续费与DCC相比都是洒洒水啦。

3D安全验证

image

1997年,Visa与MasterCard主导,联合微软、IBM推出了“安全电子交易”协议(SET协议),它以信用卡交易为基础,规范电子商务中的网络支付交易,并保证其安全性。不过SET实在过于复杂,实现复杂,不易推广。后来VISA率先推出了,更为简化的信用卡网上交易安全认证方案——3D安全认证(3 Domain Secure Authentication),作为SET协议的替代解决方案。

后来其他卡组纷纷效仿,纷纷推出了自己的3D安全认证模式,只不过每个卡组织对于3D认证的叫法各不相同:

  • Visa:Verified by VISA
  • MasterCard:MasterCard SecureCode™
  • JCB:J/Secure
  • American Express**:American Express SafeKey**

那么到底何为“3D安全认证”呢,插播一条维基百科(3-D Secure):

The basic concept of the protocol is to tie the financial authorization process with an online authentication. This authentication is based on a three-domain model (hence the 3-D in the name). The three domains are:

  • Acquirer Domain (the merchant and the bank to which money is being paid).
  • Issuer Domain (the bank which issued the card being used).
  • Interoperability Domain (the infrastructure provided by the card scheme, credit, debit, prepaid or other type of finance card, to support the 3-D Secure protocol). Interoperability Domain includes the Internet, MPI, ACS (Access Control Server) and other software providers

其实所谓3D安全认证,拆解开来可以这样理解:出于安全目的需要认证,利用的手段是3D。3D简单理解就是3方的意思,哪三方?上文那段英语已经阐释的比较清楚了:

  1. Acquirer Domain:收单行
  2. Issuer Domain: 发卡行
  3. Interoperability Domain:卡组织(一大段解释,说白了就是卡组织)

虽然把3D是哪3个D解释清楚了,但是具体流程是怎样的呢?其实非常简单,其过程我多年前我们网络的时候选择的网上银行支付,非常相似。

在Web时代,网购已经普及,但是对于第三方支付工具还持审慎态度(比如我)的时候,人们在付款的时候往往喜欢选择网上银行支付,此时我们的流量器会跳转到银行的官网页面,待我们登录,输入完密码(通常是U盾上的口令密码)成功登录后,再自动跳转回网购页面。当然,后来移动支付的普及,以及互联网金融理财的渗透,让普罗大众已经开始广泛接纳第三方支付工具,而当初的网上银行支付逐步退出历史舞台(U盾丢了好几年了)。

3D安全认证过程与之类似,之间经历3方主体。用户发起支付指令之后,商户的收单行会承接该指令,然后传递给卡组织,卡组织再传递给发卡行。此时浏览器就会弹出发卡行的网站。不需要U盾之类的实体安全口令。用户通过卡号,CVV2,过期时间以及设置的3D安全验证密码的校验来完成验证,也可能在这个页面通过手机短信来完成认证。

3D安全认证的出现,极大的保护了持卡人的支付安全,提升其网购信心,降低了拒付(主要是恶意拒付)的概率。另外也打击了不少恶意商家。但同时也阻碍了大量支付的交易的成功进行,削减了支付成功率。据悉,3D安全认证只在亚洲地区比较流行,而欧美则多为非3D的网上交易,这是因为欧美地区,信用卡制度、征信机制十分完善,资金保障机制十分完备。

ECI

ECI(Electronic Commerce Indicator)是个比较生僻的信用卡行业术语。中文翻译貌似是:卡评级。ECI数值表示在验证过程中可能出现的几种场景,不同场景存在不同的拒付责任转移。

ECI=0:MasterCard使用。ACS服务不可用或者卡片不支持3D验证。

ECI=1:MasterCard使用。持卡人或发卡行未注册3D安全验证服务。

ECI=2:MasterCard使用。持卡人3D安全验证通过。

ECI=5:Visa使用。持卡人3D安全验证通过。

ECI=6:Visa使用。持卡人或发卡行未注册3D安全验证服务。

ECI=7:Visa使用。ACS服务不可用或者卡片不支持3D验证。

ACS(Access Control Server)访问控制服务器,发卡行用来安全验证的服务器

参考资料

Visa Chargebacks

Chargeback Rules for MasterCard

Visa商户拒付管理指南

edc services你知道DCC是什么吗?

3-D Secure

conda入门

创建环境

conda create --name python35 python=3.5

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

0. 仰之弥高

2015年,在腾讯暑期实习期间,leader给我布置的一个任务是整理分析网络模型。虽然也有正常工作要做,但这个任务贯穿了整个实习期。后来实习结束的总结PPT上,这部分内容占到了一半篇幅,我从C10K问题引入,讲了很多:从fork-exec的多进程到进程池;从多线程再到IO多路复用;从accept的惊群到pthread_cond_wait的惊群。

现在回想,这些总结还是偏初级,后来又看了很多资料,但感觉还是有很多东西抓不住,尽管如此却在我心里埋下一颗种子。以至于后来工作和学习中看到Server,我都会自我诘难:它是什么『网络模型』?

1. 本立道生:基础知识导入

所谓『网络并发模型』,亦可称之为『网络并发的设计模式』。『半同步/半异步』模式是出镜率很高的一种模式,要想解释清楚它,我要先从基础讲起。熟悉的同学可以跳过本节

1.1 单线程IO多路复用

首先带大家再回顾一个典型的单线程Polling API的使用过程。Polling API泛指select/poll/epoll/kqueue这种IO多路复用API。

一图胜千言:

image

关于套接字,相信大家都不陌生,我们知道套接字有两种:服务端套接字(被动套接字)和客户端套接字。套接字在listen调用之后,会变成被动套接字,等待客户端的连接(connect)。其实socket的本质是一种特殊的fd(文件描述符)。

为了表达简洁清晰,用socket指代服务端套接字,fd表示连接之后的客户端套接字。

单线程Polling API的常规用法是:

让Polling API监控服务端socket的状态,然后开始死循循环,循环过程中主要有三种逻辑分支:

  1. 服务端socket的状态变为可读,即表示有客户端发起连接,此时就调用accept建立连接,得到一个客户端fd。将其加入到Polling API的监控集合,并标记其为可读。
  2. 客户端fd的状态变为可读,则调用read/recv从fd读取数据,然后执行业务逻辑,处理完,再将其加入到Polling API的监控集合,并标记其为可写。
  3. 客户端fd的状态变为可写,则调用write/send将数据发送给客户端。

1.2 平民级的多线程IO

最平民的多线程(or多进程)网络IO的模式,比较简单,这里就不画图了。就是主线程创建多个线程(pthread或者std::thread),然后每个线程内部开启死循环,循环体内进行accept。当无客户端连接的时候accept是阻塞的,当有连接到时候,则会被激活,accept开始返回。这种模式在上古时代,存在accept的『惊群』问题(Thundering herd Problem),即当有某个客户端连接的时候,多个阻塞的线程会被唤醒。当然这个问题在Linux内核2.6版本就已经解决。

2. 言归正传:半同步/半异步

『半同步/半异步』模式(Half-Sync/Half-Async,以下简称HSHA),所谓『半同步/半异步』主要分三层:

异步IO层+队列层+同步处理层

当然也使用了多线程,一般是一个IO线程和多个工作线程。IO线程也可以是主线程,负责异步地从客户端fd获取客户端的请求数据,而工作线程则是并发的对该数据进行处理。工作线程不关心客户端fd,不关心通信。而IO线程不关心处理过程。

那么从IO线程到工作线程如何交换数据呢?那就是:队列。果然又应了那句老话『在软件工程中,没有一个问题是引入中间层解决不了』。

通过队列来作为数据交换的桥梁。因此可以看出,在HSHA模式中,有我们熟悉的『生产者、消费者』模型。当然由于涉及到多线程的同时操作队列,所以加锁是必不可以少的。

image

潦草地画了一个图,不是UML,比较随意……

2.1 异步IO与同步处理

所谓异步:在接收客户端连接,获取请求数据,以及向队列中写入数据的时候是异步的。在写入完成可能会执行预设的回调函数,进行预处理和其他通知操作。也便是Proactor模式(与之相对的是Reactor,下文有述)。

关于异步IO,严重依赖内核的支持,比如Windows的IOCP就是公认的不错的异步IO实现,而Linux的AIO系列API虽然模拟了异步操作的接口,但是内部还是用多线程来模拟,实则为伪异步,十分鸡肋。另外请注意epoll不是异步IO!,epoll虽然可以一次返回多个fd的就绪状态,但若要获取数据,单线程的话还是同步一个fd一个fd的read的。

所谓同步:一个客户端连接的一次请求,其具体处理过程(业务逻辑)是同步的。虽然在消费队列的时候是多线程,但并不会多个线程并行处理一次请求。

综上,也就是说当一个客户端发送请求的时候,整个服务端的逻辑一分为二。第一部分,接收请求数据是异步的;第二部分,在收完数据之后的处理逻辑是同步的。所谓半同步,半异步因此得名。

2.2 返回数据是怎么发送的?

读完上一节,你明白了HSHA的名称由来,但是你发现没,漏讲了一部分。那就是『数据是如何发送回去的』。甚至我那个潦草的图里面都没有画。不止你有此一问,我其实也疑惑。关于HSHA,很多资料都有介绍如何用异步IO接收客户端请求数据,但却没有谈到应该如何发送响应数据给客户端。即便是HSHA的名称出处《POSA》这本书也没深究这部分。当然我们学习要活学活用,懂得灵活变通,而不能生搬硬套。关于如何发送,其实本身不是难点,我们也不需要拘泥于一定之规。

它的实现方式可以有很多,比如在工作线程中,处理完成之后,直接在工作线程向客户端发送数据。或者再弄一个写入队列,将返回数据和客户端信息(比如fd)放入该队列(在工作线程中侵入了IO逻辑,违背解耦初衷)。然后有一组专门负责发送的线程来取元素和发送(这种方式会增加额外的锁)。总之也不需要过分追求,什么标准、什么定义。

2.3 队列思考

队列中元素为封装了请求数据和其他元数据的结构体,可以称之为任务对象。HSHA模式不一定是多线程实现的,也可以是多进程。那么此时队列可能是一个共享内存,通过信号量同步来完成队列的操作。如果是多线程实现的。那么队列可以是一个普通的数组,多线程API若使用pthread,则同步即可使用pthread_mutext_t。当然也可以使用C++11的std::thread。

关于工作线程消费队列数据的方式,和一般的『队列』模型相同,即可分为『推』和『拉』两种模型。通常HSHA为推模型,即若队列尚无数据,则工作线程阻塞休眠,等待数据产生。而当IO线程写入了数据之后,则会唤醒休眠的工作线程来处理。很明显在pthread的语义下,这必然是一个条件变量(pthread_cond_t)。需要注意的是条件变量的惊群问题,即可能同时唤醒多个工作线程。前文虽然提到accept的惊群问题早被内核解决,但是条件变量的惊群问题仍在。这里需要注意的是虽然 pthread_cond_wait 本身便能阻塞线程,但一般还是要用while而非if来做阻塞判断,一方面便是为了避免惊群,另一个方面是某些情况下,阻塞住的线程可能被虚假唤醒(即没有pthread_cond_signal就解除了阻塞)。

伪码来描述一下:

while (1) {
    if (pthread_mutex_lock(&mtx) != 0) { // 加锁
        ... // 异常逻辑
    }
    while (!queue.empty()) {
        if (pthread_cond_wait(&cond, &mtx) != 0) {
            ... // 异常逻辑
        }
    }
    auto data = queue.pop();
    if (pthread_mutex_unlock(&mtx) != 0) { // 解锁
        ... // 异常逻辑
    }
    process(data); // 处理流程,业务逻辑
}

保险起见,上面的empty和pop函数内部一般也最好加锁保护。

再谈一下拉模型。即不需要条件变量,工作线程内做死循环,去不停的轮训队列数据。两种模型各有利弊,主要要看实际业务场景和业务规模,抛开业务谈架构,常常是狭隘的。如果是IO密集型的,比如并发度特别高,以至于几乎总能取到数据,那么就不需要推模型。

另外关于队列的数据结构,多进程需要使用到共享内存,相对麻烦,实际用多线程就OK了。前文提到多线程环境下用普通数组即可,尽管数组是定长的,当超过预设大小的时候,表示已经超过了处理能力则直接报错给客户端,即为一种『熔断』策略。我们当然也可以使用vector,但是切记,除非你真的了解容器,否则不要滥用。vector不是线程安全的,因此加锁也是必要的。另外一个隐患是,vector是可变长的,很多人自以为便自己为得起便利,除非系统内存不足,捕获一下bad_alloc,否则就以为万事大吉。殊不知vector在进行realloc,即重新分配内存的时候,之前的返回给你的迭代器会失效

请记住C++不是银弹,STL更不是!

3. 变体:半同步半反应堆

HSHA模式十分依赖异步IO,然而实现真异步通常是比较困难,即便Linux有AIO系列API,但其实十分鸡肋,内部用pthread模拟,在这方面不如Windows的IOCP。而当时IO多路复用技术的发展,带给了人们新的思路,用IO多路复用代替异步IO,对HSHA进行改造。这就是『半同步/半反应堆』模型(Half-Sync/Half-Reactor,以下简称HSHR)。

我又画了一个潦草的图:

image

循环之初,Polling API(select/poll/epoll/kqueue)只监听服务端socket,当监测到服务端socket可读,就会进行进行accept,获得客户端fd放入队列。也就是说和HSHA不同,HSHR的队列中存放的不是请求数据,而是fd。工作线程从队列中取的不是数据,而是客户端fd。和HSHA不同,HSHR将IO的过程侵入到了工作线程中。工作线程的逻辑循环内从队列取到fd后,对fd进行read/recv获取请求数据,然后进行处理,最后直接write/send客户端fd,将数据返回给客户端。可以看出来,这种IO的方式是一种Reactor模式,这就是该模型中,半反应堆(Half-Reactor)一词的由来。

当然队列中存储的元素并不是简单的int来表示fd,而是一个结构体,里面除了包含fd以外还会包含一些其他信息,比如状态之类的。如果队列是数组,则需要有状态标记,fd是否就绪,是否已被消费等等。工作线程每次取的时候不是简单的竞争队首元素,而是也要判断一下状态。当然如果是链表形式的队列,也可以通过增删节点,来表示fd是否就绪,这样工作线程每次就只需要竞争队首了,只不过在每个连接频繁发送数据的时候,会频繁的增删相同的fd节点,这样的链表操作效率未必比数组高效。

3.2 epoll一定比select效率高吗?

曾几何时,有位面试官问我“epoll一定比select效率高吗?”。我说“恩”。然后他一脸鄙夷,和我再三确认。面试结束后。我翻遍谷歌,想找出一些 what time select is better than epoll的例子来。但是很遗憾,没有发现。百度搜索国内的资料,发现国人倒是写过一些。比如说在监视的fd个数不多的时候,select可能比epoll更高效。

貌似很多人对select的理解存在误区,认为只有监视的fd个数足够多的时候,由于select的线性扫描fd集合操作效率才比较低,所以就想当然的认为当监视的fd个数不是很多的时候,它的效率可能比摆弄红黑树和链表的epoll要更高。其实不是,这个扫描效率和fd集合的大小无关,而是和最大的fd的数值有关。比如你只监视一个fd,这个fd是1000,那么它也会从0到1000都扫描一遍。当然这也不排除fd比较少的时候,有更大的概率它的数值一般也比较小,但是我不想玩文字游戏,如果硬要说fd集合小的时候,epoll效率未必最优的话,那也是和poll比,而不是select。

poll没有select那种依赖fd数值大小的弊端,虽然他也是线性扫描的,但是fd集合有多少fd,他就扫描多少。绝不会多。所以在fd集合比较小的时候,poll确实会有由于epoll的可能。但是这种场景使用epoll也完全能胜任。当然poll也并不总是由于select的。因为这两货还有一个操作就是每次select/poll的时候会将监视的fd集合从用户态拷贝到内核态。select用bitmask描述fd,而poll使用了复杂的结构体,所以当fd多的时候,每次poll需要拷贝的字节数会更多。所以poll和select的比较也是不能一概而论的。

当然我也没说select在“某些”情况下肯定就不会高于epoll哦(括弧笑)

虽然总体来说select不如epoll,但select本身的效率也没你想象中那么低。如果你在老系统上看到select,也运行的好好的,那真的只是Old-Fashion,不存在什么很科学的解释,说这个系统为什么没采用epoll。Anyway,除非你不是Linux系统,否则为什么对epoll说不呢?


好了。本文基本就到这里了,再留个课后题:本文提到的模式严重依赖队列,那么可以取消掉这个队列吗?答案是当然可以,只是那就不是HSHA了,而是Leader/Follower或者其他了。

虽然本文废话很多,也可能论述有出入。但是如果你能耐心读完,相信你还是会有所收获的。很多模糊的,抓不住的概念,可以抓住了。很多自己本来就知道的东西,其实是一套定义或方法论的。所有技术问题都怕耐心,网络编程亦如是。耐心坚持下去,你终会发现:

高山仰之可极,深渊度之可测


平时工作繁忙,写这篇文章呕心沥血,耗尽几个周末,笔者水平有限,文章内容难免有误,还望指出。写作、分享本就是一个相互提高的过程。

另外如果你觉得,看完有收获的话,欢迎:点赞,收藏,转发,评论,多多关注《后台公论》,下次再见。

相关阅读:

C++转型对比

从C时代开始。转型主要分为两种:

  • 显式类型转换
  • 隐式类型转换

显示类型转换

显式类型转换C

极度不安全。对于不相关类型(非继承)的指针也可以转换……(其实反过来也可以利用)

static_cast<>c++

比C风格转型,安全性上高一些。可以识别出不相关类型指针的转换。在编译期间报错。
比如(clang):

error: static_cast from 'A *' to 'B *', which are not related by inheritance, is not allowed

dynamic_cast<>c++

要点:

  • 原类型含有虚函数
  • 模板类型要是指针或者引用

错误1:转换成非指针/引用类型

B b = dynamic_cast<B>(a);

error: 'B' is not a reference or pointer

错误2:给不带虚函数的类型指针转换

用dynamic_cast给不带虚函数的类型指针转换。报错:

A *pa = new A;
A a;
B* pb = dynamic_cast<B*>(pa);
B b = dynamic_cast<B&>(a);

上面两次转换都报错:

error: 'A' is not polymorphic

给类A加上一个virtual的函数。再抓成不相关的类型B。
不报错。

正确用法

class A {
public:
    virtual void echo() {
        cout<<"A"<<endl;
    }
};
class B {
public:
    void echo() {
        cout<<"B"<<endl;
    }
};
int main() {
    A *a = new A;
    B* b = dynamic_cast<B*>(a);
    b->echo(); // 输出 B
    return 0;
}

指针下行转换(能编译通过)

父类指针转换为子类指针,编译不失败。两种情况:

  • 父类指针指向的实际是子类对象。成功转型。
  • 父类指针指向的就是父类对象。编译无异常,只是返回值是NULL。

dynamic_cast无二义性。不会一个编译通过,一个不通过。而实际转型成功与否交给实际情况去判断。这个其实就是RTTI

reinterpret_cast <>c++

最不安全的类型转换。像C转换一样,两个指针可以毫不相干。
另外它也要求转换目标类型为指针或者引用。

const_cast<>c++

消除const属性!一般工作中被禁止使用。

总结

上行转换,通常安全。下行转换很可能不安全。
static_cast效率比dynamic_cast高。因为RTTI效率更低。
但static_cast可能不够安全!
个人总结,只有父类有虚函数,就用dynamic_cast。没有就用static_cast。


Reference

关于分布式中CAP的反思

很久之前就听说过CAP,知道其表达到是三者无法同时满足。

C 一致性
A 可用性
P 分区容错性

后来读了DDIA,发现自己之前的很多理解还是浮于表面,没有深入骨髓。思考如下:

CAP作为经验提出,并无准确的定义。
CAP只是历史上有重大影响力的一个说法而已,对于具体系统设计的价值有待商榷。
CAP范围很窄:

  • 一致性只考虑了线性化的一致性这一种。
  • 故障也只考虑了网络分区(节点断连但各自活跃)没有考虑网络延迟、节点失败或其他折中的情况。

三者不能同时满足。这个说法有误导,其实准确的说法是:一旦发生网络故障(分区),必须要在C和A之间选择一个!因为网络分区P不是特性,是故障,无所谓喜欢与不喜欢。而C和A则可以权衡!

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

1. Ouroboros

古埃及有一个图腾:一条咬住自己的尾巴的蛇。后来这个图腾广泛流传,渗透到印度教,古希腊,也出现在北欧神话中。其名为:Ouroboros。象征着宇宙循环,无始无终,开始即是结束,结束亦是开始。其实生活也常常是这样,任凭时间推移,生活却总在某个地方回归原点。

2. 风雨与屋檐

2018年4月在公司内网的论坛上,看到一个帖子:

有人问:“什么时候你感到青春已逝?”
回答说:“所谓青春已逝,大概就是当风雨来时,抬头一看,已无屋檐。低头一看,自己已成屋檐的时候吧。”

几天之后,组会上得知一个消息,犹如晴天霹雳:“同事老孟即将离职”。

老孟是个全能,组内业务无一不精。他在入职一年后便迅速成长为组内骨干。

两年前我毕业入职以后,几经辗转来到这个组,那时开始就是老孟带我们做事。我们组年轻的同事很多,基本上都是同一时期入职的,老孟经常给我们拆借产品需求、做设计。也会帮我们出主意,帮我们和PM怼方案,帮我们处理线上问题,给我们的粗心大意擦屁股。

在组长眼里,老孟是骨干。在我们年轻同事看来,老孟就是大树,就是风雨中的屋檐。

他帮我们顶住了很多压力,长期以来,我们都很依赖他。虽然我们也经常半开玩笑地怪他做的太多了,导致我们自己没有得到锻炼。但是谁都不想没了老孟,不然我们可能更糟。

但这次是真的。

3. 是沉溺,还是用技术寻找人生的意义

再谈一下我自己和我所处的部门,我不以偏概全,肯定并非整个鹅厂都是如此。我所在的团队经营着一个边缘业务,缺少用户,没有请求量。做的业务属于第三方支付行业。早在刚工作的时候,我就发现,在这里工作越久,就越来越离不开这个行业了,而这个行业安身立命之本、职业发展技能更多的倾向于业务逻辑上的一些套路,而非一些纯计算机、纯技术的东西。

常常自嘲“if else”程序员。但是很快我就自我安慰,工作紧张忙碌,也没时间留给自己思考人生。我去认真的学习行业知识,去看支付和金融的书籍。也去细心的钻研我们产品业务逻辑。只是每每“农闲时节”,心中总有块垒,难以消解。

我知道若说业务逻辑不重要,难免也失偏颇。但业务逻辑真的只是纸老虎,并非难啃的硬骨头。我也不是鼓吹大家都转型去做基础架构,这又是走向另一个极端。我们也不应该因为自己做产品开发,做业务码农,就妄自菲薄。做产品、业务也可以接触到、学习到技术。腾讯各BG壁垒森严,技术水平参差不齐,肯定有优秀的,也有差的,但我们这显然是后者。日常还在用着上个世纪的技术,不去革新。美其名曰:追求稳定、安全。

春节红包每秒几十万笔交易,用户体验未曾衰减。其实很多时候,技术沉淀并不算差,只是不够新而已。

成吉思汗的骑兵,攻击速度与二十世纪的装甲部队相当;北宋的床弩,射程达一千五百米,与二十世纪的狙击步枪差不多;但这些仍不过是古代的骑兵与弓弩而已,不可能与现代力量抗衡。 ——《三体》

当然我并非鼓吹一味求新,马车不会有重大交通事故,但它最终被汽车淘汰。17年底,18年初,我想试试换个环境,跳槽和内部转岗都尝试过。遗憾的是面试都没有过。我平时绩效还算可以,但我积累的业务经验对面试来说就完全没用了,因为不考这些,而我工作以来技术本身成长不够,并且计算机基础、数据结构算法等知识自从毕业开始也像沙漏一样一点一点消散殆尽。所以面试时写一两个比较基础的算法题的时候,我竟然也感到措手不及。其中一个题目竟然和我当年面试实习生的时候一模一样。

自那以后我备受打击,暂时没有了离职的想法。接下来上半年也比较忙,我又再次温柔地走向了那个良夜。沉湎于这样重复的日子中了,甚至有些享受。

回想起电影《海上钢琴师》,凝望久久,面对看不见的恐惧。舷梯之上,我转身回到了船上。

4.对不起,您呼叫的用户正忙……

前面都在争论技术,似乎会带偏新人。即使是程序员,职业生涯也不能只盯着技术,跨团队协作、沟通、推动、抗压这些软素质真的不是在JD上随便写写的。

在得知老孟要走的时候,当时部门有两个比较急的项目。项目A,老孟带我开了一次会以后,他就做了甩手掌柜。当然也不是完全不管我,只是在随后的交接时间里,赶上了劳动节,况且老孟自己没用完的年假要休。

那时已经四月中,项目A的目标是6.1 开发完与其他部门联调。而项目B我也有任务,开发的deadline是5.30。

项目A,一下子变成了我主导,除了写代码还有很多其他事要做。比如与强势的上游部门沟通交互,写接口文档;梳理我们组的改动点,修改、新增哪些模块,从而完整串联起各个业务流程;最后与我们组下游的基础团队,提出我们的需求以应对这次的项目。

凡是你做过的项目,都是你的项目!
除了新项目本身呢,我还有很多其他事情要做,我去年做过的项目,虽然没有新feature,但每天都会产生大量的日常维护工作和客诉工单需要处理,我白天时间几乎被这些杂事消耗掉了。

日常里,别人在企业微信里找我,我在忙的事,没有回复,可能很快就会接到他的电话,有时刚放下电话,又接到下一个。因此晚上成了写代码的黄金时间,尽管每天回家很晚,回到家之后,我还要开着VPN远程写代码,一两点睡觉变成了家常便饭。周末几乎默认加班,我不是在公司,就是在家里远程。

五月份老孟走了,六月份开始。组里陆续来了新人,我成了一个实习生和一个毕业生的导师,除了平时的工作以外,还要抽时间去带他们熟悉工作,了解业务,分配任务等。

虽然那段时间成长很快,但也不得不说累成狗。

按照鸡汤文的套路,你可能会想我的”虽然“和”但是“是不是写反了?

不!没有,是真的很累。

经常头晕,脑鸣。早上为了多睡会,就打车上班,有一次下了车突然头晕,蹲在地上。也有好几次开会的时候头晕,忍不住把头埋起来。

彼时,领导给我画饼,我也给自己脑补了一段**“锦绣前程”**。比如好的绩效、调薪。这可能是我熬过那段日子的唯一办法了。

5. 读万卷书,行万里路

七月中,我开始琢磨重新找工作了。

因为领导和我沟通,我发现自己幻想破灭,没有什么锦绣前程。

突然信仰崩塌,如果这里没有技术成长,也没有个人发展,每天拼命加班做一些没有含量的工作,是为了什么呢。我本来就是想离开这,之前还自我催眠,如今幻想破灭,也是一个不错的契机。

生活莫名有趣:总是有人,在你认命、停滞不前、原地打转的时候,推你一把,逼你去奋斗。

几个重要项目接近尾声,白天工作。下班之后,我开始准备,复习。看面经,刷LeetCode,整理年初我面试过的那些题目。

深圳已经没有地方可去,我主要看北京的机会。几天之后我按捺不住,在拉勾网上投了头条。但结果一面还是挂掉了,虽然算法这次只考了一个大数相加,但可能是其他的问题,我回答的不好。
“胜固可喜,败亦欣然” 这次我心态比半年前好了很多,没时间安慰自己,继续准备。继续刷LeetCode,然后整理头条这次的面试题。

同时我继续找机会。联系百度的朋友内推;在拉勾上又投了北京亚马逊;然后有两个猎头强烈安利我投了两个创业公司A和B。这时候是处于广撒网的状态,但是我发现两个问题。就是社招不比校招,面试需要在工作时间面试,而面试官的工作时间,我也在工作。另外就是我人在深圳,不是所有的公司都接受全程的远程面试。

在收到4个公司的面试邀请的时候,我没有继续投简历了,此时我开始酝酿一次北京之行。

七月底,我联系了这几家公司,各自协调了一下面试时间。

  • 7月29号,周日,我坐飞机去了北京,称家中有事,请了周一周二两天年假。
  • 7月30号,周一,上午在朝阳区面试北京亚马逊,下午去海淀区面试百度。
  • 7月31号, 周二,上午面试了公司A,下午面试了公司B。晚上10点的飞机返深。凌晨两点到家。
  • 8月 1号,周三,照常上班。

关于数据结构和算法题,我真是做了很多准备,年初那次就深知自己在这方面的退化。后来我随身写的一个小笔记本(不是电脑,是真的本子),没事的时候就在纸上手写一下链表逆置、合并链表之类的。包括在去北京的飞机上,也在笔记本上写写画画。

目前我资历尚浅,还需要在大厂积累。我主要就是看亚马逊和百度的机会。一次性面完了三轮技术面。白纸上手写代码写了6道算法。最终百度当天就确认面试通过,我很高兴。其实当然也感谢给我内推的那个朋友。但亚马逊很遗憾,我没通过面试。也谈不上什么失落,我知道自己这两年技术进步有限,所以这些结果我都能接受,这不就是我要离开的原因吗,不是?

回到公司后,我开始焦急地等待着百度发正式offer,当时我想一旦offer,我就和组长去提离职了。在左等右等不到,偏偏这时候又赶上有个紧急的项目,没办法还是急急忙忙地去加班加点了。

我和深圳小伙伴的散伙饭都吃过了。问百度HR一直反馈在审批中。然后说HC紧张,让我继续等。这时候其实已经八月底了,我的心态已经崩了,你知道当一个人已经做好离职准备的时候,最后无法离职,是什么状态么?

箭在弦上,不得不发

我越来越焦虑,所以我开始再次找机会。这次我把目标放宽了,不限于北京了。

我又拾起放下了的书本和纸笔上路了。

  • 8月31号,周日。上午飞到上海,下午面试。晚上飞回深圳,凌晨到家。
  • 9月1号,周一。照常上班。下午阿里通知说周二可以面试。我急忙订票,吃完晚饭,没去加班,回家收拾了一下东西,直接赶到机场。半夜里抵达杭州,住了一晚。
  • 9月2号,周二。上午和领导请假一天。面试阿里。晚上飞回深圳,凌晨到家。
  • 9月3号,周三。照常上班。

说巧不巧,9月2号。我在杭州机场准备返深的时候,收到了百度的正式offer。两天后,公司C也发了offer,薪水相当诱人,我自己都感觉我不值这个价钱。

不久后确认了一家的offer,突然感觉确认哪家已经不重要了。从七月到八月,再到九月。从思路到心路再到脚下的路。也可谓:

读万卷书,行万里路

辗转了这么多地方,这段时间的所有经历,我所走的每一步,仿佛超越了我离职的理由。过程本身超过了过程的意义。我美其名曰“救赎之旅”。蓦然回首,我自己甚至都有点佩服我自己。当年那个说走就走的劲头还在,那个愣头愣脑的自己又回来了。

6. 回首向来萧瑟处,也无风雨也无晴

前文说道我还有两个徒弟要带,一个毕业生一个实习生。时光回溯,8月份在焦急等待offer期间,我带着毕业生小伟加班做新项目。本来他也是和一般新人一样慢慢悠悠做事。项目期间基本是我先给他写好改动点的文档,然后我再去写我的代码,工作也是繁重。

而这个月实习生也迎来考核末期,决定是否留用的offer。而关于留用考核,实习生小A表现得很焦虑。光阴荏苒,恍惚之间,感觉自己回到了三年前,2015年,我来实习的日子。我也是一样的焦虑。我毕竟是过来人,我给他很多规划和建议,最后这段期间要怎么做,周报要汇报什么,平时要学什么。最后要做个PPT做汇报。他已经做得差不多了,我看了一下没有达到我的要求,我就让他增加了一些内容,把我们业务的几个主要流程用时序图表现出来,力求有大局观和准确。修修改改,不知不觉到十二点,他可从没有加班到这么晚,不知道会不会恨我。

回头说一些8月份开始的项目,deadline是9.30。9月初,确认了新东家的offer之后,我开始陆续交接工作。彼时这个项目大体结构已经完成,剩下一些偏重复性地改动以及联调、测试、修复bug的工作。当然时间还是很紧。小伟虽然本来也在参与,但现在我要把更多的工作也交给他。

在得知我要离职的消息之后,他一脸懵逼,因为他要从打下手的角色转变到承担更多。工作的压力一下压到他身上。我当然还会继续帮助他,指导他,但更多地只能授之以渔了。我知道对于一个新人来说,这种事有些残酷,但是没办法。因为,我必须要走,而他则必须要成长起来!

看着他每天加班到很晚,看着他写代码,改bug,配合联调,在群里被很多人艾特。他加班的时候,希望我能在,即使在公司看看剧也好,因为他可以随时向我抛出问题。这一幕幕竟然都那么似曾相识。就在短短几个月前,就在老孟说他要离职的时候。

记得老孟离职之前有段时间,他休假,这期间有很多杂事,我处理地心烦,还有新项目的需求细节要和合作部门与团队勾兑,我从一个会议的旁观者,必须要转变为一个讨论的主导者,我必须要对我们已有的系和要做的需求了解得十分清楚,另外要面对合作部门的各种高级工程师,面对他们的咄咄逼人,不能怂。我每天压力都很大,某天有个重要的会要开,我心怀焦虑地来到公司。突然看到老孟坐在座位上,我顿时舒了一口气,心里不慌了,原来是他休假结束了。

当然快乐总是短暂,几天之后,老孟真的走了。后面所有刀光剑影,都只剩我一个人面对。

现在小伟处于我曾经的状态,而我在不经意间变成老孟的角色。角色变换之间,我突然切身明白了那句话:

“所谓青春已逝,大概就是当风雨来时,抬头一看,已无屋檐。低头一看,自己已成屋檐的时候吧。”

7. 人生是一条蛇,它咬住自己的尾巴

来到新公司。所有之前的资历、经历烟消云散,由于换了一个业务领域,我的知识经验很多也都清零了。我又一次有了导师,我又一次变成徒弟。我又一次变成菜鸟,又一次变成了屋檐之下躲避风雨之人。往事如烟,心若空杯,每天感觉都能进步,都有成长,也是一些安慰了。

入职两个月后,新人要做一次分享,剖析一下当前的系统模块和业务流程。代码量很庞大,想面面俱到是不可能的,我挑了几个部分,做成PPT。但是导师又给提了几个部分,要作为分享内容,我之前并不了解这几部分,无奈周末加班加点去看代码,去改PPT。时间再次倒退,仿似我指导实习生做答辩PPT,又仿似2015年我去制作实习答辩PPT的场景。

2018从春到冬,从2015到2018。时间仿佛打了一个死结,让我的生活不停转圈。其实即使没有这么多变数,这么多抉择,人生也是在某个时刻原地打转,就像我在腾讯那两年,停滞不前。但不同的是,由于一些变数,一些抉择,这个圈不一样大了。一切的一切,看似循环往复,其实在循环背后某些东西也在悄然变化,而变化本身最终会导向好的或坏的结果,或许只能留到下一个轮回,才能得到答案。

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

一个人的战斗

原写作时间 2013-03-24

作为一名爱好编程的大学生。我在独自奋斗。

在周围人都在拼命LOL的时候,我却奇葩地拼命敲着代码。这是在大一的下个学期。在上个学期,过的浑浑噩噩。也想学点技术。但是不知道学什么。东学一点,西学一点。学了点html,也学了点PS,学了使用dreamweaver,也学了点illustrator。但是都不是很精、自己也不知道要该怎么走。上学期就这么过了,期间还跑过推销,做了校代,最终的业绩只是卖个了老乡一件衣服,还挂了一门工程制图。

后来在高中同学那里听说了ACM,我开始热爱上这个。我心里想“对,我要的就是这个”。然后在努力得学,到现在差不多一个半月。最初的时候连c语言基础都不牢固,老师也没讲完c语言。我就这么开始了。但是苦逼的是我们学校根本没人搞ACM,连校队都没有,其他学校都是有的。我只有一个人在战斗。

今天参加了腾讯编程马拉松。第一道题WA了好几次,找不到原因。在确实测试了很多数据……感觉自己真的差得很远。作为高中没有noip背景的人。我只有更加努力的奋斗。因为我爱ACM。我爱算法。我爱编程。曾经听华南农业大学的ACM交流群里,有人说ACM是他的初恋。我想没错,就是这种感觉,就是这种,不管失败,受挫多少次,都死心塌地,义无反顾的感觉。

Follow My Heart —— 大二下

原写作时间 2014-07-03

又是一个学期过,呼吸之间,四个月时间飞过。这学期,感觉自己在技术上又有了长足的进步,并且感觉是个“飞跃”。貌似每个学期期末的时候都会有这种感觉😂。不知道这个学期进步的程度比前面两个学期是大还是小,不好评断,姑且一一记录。并且,无论学习生活,都悉数整理一番。

1.学习

我一直形容自己的学习之路是“摸着石头过河”。一直以来,我都是自学的,不像其他人那样有个社团或组织之类的,有前辈指路。诚然,上个学期我加入了IOT实验室,但不得不说里面软件组一直不被重视,我在里面也全是自学。我戏称自己是野路子,但我很佩服自己搜集信息的能力,还有面对选择的判断力。虽是野路子,自己走的倒也不错。摸着石头过河,我不知道我一百步以后会怎么走,我知道下一步怎么走。但是我每走一步,都能发现新的下一步该怎么走,所以我能走到第九十九步,然后一百步,一百零一步,一百零而步……

1.1 GitHub

这 个学期最大的收获,就是学会了使用GitHub,学会了常用的git命令。寒假时候,自己也琢磨过GitHub,但始终不得要领,一头雾水。三月份的时候,无意之间,开始领悟如何用GitHub。慢慢地学会了什么时候需要GitHub,GitHub能做什么。然后接下来自己的每个项目包括 android(eclipse),Qt都会使用GitHub托管。

1.2 Linux

这个学期关于Linux,算是真正的入门 了。惭愧,接触Linux有一年了,一直没有什么感觉。不知道怎么学,如何学。现在很多常用的命令,我已经很娴熟。也体会到了终端的威力与便利,慢慢地开始有点厌恶鼠标了。bash脚本的学习也有了进步。开始使用gcc、gdb来编译调试C代码。gcc、gdb也是长久以来就想学的,但是每每也都不得要 领,没有学习的手感,最后还是回归到VS这等IDE上,这次真的开始上路了。关于gcc,gdb和VS等IDE之间的效率问题,我不置可否。我只想说,我们学一个东西,如果仅仅只是停留在 用 的层面上,就太低级了。gcc,gdb除了拥有源码的编译调试外,更重要的是让我学习到了,程序编译,连接,到运行的整个内部流程。还有关于静态链接库,动态链接库的知识,二者是VS等便利的IDE所不能让我体会到的。所以,学习有时候不要只停留在表象,更要学会追根溯源。

1.3 打地鼠APP

这是三月份的最靓丽的一笔了。起初由一个网友那里看到一个用Java写的打地鼠游戏(PC版),我就琢磨要不自己也写一个android版的打地鼠,于是就开始写了起来。名为“妈妈再打我一次”。我把地鼠的头像换成了这个前段时间流行过的一个形象:
logo
后来还上线了 百度手机助手 (没什么下载量)
)。这其实代码逻辑并不复杂,但通过这个项目,我体会到了一个很重要的一点:创意比技术更重要,想法比能力更重要。这个项目中我并没有用什么高明的代码,用的都是很简单的实现逻辑。从代码层面来讲,初学android的人都能写出来,但是呢,自己当初开始学android的时候,却从未有过做一个打地鼠的想法,一直以为自己的实力不足无法cover这种小游戏,但其实有好的实现的想法的话,简单的代码也能实现。然后,我感悟了一点:最厉害的厨艺,不是满汉全席,而是无米之炊。

技术薄弱,实力不足,都没关系,只有你有足够的创意,你就能玩出花样。禅宗始祖,六祖慧能是不识字的,但是却悟出了奥妙佛理,所以师傅传递衣钵给他。代码始终只是工具,是我们表达自己情感,表达自己想法的工具,不要为了学编程而去学编程,是为了玩才去学编程。

1.4 计算器

在金工实习那一周,颇为无聊,又赶上数据结构要交期中作业,写栈的学习笔记。然后我就想把栈的后缀表达式给实践一下。趁着实习的时候时间宽裕,就写了起来。开头Qt我懂得真的不多的,但是遇到问题,百度一下,就能解决。 感觉这应用层的东西,真是没用门槛可言了,最后计算器完成了。里面界面部分真的没有什么值得夸耀的,应用层的东西,上手很容易。最困难的地方,就是后缀表达式实现的算法了。很多算法,你用心算,用笔算,用手算,都很容易,但是要用计算机来实现就不那么容易了。果然算法才是王道。

2. 生活

2.1 日常

这学期,因为开学前的一个小手术,损失3000+……,是啥手术我就不说了。所以预算超支,驾校也没有报。再加上学费改制:jb学分制收费,80一个学分,这学期我+补修+重修,最后41.5个 学分,比室友多交一千多块钱。然后就过着苦行僧般的生活,我就觉着这个学期过不下去了,期末肯定会借钱了。然后下学期怎么还呢?就想着当一回学霸吧,拿点奖学金来还债,囧。

不过后来,还好。省吃俭用的,发现能凑活活下去。还瘦了10斤。到后来,又跟家里要了两次钱。(属于正常的要钱范围)这期末就没有借钱就过来了。发现人的潜力还真是无穷的。三百块可以吃三个星期。原来我可以想不到的。而且也不饿,其实关键就在于看你吃什么了。

“君子食无求饱,居无求安”就是这样吧。所以能吃饱就行了。吃肉能吃饱,难道吃菜就吃不饱吗?对吧,姑且做一回君子。这也算是对于心志的一个磨练吧。

有的人吃东西是为了活着,有的人活着是为了吃。

再顺口说一下,这个学期领到了“软件设计师”的证书,还有英语四级的。至此,大二上个学期的目标基本上是完成了,我还记得去年八月底在去学校的火车上我定下的目标,就是大二上,考三个试,拿三个证书。除上面两个一位还有一个计算机二级,当然这个很水了。我是因为我是从非计算机专业转过来的,所以曾经报了名二 级的。按理说,计算机专业是不考二级的。

2.2 日剧

这个学期还有一些收获,是看了两部日剧《新选组血风录》、《风林火山》。前者12集,后者50集。都比较好看,强烈推荐历史迷去看《风林火山》。看里面的行军打仗的兵法诡道还有各国之间的合纵连横。看这部剧给我的历史课好好的恶补了一下。懂了好多关于日本战国时期的历史。不要吐槽我这点哦,我只是单纯以一个历史爱好者的角度去看日本历史的。对于历史,大家 还是要公正的评断。国内的电视剧实在是不想说了,穿越,后宫,谍战,婆媳。基本上没有严肃的历史正剧。。《新三国》还可以。但是里面的历史段子太熟了,初中时《三国演义》就看过两遍了。。转而看日剧,也是形势所迫。。其实关于历史,大家还是不要抱着太狭隘的民族情结在里面。因为当今日本决策者的某些问题, 使得国人看到日本就去黑,,,其实没必要,否则日本动漫大家也不要追了。

“风林火山”一词出自《孙子兵法》,传入日本后,被日本战国时期的军神武田信玄写在了旗帜上。自此这四个字名声大造。其实本身在**这四个字历史上给的关注并不多,恰恰是武田信玄的行为使得“风林火山”一词知名度猛增,然后回流到了**。。

我 是很佩服日本人对于**古典文化的了解程度。剧中有一桥段,主角山本勘助(武田信玄军师)假扮和尚潜入越后国,但被越后国的长尾景虎(后来赫赫有名的上杉谦信)所擒,景虎说了一句“‘鹪鹩巢于深林,不过一枝’你们为什么一定要侵犯他国的领土呢?”结果山本勘助回了一句“贫僧不好《庄子》,要对贫僧说教,请讲《孙子》吧。”

确实,景虎的那一句“鹪鹩巢于深林,不过一枝”是出自我国的《庄子》的,相信很多**人都不知道吧。
关于《风林火山》,我看完之后写了一篇长文回顾,有兴趣的请戳:👉「 #13

2.3 数学建模

曾 经我也想过暑假留校的,但是参加了校赛搞了一个礼拜实在是TM地想吐了。队友不给力啊,三个队友,有一个队友天天忙。校赛期间还没时间,说什么好忙,写 作业写到半夜两点之类的。她就一直没主动和我们联系。哎,她也认为我和另一个队友刘是水逼了。所以没对我们交数模论文报太大希望,但是我和刘苦战了一星期,勉勉强强还是交上去了。最后得了个三等奖,奖品是两条毛巾。我认识的都是一二等的。呵呵,输在起跑线上了,不跟你们玩了。所以决定还是不留校了。

值得一提的是,在此之前我对MATLAB并不熟,队友刘是通信专业的,这个学期有学这个,所以最初的决定是他编程,我写论文。后来, 我们两个在研究数学的阶段就人手不够,开始他有点进展了,我就试着编了点MATLAB,不会的语法百度一下。。通过知识替换,成功的把其他语言的一些经验 借鉴到了MATLAB中,所以很快我编的就比他快了,也比他好。后来我就一直编程了……

2.4 物联网实验室

开学初期,就 退掉了。呵呵了。里面一个恶心的指导老师,明明自己什么都不会,还到处叫嚣。说什么,你们学软件的太好学了,不像学硬件的;软件组不要老学习了,直接去做项目。虽然我也是鼓励从实践中去学习的,但是这个实践也是要有一定的基础来可以的。。但这SB老师根本连这一点基础都觉得不需要。后来我就离开了,说实话,我不想去管理什么软件组,太分散我学习技术的精力了,现如今学好技术才是王道。做一只闲云野鹤挺好的。自己学的倒也快活。不用再像那样,自己去 完成别人定下的学习任务。。兴趣全无啊。大一大二,大家还是多尝试,多摸索的好。。每个人的经历都不可复制,所以即使是按照前辈们的学习任务,恐怕也不得当。因为每个人有自己的路。

Follow Your Heart,跟着自己的心走吧,不会错的。前提是判断力要强哦。

我的2015:感悟篇

原写作时间 2016-01-21

就业

就业呢,是个亘古不变的话题,对大学生而言尤其如此。无论你是大一大二也好,无论你是大三大四也好。无论你以后是否读研也好,你始终都是要就业的。关于就业呢,首先要谈的是择业。

理想状态下,择业问题对于大部分毕业生而言归根结底就三个:

  1. 从事自己喜欢的工作
  2. 从事高薪的工作
  3. 去名企

说白了就是情怀、钱和逼格。(最理想状态下,大家希望能找到满足这三点的工作)我个人而言是倾向于第一点。从事自己喜欢的工作。对于大学的专业呢,大家真的不必过分纠结。如果你不喜欢你自己的专业,真的没必要去坚持。有些人担心虽然专业不好,但大学期间也努力学习了,不想就这么丢掉。其实应该看开点。我们从小学到大学了这么多知识,现在还能记住多少(尤其是高中知识)。那些知识学过了,就不算白学,它们在某个特定的时间内完成了它们应有的使命就够了。当然了,如果你喜欢自己的专业,那么就更好了,努力去学就行了,最忌讳的就是说一套,做一套。很多研究生这一现象尤甚,读研期间学的技术方向很屌,所以找工作的时候也非要找这一方向的。其实这样并不好。我认识一个研究生研究方向是机器学习。但是人家就是要找前端的工作,最后拿到了BAT某家前端的special offer。务实很重要。

当然了,对于大学生而言对很多职业认识不清,甚至有很多职业都不知道。我有一些同学的打算就是找本专业相关工作,找不到就去找销售之类的工作,实在找不到工作去考个公务员,或者考个教师资格证当老师。其实单就计算机专业而言还是有很多职业方向的。最响当当的一个就是技术路线,俗称码农或程序员。同学们想到的首先是开发。开发又分为web开发,移动端开发或者前端,后台的开发等等。这个技术选型要早点确定,指望着在快找工作了再去确定,确实有些晚。开发路线这里我就不过多表述了。基本大家都了解。

除此之外关于技术路线还有两类:测试和运维。很多人都喜欢开发看不上测试,其实没必要这样。如果你的目标是去大公司工作,那么去大公司面试测试可能比面试开发通过率更高。不过很多人还是很有情怀的,宁折不弯。比如我一个学长当年在找工作的时候面的阿里的开发,最后阿里给了测试的offer。最后他就给拒了,然后在一个小公司做了个开发。当然我不是说人家选择就是错的了,很多时候不同人的价值观不同,找到适合自己职业发展的路线是最重要的。PS:女生找个测试的工作不错。再说运维这个工作,其实任务量也很繁重的。基本上你要熟悉Linux系统的使用和管理,shell和python脚本的编写,各类软件运行环境的搭建和部署,数据库也要了解。此外对硬件方面还有要求,比如对于网络系统结构(比如网络的拓扑结构)要有深刻理解,精通各种那个组网。对网线呀,交换机呀,路由器呀、硬盘呀这些设备要熟悉。感觉考个CCNA的证书比较贴合(个人之见)。我到大四了,才发现我们专业(网络工程)就教学内容而言更倾向于培养运维人才(实属大学教育的悲哀)。其他的技术岗位,比如算法相关的(数据挖掘、机器学习等)更适合研究生来搞。

除了技术路线外,互联网公司还有两大类岗位需求:产品和运营。以我个人对这两种岗位粗略的认识:产品岗主要是给产品构思功能(然后给开发提需求),不停地优化产品细节,增强用户体验。运营岗主要是利用各种手段增加用户数,比如策划线上活动,还包括线下的推广,比如地推。一般线下的运营人才都有强大的沟通谈判技巧。【不知道我对这两个岗位的认识对不对】总体来说,很多在校生对这两个岗位都是不熟悉的。运营岗可能和大家熟知的营销、策划甚至销售都有点关系,但是产品岗则是在大学里几乎找不到一个对应专业的。正是因为这样,造成了很多在校生对产品岗了解不多,甚至闻所未闻。但也正是由于没有对应专业,所以几乎大学里任何专业的学生只要肯花时间学习都能成为一个产品人。从别人那里安利了两本产品人的书籍:《人人都是产品经理》和《结网》。另外我要推荐一个电台节目——“IT公论”。这个我自己真的有在听,前面两本书其实没有读过。我个人是程序员,IT公论也是被一个程序员推荐的。里面有些内容技术性很强,非码农可能不一定能懂,但是更多的内容我感觉更适合产品岗的同学们来收听。

       

好了,择业问题,告一段落。在确定了自己未来要从事的职业之后,然后就要早做学习规划,努力了学习了。具体怎么学的,千人千面,不能照搬照抄,这里也不做过多讨论。然后就到了招聘季,或临近招聘季。这里我要强调的是判断力和勇气。比如当时我们学校,是辅导员鼓励大家去网申腾讯暑期实习的。后来我通过了。我有一个技术也很不错的同学,和我技术选型也十分类似。C/C++,Linux,学了环境编程,网络编程之类的,计算机专业基础扎实(学霸),这些技能点是很对鹅厂胃口的。当然我在面试之前也是不知道到底对不对胃口的。。而我这个同学直接连网申都没有,他自己的话说就是觉得面腾讯太难了,很难通过(这可能是小学校学生的通病,不自信,我们学校确实很少很少BAT。)。我就觉得很可惜。所以选择常常是很需要勇气的。就我个人而言,我在南昌读书,面试通常要去武汉。我有其他同学也通过了腾讯笔试,但是通知了去武汉面试以后,就打退堂鼓了。当然如果我们也是武汉本地院校的话,这些同学可能也会去试着面一次的,但是由于在外地,一下子就觉得如果面试失败那么成本就高了。这个成本包括经济上的(火车,住宿之类),也包括心理上的。比如可能有人议论“哎呀,这个人还跑那么远去武汉面试,最后还是不过。这人太盲目自信了”。很多年轻人做事总是需要有百分之八十甚至百分之百的成功把握才去做,这是一定一定一定要改正的,年轻人其实什么都没有,但是有的最多的就是时间,去尝试一下,即使失败了,也就浪费一点时间而已,并且即使失败也能增长经验,并且不要怕丢人。所以年轻人做事、做选择一定要有勇气。不要把自己的懦弱美其名曰:“有自知之明”。有时候“自知之明”不一定就是好事。面试很多时候也是看运气和缘分的,可能碰巧面试官的问的都是你知道的,或者你很对面试官胃口,这都有可能。也不要因为一次失败,就对自己丧失了信心,降低自己的就业标准。有的同学面腾讯挂了,但是面百度就过了。这都是有可能的。

行业

2015年你问我什么概念最火,我会说:“互联网+”。如果你再让我说具体一点,我会说:O2O和互联网金融。如果你是在2014年底问我这句话的话,我可能回答的是O2O和互联网在线教育。当然这些都只是我自己的观点,局限于我个人的认知水平,所以不一定客观。当线下的各种服务开始互联网化的时候就是O2O。当金融行业开始互联网+以后就是互联网金融。       

2015年百度狂砸250亿美金去做百度糯米,发展O2O。不得不说是一步险棋,此后股价很快就下跌了,因为美国人不懂**国情,不相信**的O2O故事。所以最近传出百度有意将部分业务转向国内A股上市。2015年滴滴和快的合并,因为做O2O太烧钱了。两家一合并迅速成为垄断地位。但是好景不长,很快Uber杀入**市场。呵呵。2015国庆节刚过,美团和大众点评成功牵手。此前两者在国内同行业中就是第一第二的位置,彼时也传出了一个段子。这样说道,百度在发力百度糯米之后,励志在年底成为国内的第二,然后再美团和大众点评合并之后,促使百度糯米提前实现了目标。呵呵。。 
 
互联网金融是不得不提的话题。最近一两年,尤其是2015年,国家对互联网金融的监管逐步放宽,原来将互联网企业(甚至所有民营企业)都拒之门外的领域开始松懈。2015年1月,央行开始下发通知,让芝麻信用、腾讯征信等八家公司做好个人征信业务的准备工作。此前个人征信的业务可以一直由央行把守着,这次权力的下放无疑是看中了互联网企业拥有的庞大数据,这些数据能够对评估公民信用提供更多元的参考维度。征信只是金融的一部分,金融还包括理财、信贷、证券、保险等等。       

余额宝是阿里最早的互联网金融产品,2015年,芝麻信用,蚂蚁花呗开始发力。花呗类似于信用卡,即先消费后付款。花呗的使用在2015年双十一期间极大的简化了支付流程,提高了系统的稳定性。因为正常的一次在线交易过程,最终都要调用银行侧的接口来完成实际的转账行为(消费者扣款,商家收款),个人认为这是系统性能的一大瓶颈,阿里再厉害,也不可能去优化银行侧的接口,它只能优化自己。花呗的使用,用户可以不立即付款,而是下个月再通过花呗还款。这样就把集中式的银行交易行为化为分散式,极大提高了性能。此外据说阿里还上线了扶老人险,这应该是其在互联网保险领域的一次试水。       腾讯自然也不怠慢,理财通是腾讯旗下剑指余额宝(其实更倾向于招财宝)的一款产品,2015年也搞得风生水起。另外微众银行也开创了互联网银行的先河。另外,谈到金融,交易自然是必不可少的一环。以前在线支付一直是腾讯的短板,但是近几年由于移动互联网时代的高潮迭起,微信支付依托微信迅速崛起,占领了大部分市场。当然这些在2015年都不是新闻,在这一年要着重一提的是,红包。包括微信红包和手Q红包。从除夕夜开始,红包在这一年取得了长足的发展。红包几乎成了每个节日必不可少的例行项目。除此之外,各种聚会也少不了红包助兴。我经常这样说:“阿里巴巴在**硬生生的造出了一个新的节日——购物节,而腾讯则把所有传统节日都变成了自己的节日。”什么是改变人民的生活习惯,我认为这些就是,这大概就是互联网行业的魅力所在。  

说到这,不得不把支付宝和微信再拿出来对比一下。最早两个产品是八杆子打不着的,可是微信自从做起了支付,就无形中在和支付宝竞争。2015年,支付宝数度改版越来越社交化,也越来越像微信。前段时间支付宝又斥巨资(2.8亿左右)成为春晚红包的官方合作伙伴。一个是社交工具做支付,另一个是支付工具做社交。个人认为前者比后者有更多的合理性。比如我们可以在微信群聊的时候,时不时的发个红包助兴。但是在支付宝里和你有支付关系的人之间发红包,很多时候是不合理的。比如那个人可能是某个商户老板,某个淘宝卖家等等。当然支付宝也在做朋友系统,不过我只能说朋友之间要转账就直接转账好了,干嘛在支付宝里发个红包呢?这只是个人的一点看法。       

2015年以前,如果你问我P2P是什么?我首先联想到的肯定是:电驴、BT种子已经各种小电影。但在2015年P2P我知道了新意——个人与个人之间的小额信贷交易。P2P行业是互联网金融领域中一块很大的蛋糕,在这一年的发展更是风生水起,除了各类P2P公司外,各种分期和众筹也是类似。不过这一年,值得深思的是,P2P公司在发展的同时也是乱象丛生。一年成立了三千多家。死掉了一千多家,各种欺诈,跑路事件层出不穷。该行业未来还需更多监管。总体来说在2015年P2P是毁誉参半了。       

不管是O2O,还是互联网金融我们都能看到一个现象——“发展倒逼改革”。互联网打车行业里的专车、顺风车在以前被定义为黑车都不为过,私家车拉客,还不算黑车吗。除此之外,互联网打车还触犯了很多公交公司,出租车公司的利益,他们叫嚷着这种打车服务使城市交通更加拥堵等等。然后国家开始一再监管,不过最后国家也开始出台政策使专车合法化,因为这已经是一种不可逆的趋势了,已经不能一棒子打死了(当然一棒子打死的东西也有很多,比如互联网彩票)。从互联网金融的发展历程来看,以余额宝为代表的互联网理财产品触犯了很多银行的利益,前几年还有叫停余额宝的呼声。但是政府也不能一棒打死了,因为那样完全是逆潮流而动。于是政府开始出台政策一方面加强互联网金融的监管,另一方面开始为这一行业的发展保驾护航。从而促进了互联网金融的更大发展。

-----------------------------------------------------------------------------------------    
好了,扯淡结束。欢迎拍砖。我说的不一定对。我觉得很多东西就是需要拿出来讲,拿出来辩的。每个人的观点都不一定正确,但是在交流过程中**、认知就能升华。所以我时常幻想在毕业以后,在深圳每个周末(或每个月)抽出一个下午时间,约出一两个或三五好友(陌生人也可以),找个快餐店或咖啡馆,去交流。除了程序员、除了互联网从业人员外,还可以是金融领域或其他行业从业者。“我有一碗酒,可以慰风尘。”


后记 2017-09-24

现在回想起来,当时我对行业的看法还是十分粗浅,从滴滴打车的成功中看到的不应该只是O2O,O2O的概念炒了很久了,早就不新鲜了,滴滴的成功并不是因为搭上了O2O的末班车。我们应该从中看到的是共享经济

此外从滴滴快的的合并,美团大众点评的合并中,看到O2O行业的重组和整合,除了意识到这些投资并购是资本的行为外,更重要的是通过O2O行业的重新洗牌导致了后来移动支付入口的重新洗牌,为微信支付后来的线下业务撕开了口子。
当然,现在我在一年多以后说这些,有点马后炮了。

Tweet

开一个Issue,拿来当微博用。。

为什么我说C/C++程序员都要阅读Redis源码之:通过Redis学习事件驱动设计

0. 为什么我说C/C++程序员都要阅读Redis源码

主要原因就是『简洁』。如果你用源码编译过Redis,你会发现十分轻快,一步到位。其他语言的开发者可能不会了解这种痛,作为C/C++程序员,如果你源码编译安装过Nginx/Grpc/Thrift/Boost等开源产品,你会发现有很多依赖,而依赖也有自己的依赖,十分苦恼。通常半天一天就耗进去了。由衷地羡慕 npm/maven/pip/composer/...这些包管理器。而Redis则给人惊喜,一行make了此残生。

除了安装过程简洁,代码也十分简洁。使用纯C语言编写,每个模块功能都划分的很清晰。

废话不多说,本文要介绍的是Redis里的事件处理功能,与Memcache引入libevent这一臃肿的事件库不同,Redis自己实现了一个小型轻量的事件驱动库——AE。阅读它的源码是一次非常好的学习和体验。

1. 跨平台兼容:重剑无锋,大巧不工

文件名说明ae.h/ae.c主要文件,根据OS平台的不同依赖以下不同文件:

文件 平台
ae_epoll.c Linux平台
ae_kqueue.c BSD平台
ae_evport.c Solaris平台
ae_select.c 其他Unix平台

虽然源码文件看起来不少,但是实际上ae_epoll.c、 ae_kqueue.c、 ae_evport.c、 ae_select.c 这4个文件的功能是完全一样的,提供一致的API接口,给ae.c文件调用。这是由于实现高性能的事件驱动的API(称之为polling API)不存在ANSI或POSIX的标准,不同的OS内核有着自己的实现。比如Linux内核的epoll,BSD内核中的kqueue。
ae.c中有:

#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
    #ifdef HAVE_EPOLL
    #include "ae_epoll.c"
    #else
        #ifdef HAVE_KQUEUE
        #include "ae_kqueue.c"
        #else
        #include "ae_select.c"
        #endif
    #endif
#endif

这些HAVE的宏,都是由在config.h中定义的。依据不同的操作系统,引入这4个文件中的某一个。
从功能上来说,这样设计的目的与GOF设计模式中“适配器模式”(修改成一致接口)或“外观模式”(抽象复杂接口为简单接口)的**类似,但实际上我个人感觉更类似于《POSA》(卷二)中提到的“包装门面模式”(Wrapper Facade)。Anyway,这个编程**值得学习。

注意,这里include的是.c文件,而非.h。也没有对应的 .h文件存在。也就是说这些源文件不会单独编译,而总是作为ae.c的一部分。

2. 用C++去设计,用C编码:aeEventLoop

十几年前,以Linux之父炮轰C++为开端,社区内展开了一场C与C++孰是孰非的论战。而在国内,以原CSDN总编刘江援引此文为始,把战火烧到了国内。孟岩云风pongba几位大佬都身陷其中。后来以孟岩的一句『用C设计,用C++编码』在国内为这场论战定下基调。

反观Redis,他是纯C编码,但是融入了面向对象的**。和上述观点截然相反,可谓是『用C++去设计,用C编码』。当然本文目的并非挑起语言之争,各种语言自有其利弊,开源项目的语言选择也主要是由于项目作者的个人经历和主观意愿。

定义在ae.h中的结构体 aeEventLoop 是AE库中最核心的数据结构,并且它采用了面向对象的设计**:ae.h 中声明了多个函数,其第一个参数都是一个aeEventLoop指针,用于操纵aeEventLoop结构体。
从这个角度来说,可以将该结构体理解为面向对象语言中的类,而操纵它的函数则可以视为其成员函数。(其实C++的class编译之后大概也是类似的模式)

函数 函数说明
aeCreateEventLoop 初始化一个事件循环结构体(eventLoop)aeGetSetSize返回当前setsize的值
aeResizeSetSize 改变setsize的值(空间重新分配)
aeDeleteEventLoop 删除事件循环eventLoop(释放内存空间)
aeStop 停止事件循环,即stop值设为1
aeProcessEvents 核心部分:事件处理逻辑
aeMain 启动事件循环,事件循环的入口
aeSetBeforeSleepProc 注册回调函数,即每次主循环在休眠之前被调用

函数 aeCreateEventLoop 和 aeDeleteEventLoop 可以视为“类”aeEventLoop的构造和析构函数。其他为成员函数。

调用流程
在客户程序调用AE库的时候,一般是依次调用:

  1. aeCreateEventLoop
  2. 给EventLoop注册文件事件or时间事件
  3. aeSetBeforeSleepProc
  4. aeMain
  5. aeDeleteEventLoop

2.1 AE的两种事件

事件处理,是有别于多线程/多进程的并发模型。我也都知道Redis是单线程的。它的性能主要依靠异步事件处理功能来实现。虽然事件处理通常和网络编程混作一谈,但其实事件处理本身不一定是为网络编程服务的,它主要是服务于IO,网络通信是IO,文件读写同样是。当然Unix中万物皆文件了,socket也是一种fd。
AE支持两种事件:

  1. 文件事件(IO)
  2. 时间事件(毫秒级)

这两种事件都作为aeEventLoop的结构体成员存在。
aeEventLoop各成员说明:

typedef struct aeEventLoop {
    int maxfd;                      /* 当前注册的最大fd */
    int setsize;                    /* 监视的fd的最大数量 */
    long long timeEventNextId;      /* 下一个时间事件的ID */
    time_t lastTime;                /* 上次时间事件处理时间 */
    aeFileEvent *events;            /* 已注册文件事件数组 */
    aeFiredEvent *fired;            /* 就绪的文件事件数组 */
    aeTimeEvent *timeEventHead;     /* 时间事件链表的头 */
    int stop;                       /* 是否停止(0:否;1:是)*/
    void *apidata;                  /* 各平台polling API所需的特定数据 */
    aeBeforeSleepProc *beforesleep; /* 事件循环休眠开始的处理函数 */
    aeBeforeSleepProc *aftersleep;  /* 事件循环休眠结束的处理函数 */
} aeEventLoop;

文件事件,主要依靠两个数组。一个是注册的文件事件数组,一个是已就绪的文件事件数组。

typedef struct aeFileEvent {
    int mask; /* one of AE_(READABLE|WRITABLE|BARRIER) */
    aeFileProc *rfileProc;
    aeFileProc *wfileProc;
    void *clientData;
} aeFileEvent;

typedef struct aeFiredEvent {
    int fd;
    int mask;
} aeFiredEvent;

单词Fired在这里表示的是就绪的意思

每个文件事件,其读写设置了不同的处理函数。另外mask表示事件的触发类型。当每次polling API返回就绪之后(比如epoll_wait返回),就绪会被设置到aeFireEvent,然后反查aeFileEvent获得处理函数并处理。你会发现aeFileEvent结构体里并没有记录fd。其实这是使用了HASH策略,aeEventLoop的成员 aeFileEvent数组的下标即是fd,便于快速查找。

时间事件,本质就是定时器任务,其数据结构采用一个双向链表。链表每个结点为aeTimeEvent结构体,主要包含事件的ID(递增)、就绪的时间,处理函数、清理函数、客户数据。

typedef struct aeTimeEvent {
    long long id; /* time event identifier. */
    long when_sec; /* seconds */
    long when_ms; /* milliseconds */
    aeTimeProc *timeProc;
    aeEventFinalizerProc *finalizerProc;
    void *clientData;
    struct aeTimeEvent *prev;
    struct aeTimeEvent *next;
} aeTimeEvent;

每个事件循环中,每个时间事件的ID唯一且递增,主要依赖aeEventLoop里的timeEventNextId来维护这个ID的递增关系。创建新的时间事件时(aeCreateTimeEvent)会赋值,由于只考虑了单线程,所以没有加锁逻辑,大家也不要贸然把AE用在多线程环境中。

when_sec和 when_ms 记录了时间事件的就绪时间(秒+毫秒),即当当前时间大于等于这个时间的时候,该时间事件应被处理。

时间事件的处理过程(processTimeEvents)主要就是:继续遍历链表,如果发现节点状态为AE_DELETED_EVENT_ID则删除该节点。如果判断当前时间已经超过节点的就绪时间就开始处理。处理函数的返回值可以指定,后续不再处理该事件(NOMORE),则该节点会被置为AE_DELETED_EVENT_ID。如果下次还需要处理,则更新该节点的时间为下次就绪时间。

2.2 事件循环的处理逻辑

再用一张图,回顾一下EventLoop中的两种事件,基本可以做如下理解。一个链表,一个数组。文件事件中的数组不是线性填满的,因为是采用的HASH策略,将fd作为数组下标了。

image

aeProcessEvents 是aeEventLoop在循环过程中的的实际处理逻辑。函数原型如下:

int aeProcessEvents(aeEventLoop *eventLoop, int flags);

flags标记,表示本次需要处理的事件类型标记和是否阻塞标记。

标记位 含义
AE_TIME_EVENTS 时间事件标记
AE_FILE_EVENTS 文件事件标记
AE_DONT_WAIT 立即返回不阻塞等待的标记

aeProcessEvents 具体实现代码我就不贴了。它巧妙的地方是一次柔和了文件和时间事件的两种处理过程。在函数之初,会查找时间事件的链表,找到最近就绪时间事件,然后用它的就绪时间减去当前时间的时间差作为 polling API 的休眠时间(epoll_wait的timeout参数)。然后休眠等待polling api返回。在返回之后先执行aftersleep的的处理逻辑,然后执行这段休眠时间内就绪的文件事件,最后再处理就绪的时间事件。返回值是处理过的事件总数。

也就说AE会尽量在一次处理过程中,将时间事件和文件事件一次性处理。你也许会问如果没有时间事件怎么办。当然没关系,在aeProcessEvents开始部分就根据标记位进行了判断。上面的逻辑是在文件事件和时间事件都存在的情况下,如果仅存在文件事件,则看是否设置了不阻塞的标记(AE_DONT_WAIT),若有,则polling 的超时时间设置为0。如无,即可以阻塞,则设置为-1,则polling API会阻塞直到有文件事件发生。

3. ae_epoll(Linux上epoll的封装)

前文说道Redis适配各种Unix-like的操作系统。它将内核强相关的事件API(polling API)部分单独抽出来,包装出了相同的接口给AE的对外API调用。在Linux系统上的API实现为:ae_epoll.c,建议在阅读这个文件源码之前先好好回顾一下epoll的API,这样更助于快速理解。相信工作后大家写业务逻辑,应该很少接触epoll了。可以阅读这个wik,快速回顾epoll的api:LinuxAPI:epoll
ae_epoll.c 完全被 ae.c调用。各函数调用关系如下(aeApi开头的都是ae_epoll.c中的函数):
ae.c

  • aeCreateEventLoop
    • aeApiCreate
  • aeResizeSetSize
    • aeApiResize
  • aeDeleteEventLoop
    • aeApiFree
  • aeCreateFileEvent
    • aeApiAddEvent
  • aeDeleteFileEvent
    • aeApiDelEvent
  • aeProcessEvent
    • aeApiPoll
  • aeGetApiName
    • aeApiName

除了aeApiName()以外,其他函数第一个参数也都是aeEventLoop * 。用面向对象的**来看这也是aeEventLoop的成员函数。试想若是C++,则可能会被处理成父子两个类,而aeApi系列的函数是纯虚的。
aeApi的函数也是可以做到顾名即可思义。比如:

  • aeApiCreate在堆上进行内存的分配,封装epoll_create创建epfd,并写入aeEventLoop。
  • aeApiAddEvent、aeApiDelEvent是封装的epoll_ctl来对aeEventLoop的监控的epoll事件进行添加和删除。
  • aeApiPoll是封装的epoll_wait开启事件循环,并且每次取出就绪的fd存入aeEventLoop的fired数组中,并置位相应的mask(读or写)
  • aeApiResize、aeApiFree分别进行的是内存的重分配、资源的清理(关闭epfd,free内存)和epoll本身关联不大。

4.Jim:吃水不忘挖井人,AE的灵感之源

阅读完AE代码,可能只需要一下午的时间,你会惊叹于作者的设计功力。其实里面也没有太多花哨的东西,但就是如此简洁清晰的给你呈现了一个完成度如此之高的事件驱动处理库。但我想即使大家都熟悉epoll、熟悉kqueue、熟悉数据结构也不一定能设计出来AE,所以把程序员比作代码的设计师、建筑师是丝毫不为过的。

“吃水不忘挖井人”,AE的设计灵感也是受另外一个开源项目影响,它就是 Jim。Redis的ae.c的开篇注释中就已注明:

/* A simple event-driven programming library. Originally I wrote this code
 * for the Jim's event-loop (Jim is a Tcl interpreter) but later translated
 * it in form of a library for easy reuse.

Jim的源码在Github上有它的镜像,其中事件循环的代码在此:https://github.com/msteveb/jimtcl/blob/master/jim-eventloop.c

简单阅读一下,你就会发现AE确实整体的处理逻辑是从Jim吸收的。但AE也不乏创新,比如抽象除polling API这层,达到了多平台的兼容和解耦,而Jim强耦合了select。

Anyway,就像经典的『站在巨人肩膀』理论,虽然Jim不是巨人,但它启发了AE,即使Jim最终被世人遗忘,而它的血肉也化作了土壤,滋养后来人,这就是开源运动的意义所在,也是魅力所在。学习的本质,其实就是模仿,然后改进,这不是抄袭,这是传承。

5. 题外话

另外不止AE中,整个Redis在使用堆内存的时候,都是使用它自己实现的zmalloc,而非libc的malloc。有兴趣可以阅读:
https://blog.csdn.net/guodongxiaren/article/details/44747719

《这就是搜索引擎》读书笔记:网页作弊

要首先牢牢记住:作弊的目的是出于商业利益驱使!
即在做不正当的营销。

主要作弊类型

1. 内容作弊

  1. 增加目标作弊词的词频
    i. 页面隐藏元素增加大量词表(css隐藏、alt、meta)
    ii. 页面内容中大量使用
  2. 增加主题无关的热门query词引流
    i. 主题无关热门词加到标题(主要是主题无关,主题相关是蹭热度,不算作弊)
    ii. 页面隐藏元素增加主题无关词(方式同a.i)
  3. 关键位置插入作弊词
    i. <b> <h> <strong> 等也是搜索引擎重要的排序依据

2. 链接作弊

  1. 链接农场(Link Farm):构建大量相互链接的网页集合
  2. 锚文字诱导。标签的文字和链接无关,文字是主题相关,但链接无关(出现过Google轰炸)。
  3. 交换友链/购买链接 让高排名网站指向自己。(正常网站也会做)
  4. 购买过期域名。高排名的旧域名,指向自己
  5. 门页(Doorway Pages)作弊:
    i. 门页即hao123类型的聚合导航页。构造这种网页,实际链接指向同一个网站(色情网站经常这样做)

3. 页面隐藏作弊

  1. 隐形作弊:通过失败搜索引擎爬虫的IP和User-Agent,来针对性的返回伪造页面(用户正常检索不会触发),伪造页面可能质量很高,而用户看到的页面往往是营销页面。
    i. IP地址隐形作弊(IP Cloaking )
    ii. User Agent隐形作弊(User Agent Cloaking)
  2. 网页重定向:让搜索引擎收录一个页面,用户点击被重定向到新页面

4. Web2.0作弊方法

  1. 博客作弊:
    i. 作弊博客(Splog):类似写软文的思路,不过博文目的是嵌入链接。增加目标页面(作弊页面)的排名
    ii. 博客评论作弊
    iii. TraceBack作弊:TraceBack为博文作者互相通知协议。作弊者通过引用高热度的博文来触发TraceBack(如果原作者博客支持该协议,会在原文增加引用者博文的链接)
  2. 点评作弊:类似大众点评的评论中,加入其他网站链接
  3. 标签作弊:某些网站支持标签,比如博客标签,图片、视频分享的标签,在标签中加入推广内容来导流
  4. SNS作弊:在SNS网站建立虚假账号,用色情等信息来吸引点击,诱导分享
  5. 微博作弊:微博、推特都存在互粉行为,通过大量关注他人来获取互粉,在粉丝足够的时候,开始发布营销信息。

小结

内容作弊和链接作弊,主要是针对搜索引擎的算法来操作的。
搜索引擎两个重要排序依据:

  1. 内容质量
  2. 链接分析

也可以通俗的理解为:

  • 一种是想尽办法(作弊的方式)增加营销页面中被搜索引擎所关心的内容。
  • 另一种是用尽办法从其他地方通过链接来给自己的营销页面导流。

貌似后者比较常见,花样也比较多。

TBB:quick start

TBB

Intel 开源的C++并行计算库:Threading Building Blocks

同类产品:

  • PPL:微软开源:Parallel Pattern Library
  • OpenMp:老牌的并行计算库

brpc安装

github主页:

https://github.com/apache/incubator-brpc

克隆:

git clone https://github.com/apache/incubator-brpc.git

本地依赖

cmake

其中一个gflags需要cmake3,所以要安装cmake3:

yum install cmake3

依赖第三方库

  • gflags
  • leveldb
  • protobuf【2或3均可】
  • openssl

其中gflags、leveldb默认cmake会编译成静态库,编译brpc时会出错:

/usr/local/lib/libgflags.a(gflags.cc.o): relocation R_X86_64_32S against `.rodata' can not be used

需要编译成动态库,编译方法如下:

mkdir bld
cd bld
cmake3 -DBUILD_SHARED_LIBS=ON ..
make -j 8

编译brpc

在确认安装好上述依赖后,cd到brpc的下载目录中。

mkdir bld
cd bld
cmake3 ..
make

编译brpc尽量不要并行make。容易编译失败

编译example

example下面的的代码用cmake编译,可能会失败。最好用普通make编译的方式。

首先要先生成config.mk:

sh config_brpc.sh --headers=/usr/local/include  --libs=/usr/local/lib

headers和libs指定第三方库的头文件和库路径。尽量集中到一起,不在一起的可以建立软连接。

生成config.mk之后,可以去example目录编译。比如:

cd example/echo_c++
make

大四这一年

0x00

“吃完饭,去外面散散步吧。”

说话人是HomKai,与我同在腾讯实习。

2015年,深圳八月的傍晚。

腾讯大厦周边的马路上,行走着两个男人,一胖一瘦。

路边有零星几个商贩,叫卖着熟玉米、茶叶蛋等小吃。

“你说,咱们如果不会敲代码的话,现在会不会和他们一样啊?”HomKai又开口了。

“这……说不好,或许吧”

我不好回答,想来如果假设成立,即便我们不是在路边摆摊,也会是从事其他劳力的工作。

HomKai与我是老乡,同届,同在南昌读大学,同是程序员。不同的是我是后台,他是前端。另外一个共同之处就是我们的父母都是北方土生土长的农民。

想到这里,HomKai刚才的假设便不足为奇了。

我们继续走着。夕阳如血,两个外乡人的背影消失在深圳的钢筋水泥之中。

0x01

“大四的同学都赶快回来上课,不然期末挂科,后果自负”

九月下旬,某个工作日的午休时刻。

辅导员在计算机系的大群里吼着。没错,我们大四上学期还有课。

班里的同学也在盛传XX老师每节课都点到,而老师只能容忍三次缺勤,超过这三次,直接挂科。而这周就是上第三次课了。

对于学校的种种制度我有力吐槽却无力改变

无疑,返校该提上日程。

难熬的八月过去了,在焦虑与紧张的情绪中,经历了实习生留用的考核。

彼时,大厂缩招、阿里拥抱变化等消息搅动了整个秋招市场。互联网就业寒冬的说法不绝于耳。

天气转凉,毕业生们的心也随着天气一起变凉了。

这个月初,HR通知留用,心情放松许久。

回首一路,自己无疑是幸运的。

有人说找工作也要靠运气,虽有一定道理,却不敢苟同。我的说法是:找工作也要看缘分。

0x02

南昌,十月。

“回来了?后天有科目三考试,两点半过来练车!”

科目三教练突然电话催练车。

遥想六月初,考过一次科目三,很不幸,挂掉了。此后心里一直耿耿于怀。

如果说大学是我们从学校到社会的过渡阶段的话,那么驾校无疑页是进入社会前的一次小规模演习了。

从科目二到科目三,从教练到学员身上体会了各式各样的社会习气。

今年三月,科目二练车,中午,一辆车,四个人。

“四个人,今天还有没来的,但是下周科目二考试只有三个名额,所以现在就是你们努力的时候了,谁练得好就谁就去考。”教练在车外趴着车窗抽着烟说道。

下午,厕所。

一个男人提着裤子正要走出来,被我硬挤了进去。

一包烟塞到教练兜里。

“不能要,不能要。”

“拿着,拿着。”

这已经是第二次送烟了,一周以前也送过一次。对于这些社会规则我并不熟练,我知道自己还很笨拙。
此后的几天,同车的几个女生把各种驾车技巧练的很熟,教练依旧骂我练得不行。

一周之后,我参加了科目二的考试。而那些女生却只有一个参加考试。幸运的是,那天我一次通过了科目二。

先烧香,后拜佛。

科目三的佛不仅是教练,还有考场上同车的安全员。

两天之后,第二次考科目三的我,配上天时地利人和,终于通过。

  • 何为天时,上路考试时没有遇到上下班高峰。
  • 何为地利,路上没有遇到突发的车辆和行人。
  • 何为人和,安全员没有故意一脚刹车踩挂我。

0x03

双十一,凌晨。

买了一部iphone 6s。这部手机距离发布仅过去两个月,但是这次优惠实在太多。我用实习工资剩的钱买了一部。

其实这是我第一次用iphone。或许是因为实在受不了低端的安卓机了,或许仅仅是因为虚荣。

几天之后,我收到了手机。然而第二天,我又收到了一部同型号的手机,让我很是惊奇。我意识到他们出了问题。

我和客服反映多收到一部手机的事,起初她还不信,回复慢得出奇,总以为我在拿她消遣。后面她终于相信了我说的话。

这家店是天猫苏宁,苏宁在全国各大城市都有实体店。我让他们赶紧来人取,但他们动作依旧很慢,让我等了好几天。

“再不来人,我可就卖了啊!”我不耐烦地和客服说道。

“谢谢你,同学,太感谢你了”,几天之后一个送货员过来取手机,“这几天双十一送货实在太忙了,过了这段,我请你吃个饭,交个朋友。”

“不用了,不用了,太麻烦了。”

“没事没事,要不这样,这个好人好事,我们肯定会向你们学校反映的。”说完,他加了我微信。

意识到自己很快就会登上校内各种黑板报,突然好紧张,但又有点兴奋。两个月后,我意识到自己想多了。并没有什么鲜花和掌声,显然,送货员并没有信守承诺,都是套路。

如今他依旧在我微信里,但我并没和他多说什么。

拾金不昧,是对抗自己的贪婪,而若执意去让别人表彰自己,难道不是另一种贪婪么?

想到这里,觉得自己有点可笑,变得假仁假义了。实际上可能是被道德绑架了吧。

我的蚂蚁花呗只有三千额度,这让我不住感叹:数据挖掘和各类征信评分算法再先进,也始终算不透人心。

0x04

实习期间,发现自己存在很多技术短板,同时也对一些新的未知产生了兴趣,于是我制定了满满的学习计划。回校之后,空闲时间较多,便开始践行这些计划。当然到最后没能全部完成它们,但那又有什么关系呢?

取乎其上,得乎其中;取乎其中,得乎其下;取乎其下,则无所得矣。

虽然C++码农,但是实习的时候遇到了一些前端的需求,这让我意识到固步自封是危险的。所以我满满的学习计划中有学习前端这一项,虽然到目前前端水平还极其有限,但是至少不再是前端白痴了。

罗辑思维的罗胖有个习惯,每天六点坚持发布一段60秒的音频。看似是一件微不足道的事,但是能持续的,不间断的坚持三年着实令人佩服。用他的话说叫做死磕

虽然罗胖的某些观点我不敢苟同,但我还是爱听他节目的。忽然某一天,我对自己说:“我能不能也试着死磕一件事呢?”

我选择读书。读技术书籍,读经典书籍。

《Effective C++》系列三部曲是所有C++码农必读的经典。我一直都有这三本书的电子版,但总是零零散散的阅读过某些章节,从未细致,完整的阅读过。大学期间,我读的很多书籍都有这个毛病,虽然读的书也不少,但是真正完整读完的书籍并不多。

每天只读一个小节,这是我给自己定下的死磕目标。一个小节少则七八页,多则二十页。其实并不多,每天花费的时间极少。因为我不想给自己造成压力,制定太高的目标,可能坚持一两天还行,难以长久坚持。

在图书馆找到了纸质书,每天读一小节,就在目录上用荧光笔标记一下。

小目标,逐渐变得不像目标了,而是像吃饭喝水一样。

那三本书读完后,我又从图书馆找了新的书籍继续死磕计划。今年六月份,死磕完了五本书。虽然读的很慢,但是心里毫无负担,这才得以坚持。

0x05

十一月,天气渐凉。

双十一过后两天,我大病一场,可能是因为换季,也可能是其他原因。

我决定开始跑步。忘记了具体的动因,可能是因为健康,也或许是想减减肥找个妹子了。

从此,晚上九点左右的操场,多了一个胖子。

大学期间,我不是没有试着跑步过,但最终都没能坚持下来。

计步软件、体重秤、有声书,一个都不能少。

我曾误以为我需要跑的很快才能达到减肥的目的,现在在明白慢跑才减肥。

快跑是无氧运动,慢跑是有氧运动。

跑步前三十分钟主要消耗糖,此后开始大量消耗脂肪。有氧运动可持续时间长。

三圈、五圈、八圈……。圈数这样增加着。跑步最终也成了死磕,除非天气太差,否则都会坚持。

我喜欢在跑步的时候听书,这是一种转移注意力的方法,也是一种解闷的方法。

当跑步时间越来越久,会发现慢跑并不会让自己很累,但会让人无聊。

2016年五一,我听完了《盗墓笔记》。

彼时,我体重下降了二十斤。

可以买到更多合身的衣服,也不再害怕拍照了。这是我首先体会到的变化。尽管我的内心依旧是一个胖子。

0x06

毕业设计,做的指导老师的题目。大概今年四月份的时候我开始做毕设了。

你知道的,本科生嘛,毕设的技术要求极为有限,基本上就是做信息管理系统了,当然我们导师也不例外。

老实说,我的工作是Linux上的C++开发,此前并没仔细学过WEB开发。

语言、框架都任意。面对毕设的要求,我选择了PHP以及Yii2框架,之所以选择它们,并不是因为我熟,相反是因为不熟。既然做毕设肯定要花时间,不如趁此机会学点新东西也好。

我并不会Yii2框架,甚至PHP都不熟。但是本着学习新知识的态度,我决定使用他们,哈哈,主要是由于PHP比较简单啦。三个字:糙、快、猛。

PHP做本科毕设也是不必使用框架的,直接裸写出来肯定更简单。毕设答辩,答辩老师们只关心它的界面,它的效果,业务功能是否健全。显然,他们并不在意你用了什么后台技术。

但这并没有关系,我通过学习Yii2框架,学到了一个WEB框架应该具备的技术和功能,这对我来说很重要,远比记忆这个框架的API要更为重要。日后我学习其他框架,即使不是PHP的,都没有太大关系了。

PHP的框架有很多,起初在选择框架的时候我并没有花太多功夫,因为我不想把太多时间浪费在选择上,毕竟这只是一个毕设。在学习使用Yii2框架的时候,发现了它的优点,当然也有槽点。

见过一些网友想学习编程,却花了过多的时间在选择语言和选择框架上。

0x07

“各位嘉宾都准备一句话吧,等到上台的时候,先在台上说一句话,然后再入座,这样不会显得很突兀。”工作人员对我们说着。

五月二十六日,南昌大学游泳馆报告厅,2016届优秀毕业生经验交流会。邀请了来自考研、保研、创业、就业、留学以及考公务员的八个学生代表作为嘉宾。

“大家好,我原来是一名诗人,现在是一名程序员。”因为我和一个诗人同名,所以就用了一个小幽默这样开场了。记不清楚这是我第几次玩这个姓名梗了。

两周之前,我也应邀参加过一次暑期实习经验的分享会。那次是PPT形式的分享。那是我第一次上台,显然比这次要紧张。语速稍快,导致有些喘不过气来,数度停顿对着话筒吹气。不过慢慢地我开始适应,逐渐变的自然流利。加上一些小幽默,最后得到了不错的掌声。

唯一失望的是那并不是我自己学院举办的活动。

这次的毕业交流会,并不能说明我们就是这一届最优秀的,因为这个一个自愿报名参加的活动,而很多比我们优秀的学生并没有兴趣上台。

我也不擅长上台,尽管这是一个座谈会,但准备的时候还是难免焦虑。

之所以要站出来有两个原因。首先,大学期间,我对于这种抛头露面的活动逃避了太多了,导致自己在上台讲话方面严重不足,这可能会限制我未来的发展。其次,我真的很想给学弟学妹们介绍一些经验,让他们少走弯路,如果真能启发一些人,帮助一些人,那真是太好不过了。

我用手为你指路,希望你看的的是路,而不是我的手。

大一的时候,我读到这句话。那是某校一位已毕业的学长写长文分享经验。当我最后读到那句话的时候,瞬间对这位学长心生敬意。

我想成为那样的学长,对着学弟学妹们侃侃而谈。其实在内心里,我已经导演过很多次类似场景了。

很多人可能和我一样害怕上台,害怕被聚焦,害怕看到台下那么多人的目光。

其实真正在台上,会发现,虽然人很多,但是正是太多了,所以你看不清每个人的脸,看不清他们是满意还是失望的表情。看不清的话,就当作没有观众就好了。看不清的话,就当作所有观众都很满意地认真听讲好了。

“最后请嘉宾们都站到台前,最后一句话,寄语学弟学妹。”主持人如是说着。

“学弟学妹们,大学期间一定要找到自己的定位,找到自己的方向。一句话:选择比努力更重要。”

恍惚中,感觉自己大学四年的努力,或许都是为了这一天吧,获得别人的认可和掌声。也不清楚自己究竟是为了自己而努力,还是为了别人而努力。

总之,这一页翻过去了,所有前尘旧事的因因果果都已经不重要了。翻开下一页,明天会更好。

0x08

"学长,你是一个好人。"

0x09

“没有接收函的同学,尽快在档案回原籍的确认书上签字。”

辅导员又在计算机系的大群里发布了一则消息。

如果毕业前没有拿到接收函,那么档案就只能回原籍。彼时,已经是五月底了,距离毕业不到一个月。
接收函有两种,公司的和政府人事局的。然而只有国企才有能力接收和保存档案,其他企业不可以。显然腾讯不是国企,因此我需要深圳人事局的接收函。

可惜我没有。

当我赶紧向公司申请办理人事局接收函时,被告知人事局需要一个多月才能受理。我肯定是等不到那时候了。

深圳人事局的接收函办理制度:原则上需要毕业生提供双证:毕业证和学位证。然而不到毕业,我肯定是没有这两个证的。

南昌大学的档案管理制度:在学生毕业前即将档案派遣到相应接收单位:生源地、工作单位或者工作单位所在城市的人事局。我们学校在学生毕业后不再保管档案,一个月都不保留。另外无档案缓寄的制度。

显然两者有不可调和的矛盾。当然不同政府的做法是不同的,不同学校的做法也是不同的。

我的档案最终被派回原籍了。

档案有多重要起初我不了解,接收函和报到证具体有什么作用,长久以来我也不很清楚,学校此前也没跟我们贯彻,突然发难,实在让人措手不及。

落户深圳,档案需要和户口一起走,即是说我的档案应该转移到深圳人事局。如果这步不能完成,则无法落户。

档案回原籍之后,如果我想继续完成这步,需要这样:

  1. 拿到双证之后去公司入职,公司去申请深圳人事局的接收函。耗时一个多月。
  2. 拿到接收函后回学校办理改派手续,由学校批量将改派申请提交到省就业办。
  3. 回学校领取就业办的改派材料。
  4. 回原籍,去办理实际改派手续,当地人事局签署意见。办理新的报到证。
  5. 最后拿着新的报到证去深圳人事局报道,档案转移到深圳。

我家在河北,大学在江西,工作在深圳。显然这么多道手续办下来,真够我折腾的,并且要请不少的假。
但如果不落户深圳的话,这些手续都不需要办了。我开始质疑自己落户深圳的必要性。又开始纠结是否要为了落户而这样来回奔波。

慢慢地我的思绪上升到我以后要在哪个城市发展,哪个城市户口含金量高,如果今后想落户北京具体我要奋斗多少年才能落户,我的未来在哪里。于是我意识到:

我想多了。

初入社会,发现了更多自己无力改变的东西,体会到了更多只能被动接受的东西。曾经的不可一世最终都变成不自量力。

月色皎洁,寝室此时只剩我一人。望着窗外,曾经坚毅又充满热情的眼神变得混沌,才理清头绪,却又陷入深深的迷茫……

写过无数次的 Hello World,却找不到我的世界在哪里。
用过无数次的面向对象,却仍然孤身一人。
调过无数次的BUG,却始终解不开生活中的BUG。

写给立志做码农的大学生

**声明 **
注意本文标题是“写给立志做码农的大学生”而非“写给计算机专业的大学生”。所以并不是教计算机专业学生都要走码农这条路,因此不一定适用于对编程不感兴趣的同学。同样,如果是其他专业的同学,想走码农这条路也是欢迎阅读本文的。但碍于笔者自身兴趣、见识、阅历以及专业背景的局限,所以文中观点肯定并非完全正确或适合大家,大家阅读的时候需要自行选择性吸收对自己有用的部分,切不可照单全收。所谓知识虽然通常从别处获得,但是仍需要自己挑拣和消化的

先简单介绍一下我自己,我是一所普通大学的本科生,大学录取时的专业是电子系的,大一的时候意识到自己喜欢敲代码后,就提交了转专业申请。大二起开始在计算机系学习。大三时(2015年4月)拿到了腾讯暑期实习的offer,实习结束后获得留用offer,大四没跑秋招,几乎就在学校浪荡了一年。

我不是大牛,不是来传播鸡汤或成功学的,只是最近有感于学弟学妹们在学习以及规划方面严重不足,觉得这是一个共性问题,加上我好为人师的性格,遂捉起纸笔,写点东西。

1. 确定方向

1.1 选择比努力更重要

关于方向的选择其实越早确定越好,生活中我们要面临无数个选择,前几天看了一个美剧《Mr. Robot》,其中有句台词说的不错:

life is binary

生活就是二进制,一个个0101组成的。每一次抉择,选了就是1,不选就是0。大家可能也听过另外一句话:

“人一生要面临很多选择,但是真正能决定你命运的只有几个”。

没错其实就是这样。如果你是计算机专业的学生,那么到底是考研还是就业就是首先要面临的选择。本文是面向想就业的大学生的,所以关于这个抉择,不再赘述。
就业的话,本文标题是码农,实际是指所有计算机相关的技术工种。

很多选择本身并没有对错或优劣,只有适合不适合

不要滥用勤能补拙,这个词语一度被很多人奉为圭臬,但同时也成了枷锁。我相信这个词语,但是要考虑现状,要考虑投资回报率。你在自己并不擅长或不感兴趣的领域深耕了四年,最后不一定能获得多少成绩。当然如果你能在毕业后继续深耕几年或许是可以的,但是我希望每一位大学生在毕业的时候都能有一份好的工作,并且如果你并不喜欢某一领域的话,那么我相信你也不会长久坚持下去。所以我们一定要找到适合自己的方向!

那么如何发现自己对什么感兴趣呢?我也不知道很好的办法,我只知道一个朴素的方法——尝试。趁着年轻,就要多尝试。千万不要大三了都还不知道自己兴趣在哪,想做什么,适合什么。所以大一大二努力去碰钉子吧。

1.2 算法还是开发

数据结构和算法很重要,无论是面试还是工作,无论你从事哪方面的技术。不过算法虽然重要,但并不适合每个人都花费大学全部的精力去钻研
相信很多学校都有ACM竞赛相关的社团或组织。很不幸,我们学校没有,我大一的时候也花了很多精力刷题,但是硬件条件不太允许,氛围太缺乏,遂放弃。如果你觉得自己能够在ACM比赛中游刃有余,那么恭喜你,你可以一心一意搞算法。如果你觉得自己在这个过程中十分吃力,挫败感频生,那么也不要气馁,或许有另一条路是属于你的。选择开发,有深厚算法功底是很棒的事,但是仅仅只有算法同样是不够的,计算机海洋还有很多未知等着你探索。

算法岗包括数据挖掘、机器学习之类的(怎么样,高大上吧,反正我不懂)。要说明的是想做算法的同学最好选择读研继续深造,因为大企业在算法岗的招聘上对本科生是很不友好的。还是要声明一句,你做开发也不能忽视算法和数据结构,起码面试还是经常考的!记住一句:

算法功底好的人,运气都不会差。

对于本科生而言做开发还是相对容易的一条道路,不过开发的技术路线也是不胜枚举:前端、后台(PHP后台、Java后台等等)、移动端(安卓和IOS)、游戏开发、数据库(比如做DBA)……。这里我肯定不会去推荐你去学哪一种,我没有能力也不适合。只有你自己才能发现自己的兴趣以及好奇心之所在。

我能做的只是在浩如烟海的技术观点中,帮一个个本科生排疑解惑。

1.3 认识技术

关于技术,很多本科生都存在诸多误区。初学者总喜欢追随牛逼的技术,实在过于盲目,找准自己的定位最重要。

误区1: 图形化的东西比非图形化东西更牛逼

多见于初学者,尤其是计算机专业新生(我大一的时候就是)。当时学校教了点C语言,一直都是控制台程序,面对黑窗口,我就各种百度看看怎么弄出图形化的东西,那时候才知道GUI这个缩写是啥意思(当初知道这个缩写的全称还小激动了一下下,果然我还是太年轻了),然后知道了WIN32、MFC这些名词。确实只能说是知道名词。当时对着视频教程做了计算器,就是用VC++拖拖控件,视频里的人敲一句代码,我就敲一句。后面虽然弄出来了,但是感觉自己什么都不懂,只是依样画葫芦。这时我才意识到,还有很多基础没有打劳。

八卦一下,现在桌面客户端的开发工作并不多,所以大家谨慎选择这一技术方向。桌面端GUI技术一度火爆(MFC、Qt、WinForm、WPF、Swing……),但如今早已是互联网及移动互联网时代。所以大家真的要慎重选择。不过还是可以学习一下的,至少能加深你对编程语言以及设计模式的理解。

误区2:非图形化的东西比图形化的东西更牛逼

具体而言就比如说:后台技术比前端技术、客户端(Android、IOS)更牛逼。多见于有Linux背景的人(没错,说的就是我=_=|||)。

我也一度这样认为,其实不然。这里和上一个误区一起澄清一下:技术本身没有高低优劣之分,只是程序员对其有好恶之别

另外要说明一下,不能说前端就简单,后台就更难,同样反过来说也不对。我只能说这完全是不同层面的东西,不能量化的去比较。

前后端都自有其痛点、难点以及G点

不能说你能处理后端复杂的并发、同步、高可用,那么你就能轻松地完成美观的网页及特效、处理麻烦的浏览器兼容、极尽所能地降低页面的加载速度。举个不恰当的比喻:同样是一双按在键盘上的手,那么钢琴家演奏优美的乐曲和程序员开发高性能的软件,哪个更困难?

误区3:XXX是最美的语言/框架/平台/……

多见于PHP程序员。哈哈,开个玩笑。这里不是在谈论谁是最好的语言,而是告诉大学生朋友们不要迷信论断。不要盲目跟风,追新,找到适合自己的最重要。

我大一的时候去图书馆看书,看到有Java Web的书,前言写的很清楚,痛陈了PHP和ASP.NET的缺点,阐述Java是多么优秀,OK。你可能也和我一样,在入门的时候经历过类似的事。我要告诉你的是,多翻几本书,你会看到ASP.NET和PHP书籍的前言写的同样精彩,你绝不会在ASP.NET的书里看到夸耀Java的句子。不同的技术自有其优劣,千万不要成为前言驱动的学习者

继续八卦一下,虽然说不同技术自有其优劣,但是就目前国内形势来看,学习Java绝对是不错的投资,Java后台几乎占据了**互联网企业后台的半壁江山。而.NET技术确实日薄西山。不过PHP现在依然有很顽强的生命力。(其实我是C++狗)

另外还有一些经典论断:

  • LAMP架构只适合中小企业;
  • MySQL只能用于中小企业,大企业都用Oracle。等等。

这些论断从技术角度出发,确实无可非议,但却并不客观。见过一些朋友,只看的上Oracle,对MySQL充满鄙夷,觉得MySQL很容易出现瓶颈之类的。其实我想说,阿里、腾讯都大量使用了MySQL。别问我为啥MySQL被这么大体量的公司采用(无外乎开源的好处和历史原因啦),我觉得,只要技术够屌,什么瓶颈都能克服。。


2. 学习那点事

2.1 关于逃课

相信每一个大学生都逃过课,我也不例外,而且很多。我在谈逃课,其实也是从某个侧面来谈自学。之前有个网友和我咨询如何面试,如何准备之类的。他已经大三了,学校的课程完成的不错。但我感觉他还欠缺很多。要想找到好工作只靠老师教你那些东西是不够的,跟着学校的进度走,其实只会让你落后。我并非一味的鼓励大学生逃课,我的观点是要选择性的逃课(如果是好课那么即使不开课也要去蹭课的)。哪些课要逃呢?

  1. 无聊的课程。比如思修、毛概、马原统统要逃。别急着反驳我,只是谈逃课而已,不要形而上。数学相关的课程,我只想说量力而行,数学确实对于程序员来说还算重要,但是不同岗位对数学的要求又不尽相同,你能应付就好好听,不能应付就。。
  2. 与你的技术方向无关。这个就要看你是不是计算机专业了,如果你是其他专业学生,但是对计算机感兴趣,相信很多课都是可以逃的了。或者比如你的技术栈是建立在Linux基础上的,但是学校有一门MFC编程的课,你有兴趣又有时间可以听听,没时间就逃,OK的。这个也是有个前提的,就是你能清楚的明白哪些课程是对你有帮助的。你说:“我学C++的,我把数据库的课逃了”。=_=||别说你读了我的文字。。
  3. 你已经掌握了的。相信会自学的孩子,都有这种情况:在学校开课前,你就自学过了某门课程。那么等到开课以后你就可以逃了,我就是这样逃了Linux编程的课。当然你要清楚的了解自己到底掌握了多少,不要一知半解,还自以为懂了,就不听课了。其实要逃这种课,你也不需要懂得太多,你只需要保证你比老师讲课的水平高就行了。我们有的老师,水平真心烂,不逃课对不起他。

但是很多学生总是走极端,说到自学就一点课都不上了,看不起学校的课程安排。自己在寝室学个把月就能轻轻松松地做出网站或者APP。但是我想告诉你,你能做到的,别人同样能做到。有一句话说的很好:

你的工资不是和你的工作时间成正比,而是和你的不可替代性成正比。

你和培训机构几个月量产出来的程序员差别在哪?仅仅是你没有给培训机构交学费吗?但你的技能和他们是差不多的啊。所以说学校教的基础课是很重要的,最直接的好处就是笔试,笔试考的就是基础。然后这对你长期的职业发展也是很有帮助的。你工作几年之后(可能就是一两年),发展肯定会遇到瓶颈。

2.2 关于读书

多读书,读好书

这是一句老掉牙的话了,但是事实就是如此,阅读经典书籍,你的投资回报率其实远高于阅读低质量的书籍。那么什么是低质量的书籍呢?比如《21天精通XXX》之类的。但是不管读什么书,都不能盲目跟风、囫囵吞枣。在网上,生活中经常看到各种索要书单的网友,借鉴别人的书单是可以得,但是直接照搬照抄则是不明智的。因为每个人已有的知识储备是不一样的,别人阅读的书籍不一定适合你。所以阅读合适的书籍也是一种重要的命题。

阅读合适的书籍

那什么是不合适的书籍呢?我认为有如下几类:

  1. 与自己的技术栈毫不相干的。这相关与否是建立在你已经做了清晰的职业规划的基础上,并且通过搜集信息能够自己辨识哪些是和自己的技术栈相关的,哪些是不相关的。当然,我并不是鼓吹大家技能点越单一越好,技术人员当然需要不停扩充知识面,但是对于大学生而言,这要建立在你在主要的技术栈上的积累已经足够多的时候(足以应付面试),不然东一榔头,西一棒槌,最后只能样样稀松。
  2. 超出自己能力范围的。虽然我前面说要读好书,要读经典书籍,但是一定要量力而行。很多经典书籍的阅读需要一定的基础,如果你只看到了别人对这本书推崇备至就开始强行阅读,最后通常也不多是走马观花,像读小说一样读完了而已,最后什么都没学到,还浪费了时间。老子说“企者不立,跨者不行”,其实不只是读书,学习技术本身也同样如此。
  3. 知识点与自身已具备知识过度重合的。面对一本经典书籍,可能你已经具备了那本书中所阐述的绝大部分知识,那么还有没有必要读呢?我的建议是:可以查漏补缺,但不要通读。很多经典书籍,单拿出一本来说都是值得阅读的,但是放到一起就不一定了。因为两本书籍可能70%甚至80%的内容类似,这时你读完一本,再通读另一本就没有必要了,比如我读了《C++ Primer》就没再去读《C++ Primer Plus》了。当然你可以阅读不重合的部分,这需要你有较强的辨识能力。

《C++ Primer Plus》虽然从名字上看起来像是《C++ Primer》的加强版,但其实并不是。它们是不同的作者,并且从风评来看《C++ Primer Plus》貌似比《C++ Primer》还要基础一些。。

善待图书馆

请大家一定一定要善待图书馆。讲真大学几年我对我们学校并无过多好感,但是唯一让我不舍的就是图书馆。相比电子书,我更喜欢那种手指翻阅纸张时那种真实的触感。大学临近尾声,这几个月疯狂的去图书馆借书读书。上个月竟然发现图书馆新购入了好几本好书,可惜的是我实在是没时间读了。

书非借不能读

很朴素的一个真理,借的书因为有时间限制,所以会逼迫你阅读。而如果是自己买的书,你潜意识就会觉得“啥时候读都一样”。当然这是对自制力不强的同学们说的。

2.3 打造自己的技术栈

技术栈,或者叫技术体系、知识体系,起于编程语言而又不止于编程语言。你可以多尝试,然后找到自己喜爱的技术方向开发深挖、发散。然而很多学生通常会在起步的时候就陷入迷茫。在网上看到过一个人,想学web开发,各种调研,然后向别人征求意见该学哪门语言比较好,哪个框架更有优势。后面大概过了半年,他还在纠结该选哪一个。

我只想说:先跑起来。语言很重要但并没有那么重要。无论语言还是框架本质上都是工具,在这些工具的使用过程中提炼出的**、方法、认知才是你要追求的能力。有了能力,即使你换了语言,换了框架照样能快速上手。我觉得大公司一般不会计较你对某一框架的API熟悉不熟悉,他更看重的是你对框架背后的设计哲学和原理是否了解。

简单谈一下学生阶段应该积累的一些通用技能:熟练掌握一门编程语言、熟悉一个数据库、熟悉一个版本控制系统(SVN、Git)还有就是老生常谈的计算机专业的基础了。

技术栈就像一棵大树,树根可能是操作系统、网络、算法、数据库。再靠上一点是编程语言。接着树干就是你的职业方向,可以是安卓、IOS、前端、后台等等。别忘了还有树枝和树叶。技术没有孤岛。把自己封闭在闭塞的圈子内十分危险。你应该是具备了深度的同时再拥有广度,请注意拥有深度是前提

没有什么东西绝对该学或者绝对不该学的,切忌盲从,照搬照抄别人的学习经历,强迫自己跟着别人的步子走。谁说你是后台的就不能看前端的东西?在你后台技术成熟之后是可以的,这样也能加深你对整体架构的理解。不仅前后端知识不再是孤岛,甚至开发、测试、运维之间的边界都在模糊。

另外这些树枝和树叶上悬挂着的也可能NoSQL、Git或者Docker等,你不需要在每个方面都是专家,但你应该对新技术抱有好奇心。

参次多态才是幸福的本源

2.4 深度思考和提炼

不管是前端还是后台,框架都是层出不穷的。每个都学,谁都会疲于学习。但实际上你并没有必要这么做,对于一个框架,记忆它的API永远是最低的技能,你要从中提炼出一些共性的知识点。比如后台框架,你学了之后你要记住的应该是URL路由、模板、权限控制、MVC的设计等等。那么你换一个框架,即使有不同,你也能快速上手,思维上只是换一套API,接着补一下个别差异、新特征而已。

对于编程语言的学习也是如此。C++的STL里面有各种算法,很多算法的参数中都包含一个函数对象(实际为重载运算符()),这就是函数式编程啊。学了javascript,你会感觉到很多时候其实也都是在进行函数式编程,并且比C++更甚,尤其是jQuery这个库的用法。提炼出不同语言之中的相似处及不同点,不仅能帮助你学习新语言,并且能帮助你巩固旧语言,加深你对旧语言的理解。

另外呢,计算机专业的很多课程其实也不是完全孤立的(虽然看起来可能如此)。比如说操作系统这门课:讲链接和装载,这肯定和C语言编译的可执行文件有莫大关联啦。讲内存管理,分段是啥?你不知道C语言里面数据段、代码段、XX段吗?内存的分配策略和分配算法,其实C语言里面malloc就在使用这些策略啊。大家一定要学会在不同课程之间建立联系,这是一件很有趣的事。

2.5 解决问题的能力

看似简单的能力,实际上很多学生都缺乏。解决问题的能力包罗万象。从初学者角度来说,你学习C语言编程,那么你一定要尽快学会调试的技巧,比如加断点,追踪栈信息之类的,其实并不难。但是不知道为什么很多人不会调试,我之前就给几个学妹调试过程序,烦死。

自己调试解决不了的问题,或者读书过程中产生的疑惑,其实绝大部分都是可以通过搜索引擎或者阅读更多的书籍来解决的。同样有很多人,一有一问题就问别人,我也遇到过,很多时候我也没能力直接回答他的,我需要去搜索,找到答案,再告诉他。我就想说**你不会用搜索引擎的吗?**最后浪费的是两个人的时间。

你想问别人的问题基本上网上都有人提问过了,你要做的就是耐心检索。其实使用搜索引擎也是有技巧的。比如:

  • 搜索的内容尽量精炼。不要既啰嗦又没有重点
  • 不停的修正你的问题。一次搜索结果通常不会解决问题,你需要的就是利用每一次搜索结果提供的信息来不停的修正你的问题,使之逐步精确到问题的核心
  • 某度解决不了的,用谷歌

别做伸手党,很多问题都是可以自己解决的,解决的方式有很多,不一一列举了。接着如果仍然不能解决问题,这时你就可以去各大问答类网站提问了。请注意,过于基础的问题,是没人愿意理你的。所以请确保你在提问之前已经做足了前面的工作。


3. 求职准备

3.1 早做规划

关于求职,一定要早做规划,最起码在大三开始就应该定下求职的规划。举个例子:

我意识到自己直接参加大四的秋招可能有很多不足,但是如果我找一个大三的暑期实习相比秋招应该要来的容易,并且实习留用的概率也比直接秋招通过的概率高。退一步讲,即便我实习不能留用,但我已经有了实习经历,那么我再去参加其他公司的秋招胜算也会大很多。

自己的短板一定要早点发现,然后及时找到弥补方案。比如你项目经验匮乏,那么你就应该在其他地方找到填补,例如:把基础打牢(从上层应用到底层原理),深入了解数据结构和算法,阅读开源项目源码等等。

俗话说“知己知彼,百战不殆”,你应该找个时间(不需要太早)去看一看你所关注的公司往年的笔试题以及面试题。网上有很多笔经面经可供参考。

其他的规划还有很多,比如你大概什么时候开始就应该频繁关注各大公司的招聘信息,什么时候开始海投。如果你准备去外地面试,那么提前给自己准备好足够的钱,不仅是车票,面试过程可能会持续几天,需要住宿之类的。

3.2 关于刷题

这是个见仁见智的问题,如果你基础足够好,那么大可以不要花太多时间在刷题上,但是我也建议你读一读《编程之美》、《剑指Offer》、《程序员面试宝典》、《程序员面试金典》之类的书来熟悉一下题型。

吐槽一下,我当时看的《程序员面试宝典》是第4版,不知道为啥出到第4版了,错误还很多。前半部分还好,值得一读,后面就不敢恭维了。大家读书一定要警惕。

如果你基础不太好,那么刷题就尤为重要了,虽然有点取巧,但也不失为一个办法。

这里提一下C++,即使你投的岗位不是C++(是Java或其他),那么笔试的时候遇到C++的概率也是很高的。这是因为考察C++更有区分度,更加便于筛选,所以希望大家尽量突击一下C++。当然,不同公司的选拔风格不一样,大家还是多参考一下他们往年的笔试题吧。(前端的话应该考不到C++,这点我不了解)

3.3 鼓起勇气

之前我们学校本科生进BAT的很少,可能要隔一年才有一个。但是其实并不是我们学校学生真的这么差,虽然我们学校教育不怎么样,但不代表我们学生的素质就是如此。原因很简单就是缺乏勇气。我曾和一些学长学姐共事过一段时间,他们对于BAT以及其他的互联网大厂,都是想都不敢想。我也曾经羞于说出自己的梦想“进入BAT”。

所有互联网大厂都是不会来我们学校所在城市(南昌)招聘的,我们要想面试这些企业都要去省外城市(比如武汉)。异地面试也是给很多人心中造成了无形的压力,觉得跑这么远,要是面试失败咋办,觉得不仅丢了钱还会丢面子。其实很幼稚,每个人都应该尽自己所能找到最好的工作,没必要想这么多,你丢掉的钱,迟早会得到更丰厚的回报。你丢掉的面子,迟早也会获得欣羡的目光,最差的情况你也能告诉自己“努力过了,争取过了,失败了也不后悔”。

想我当初可是在武汉面试蘑菇街一面就挂掉了,然后三天之后又收到了腾讯武汉面试的短信。你说我去不去?
“蘑菇街你都挂了,你还要面腾讯?”
我去,我一定要去。

还有一点就是不要害怕自己学校差(普通一本甚至二本),不要嫌弃自己学历低(本科)。首先研究生们在算法岗方面确实你本科生有优势,但是在开发岗上并没太大差别。然后大公司招聘虽然喜欢招聘名校的毕业生,但这仅仅是因为通过半个小时到一个小时的面试,面试官真的很难了解到你的全貌。而如果你是名校的学生,那么无形之中就在证明自己的能力,首先你能考上这个学校就证明了你的学习能力,然后这个学校师资力量,办学条件十分优厚,确实能助力学生的成长。如果你学校一般,那么面试官可能觉得你学习能力有欠缺,或者觉得这样一个学校并没有好的条件去培养你。

但是这绝对不是全部。你是普通学校的学生,并不代表你没有足够的学习能力,没有掌握足够的专业技能。你需要做的仅仅是努力向面试官展示出你的学习能力,你所掌握的技能就好了。

我有一个老乡,二本学校,但是去年收割了BAT的offer,其中霸面百度拿了special offer。他大学期间就做了很多事,做了很多项目,还开办工作室等等。这些大学经历以及项目经验写到简历上,和面试官一聊,那么面试官真的不会在乎你是什么学校什么学历的。

同学们,鼓起勇气,干巴爹。


写在大二的软考之后

原写作时间 2013-11-10

这周本就是考试周,昨天11.9也是全国软考的日子。

想起来我大概是8月15号左右,决定参加今天十一月份的软考的。现在想想当初莽撞的很。可能我没有一个说走就走的旅行。但是对于其他的事,说干就干的情况还是蛮多的。比如暑假时候去北大。当时也是脑袋一热就去了。这是我的缺点,也是我的优点。

试考完了,结果我不确定。上午好多也是不懂,但也以一种自己认为合理的逻辑推理出来了。上午呢,感觉计算机组成原理和设计模式确实薄弱。策略模式本来选了后来改了……下午总体感觉比上午轻松,只是那道c语言的算法题,我是基本上全蒙的。。汗颜啊。枉费我曾经花过那么多时间去ACM。不过这几个月我看了很多软考的知识点,唯独忽略了数据结构和算法。因为我的自负吧,呵呵。😔应该是自大。以为软考的算法要比acm简单太多,故没有去花时间。

不管怎么说,即便是两个月后,我得知我没有通过软考,我也不会太遗憾,太伤心,因为通过准备这个考试,我确实学到了很多东西,因为软考,我真的认识到、了解到太多太多的东西,解开了我许多的疑惑。大大加快了我学习计算机的步伐。。因为软考,我第一次看数据库。因为软考,我第一次学计算机网络,因为软考,我了解了软件工程,体会了面向对象的**和原则,意识到了设计模式的强大。因为软考,我明白了uml是个什么东西。因为软考,我去尝试并努力地理解计算机底层。。因为软考,我终于搞懂图片分辨率、像素点和图片存储空间的关系。因为软考,我开始发掘对网络通信的兴趣,试着去了解协议,也终于明白了,快播的(qvod协议)的强大,明白了p2p是peer to peer而不是point to point,明白了p2psearcher的原理是在使用电骡(电驴)的ed2k和kad协议。因为软考,我了解到的还有软件开发方法学,还有敏捷开发、极限编程(最有趣的是其中的结对编程),还有知识产权,还有考前两天才明白的dfd图。呵呵,还有,还有,还有很多。
所以即使我最后没有通过软考,我这笔买卖也是稳赚不赔。。

我昨天是五点四十起床,没有抱怨,没有抵触,没有不情愿。下了楼,发现门关着,刷卡也不开。。然后和寝室楼的老大爷磨蹭了一会我才开了门出去。坐公交的时候,到了市公交总公司站,下了225路公交,本来应该像往常一样坐6路的。但是等了一会还是不出现。我沉不住气了,5路有很多,看看5路的路线也是去南昌大学青山湖校区的。就坐上去了。谁知它开到火车站就提示说到了终点站了。尼玛,难道我看错方向了。越赶时间,越出乱子。这难道就是传说中的“墨菲定律”。百度地图查查,火车站,10路可以去南大青山湖。没想到,我站的地方就是10路的候车点。一会就上车了。最后到了软件学院,比计划还要早个十分钟左右。或许是天早没有堵车的缘故。好事多磨。

题外话是,在10路公交车上,我发现自己新买的瑞士军刀*威戈的包包破了个洞。我好桑心,花了268买个包就是因为不想再用几十块钱的烂包了(上个包40元,没多久,下面就开线了),这个两百多的包下面又破了……我自己真是难以原谅自己。四十块的破旧破了。这个有什么理由破。想退货,但是发票被自己丢掉了。呜呜。自己被坑了。顿时心情到了谷底……😭。后来发现,种种迹象表明是一只老鼠所为。为了偷吃我包包里的面包,咬破了我的包。😡😡该死的老鼠。不过心情较之刚才好了许多。我想原因应该是这样:起初我以为是包的质量问题,而破洞。我就是为了要个不容易破的高质量的包而花了268大洋。结果还破了,这就怪厂家坑我,我自己也傻,把发票丢了,更蠢到家,不过后来发现是老鼠所为,我就释然了,原来责任不在我身上,厂家没有问题,这个包质量本也是好的,我没有被坑。错在老鼠身上。呵呵。虽然结果是一样的。破了的洞还是破着,但是心情却不一样了。👊

软件学院门前还有很多大人,或者称之为已工作人士。当然他们是考的高级——高贵的系统架构师。我是中级。只能安慰自己至少不是初级。

未来大门已经打开,待我缓步向前。🚶。


PS:后续的补充
苦等了两个月,2014年1月12号的时候,终于查到成绩了。在此之前的一个月,几乎每天都会登陆那个查分网站。结果还好。下午56,上午53。嘻嘻,过了。


后记之二 2017-09-15

后来我计算机系的室友、同学经常说软考证书没啥含金量,没用。但我想说的是:
证书本身不重要,以考促学是王道

我的2013:变化的角色,不变的心

原写作时间 2014-01-04

开始的开始,我是失败的“推销员”

2012年九月,我终于通过苦逼的高考,迈进了一所南方大学的大门。那时,我对自己自信满满,相信自己能够在这方土地上大展拳脚。然后……

  • 竞选班干部,因为胆子太小而一无所获;
  • 报了多个社团,或笔试,或面试,无一通过;
  • 报考本专业的重点班,疏于准备而失败;
  • 追一个女孩,还没什么行动,就对我判了死刑。

那是大一上学期,一段黑暗的日子,此后认识了好多老乡,有的做了班长,有的进入了重点班,有的加入了牛逼社团,风云一时。这时我的日子更加黑暗了。

后来我做了很多的事,为的就是在大学里证明自己,因为一颗不甘庸碌的心。后来,被人忽悠着去做旅游推销,搞班级旅游,在班群里一提这个,就被同学们认为是赚同学的钱,然后各种鄙视。再后来跟着一群不靠谱的人去创业,跑着所谓的业务,然后在一个大雨之夜,我自认为敬业地去开会,结果被各种批,我默不作声地选择了退出。再再后来,阴差阳错地做了三个挂名的校园代理,去推销衣服,最后只卖给老乡一件正装,提成39。我真的不是这块料,但当初我依旧对未来信心满满,梦想着未来某一天,成为校园推销高手 ……各种名片,各种业务。哈哈,多好的白日梦啊,一直到那年寒假。世界末日已过,没成为拯救世界的英雄,平凡的日子还是要继续。那时,2013已经来了。

那个寒假里,我喜欢上了编程,其实大一上个学期,我们有开c语言的课,但是也只是期末突击了一段时间,考了个70分。当时确实面对这黑黑的cmd窗口,没有一点兴趣。。看不出高端大气?或许黑窗口中真的藏着黑客也说不定,我这样开着玩笑。

真正的开始,独学而无友

想起acm的事情,我总是唏嘘不已,我历历在目的是除夕夜的电话,一个感慨的暑假,还有我们院长敷衍的笑容。

除夕夜,在一个发小的问候中,提到了acm。他和我不是一个学校,他是学软件的,我是通信的,可以说是硬件。然后,搞了许久终于在杭电注册好,又搞了会找到了题目,又搞了一会找到了提交题目的地方。好多英文。。。然后,我突然对这个有了兴趣,一整天一整天都在提交代码。等着ac。虽然,刚开始我的c语言特别的水,错误百出,误解颇多。但是也在一点一点补足。呵呵,然后开学了,我在学校贴吧里询问了好久,得到了一个冰冷的事实,我们学校没有acm的校队,甚至好多人不知道有这么个东西,也不感兴趣。我一遍一遍在贴吧里呐喊,也曾试图说服几个同学一起来A题目。但是失败了。

“独学而无友,则孤陋寡闻”

不只是孤陋寡闻,更是一种深深的寂寞。只有我自己一个人整天对着oj敲代码、提交。然后看着ac而手舞足蹈,也会每隔十道题的时候发一条说说,比如“我做了五十道了”。但是没人懂我,大家开始觉得我有些不可理喻,有些魔障了。所幸的是,我们开了数据结构课,我很高兴。然后大一下的这个学期,我开始拓展编程的兴趣。尝试了java,尝试了python,甚至装过linux系统。大都没有坚持下去,我觉得人的精力是有限的,花在时间上走马观花,是毫无意义的。但是这些关于编程,关于计算机的尝试,确实也蛮有乐趣。生活的重心多次转移,又一次次回到acm上。很多时候做出一道题来,还自鸣得意的发到csdn博客里。熬夜成了家常便饭,吃饭也不好好吃了,身体也变差了好多,清楚的记得又一次早上上厕所,结果突然失去意识,跌了下去。幸亏摔到地上的时候,疼痛感很强,然后我恢复了意识,踉踉跄跄的站了起来。后来有转专业的机会,我也报名了转专业考试,我的目的很明确——计算机专业。其实通信和计算机也是相关专业,并且我也主要是自学的,但是通信专业的课程之多,课程之我不喜欢的程度超出我预料。

转专业考试,我还是没有怎么复习,依旧醉心于编程(我自控力太差了),然后觉得自己转专业无望了。但这段时间,感觉自己的自信心反而倍增,原来做过那么多事都做不好,终于发现一个自己能做好的事情了,那就是编程。兴趣是最好的老师。我们在大学里就应该多尝试才好啊。记得心理健康课的老师曾经说过:

你面前有一百种水果,怎样知道你最喜欢吃哪一种水果呢?答案只有一个,那就是吃一遍。

是啊。大学里碰壁不可怕,怕的是因为怕碰壁而不敢去尝试。

赶上计算机二级报名的时候,当时我还问了我的数据结构老师在哪里报名,老师说了句“二级?你怎么不报三级呢?”。我笑了。期末了,后来奇迹的是我收到了转专业成功的通知。下个学期,就可以转。然后自己就没有好好复习自己专业的课,挂了两门。但是数据结构考了95分。巧的是,后来的计算机二级也是95分。

暑假开始了,原先在poj上看到了北大暑期学校的广告。然后就报了。暑假就去了北大听课了。住在亲戚家里,每天到地铁去北大东门。哎,惭愧的是,一起上课同学的都是来自知名学府。深感自己基础不足。然后,浑浑噩噩的两周。中间周末的时候去北京玩了两天。踩坏了一只沙滩鞋。还有就是喜欢喝农夫山泉了。因为我发现无论是酸奶,果汁、或者碳酸饮料这些东西都很好喝。但是喝的同样很快。倒是一瓶农夫山泉在旅游的时候喝的久一点。

回到家里。开始一边搞搞算法,一边学学android。这时有一种纠结的心理状态,关于算法还是应用开发。大一下学期期末的时候,加了一个实验室。我选择加入的是android组。还有就是因为计算机二级对于计算机专业是没有用的,所以暑假的时候报名了十一月份的软考。通过软考我真的学到了好多东西,从前我完全没有接触的东西,比如操作系统,计算机网络,设计模式,软件工程,数据库等等。这让我发现了计算机世界原来如此博大,它并不只有算法而已。

还有一件事,值得一提。那个暑假,我还给我们学院的院长,发过一封邮件,讲的是我对于学校开展acm的倡议。结果,院长回复了,并让我准备acm相关材料,九月份开学去找他谈。我喜出望外。然后精心打磨了21页的材料,在word里,还加了大标题,小标题,然后目录。还给每页的添加了个美观的页码。开学后,我去了院长办公室,院长又找来一位主任,把这个事情交给他办,他们还说的大义凛然。说过段时间联系我。我很高兴。然后呢?就没有然后了……这就是院长的敷衍。从此我对学院,对于学校都失去了信心。甚至悔恨自己当初选错了学校。

话休絮烦,我们学校的计算机专业是很不好的专业。转专业的时候,从来是计算机专业转到其他专业,极少有其他专业转入计算机专业,除非是比计算机还差的专业。然后我因为没有竞争力,以转专业考试高数49分的成绩就考了过来。。哎,微积分,没学好啊。然后这个学期呢,主要还是自学为主。由于对于算法,对于acm伤透了心,所以这学期大部分精力都在学开发,跟着实验室那帮人。主要就是java啊,android啊。搞算法的时间少了。虽然不是acm了,但是我的不安分的心还是一样的。我仍旧渴望证明自己。

国庆七天,我没有出去玩,而是待在实验室里,因为我觉得放假的时候是最好的学习时间。诚然,这七天的学习效率,远超过此后一个月。这七天,我多次是三四点钟才睡。有时候还不困,然后一看时间,快四点了,自己都很惊奇。

渐渐地,也小有所成,对于开发,在同届同学里面算作佼佼者了。将自己写的一段代码发到csdn博文里,竟然上了首页。呵呵。我自己觉得真的是很水的东西,我感觉是越学越发现自己的无知。这个学期,有些搞智能车比赛的同学,也曾邀请我去做软件。但我谢绝了。还有其他的同学,找我做项目,我研究了一番后也谢绝了。虽然也说是去做软件,但我明白自己喜欢做什么,不喜欢做什么,我没有发现我所喜欢的idea,我不会轻易浪费自己的时间去做,时间是如此宝贵。

不是结束的结束,不变的心

后来又是一年的十月份,十一月份,十二月份,那时候想到去年这个时候自己还在推销,如今已经找到了兴趣,并为之拼搏,励志要做程序员。回首一年往事,对于人生的起伏多变,既感慨,又欣慰。而关于我与acm的一切,我已几乎不与人提及。。这也成了我的隐痛。并逐渐被我忘却。元旦的时候,放下了编程,也不去实验室了,开始期末复习,偶然间看到书架上被自己束之高阁的《算法导论》。心中一阵酸楚。我几乎一个学期都没有碰它,我还记得当初花80大洋,从当当那里拿到货时的喜悦。曾经也多次翻阅。

所有的结局都已写好,所有的泪水也都已启程,却忽然忘了,是怎麽样的一个开始

是啊,我忘了自己是怎样开始喜欢编程的,我忘了自己曾经的执迷。这次,我开始坦然面对,学校没有acm又如何呢?我喜欢的更多的是算法吧。算法在今后的工作中其实还是蛮重要的,如果你不想只停留在表面的话。今后我同样可以自己学学算法。只是不需要像对待一个竞赛那样花费全部精力去对待他,这样我还有时间去搞搞开发。成功的道路有很多。且不管今后如何,我在做自己喜欢的就对了。我对自己说:**谁不是摸着石头过河呢?**我一直以来不就是这样过来的吗?

岁末末,暑假的时候给自己定的三个小目标都实现了:计算机二级,英语四级,软考。新的一年又开始了,从2012到2013,再到2014。变了好多东西。我的角色也在转变。我的想法,我身边的人,包括我敲的代码也在变。曾经梦想变成一个推销高手。如今梦想变成一个编程高手,但我如今愈发觉得,从上大学开始,虽然变化了这么多东西。但是有些根本的东西还是一样的,那就是,我是如此地渴望证明自己,渴望被别人认同。

这一年,我相信是我人生的一个转折。2013,我开始爱上编程。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.