V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Applenice
V2EX  ›  程序员

请教 V 友们,一或两年经验的 C/C++程序员,应该具有什么样的能力才算是合格或者优秀的

  •  
  •   Applenice · 2018-05-29 16:36:55 +08:00 · 11350 次点击
    这是一个创建于 2377 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想请教 V 友们一下,一或两年经验的 C/C++程序员,应该具有什么样的能力才算是合格或者优秀的,看招聘信息的要求总感觉有些乱,如果你们去面试这样的同学都会考察哪些方面呢?先谢谢大家

    第 1 条附言  ·  2018-05-30 16:13:39 +08:00
    真心的感谢大佬们的讨论,先简单汇总一下吧,有没提到的我会补上
    1.printf 的问题,详见 41,76,77 楼
    2.协程问题详见 63,66,90,91 楼
    3.能力问题详见 1,10,15,17,47,53,62,82 楼
    再次感谢各位大佬
    120 条回复    2018-05-31 14:41:38 +08:00
    1  2  
    vx2018
        101
    vx2018  
       2018-05-31 10:10:35 +08:00
    写写业务写写界面给各位大佬递阔乐
    GUS777
        102
    GUS777  
       2018-05-31 10:11:53 +08:00
    Mark
    wekw
        103
    wekw  
       2018-05-31 10:38:22 +08:00   ❤️ 1
    @mashiro233 这个是你的博客吗? https://2heng.xin/ 2015 级的商科本科生,技术爱好者?下一条回复我会一一驳斥你的观点。

    这里不是你误导人的地方。

    如果你想获得成就感,出门左转知乎谢谢,上面很多中学生,一定会对你五体投地的。
    mashiro233
        104
    mashiro233  
       2018-05-31 10:55:27 +08:00
    @wekw
    不是

    同样,这里不是你误导人的地方。这句话我还给你。

    期待你的驳斥。
    wekw
        105
    wekw  
       2018-05-31 11:06:10 +08:00   ❤️ 3
    @mashiro233 正面回应:

    首先我希望你不要把你在网上的博客上看来的浅显甚至是错误的知识用来反驳我。从你的反驳可以看出,这不是你自己工作经验的产物,甚至都不是系统学习的产物,你需要学习的是《计算机组成原理》和《 CS:APP 》,特别是后者,建议你看一下。

    1. 协程是在单线程内工作的一点错没有,现实中协程调度就是在单线程内做的,理论上讲只占一个核心。但是,第一操作系统会自动调控,第二单线程的协程也比多线程多进程性能高几个数量级,例如 C10K 和 C1000K。
    2. 你完全没有好好看我的评论,协程为什么性能高,就是因为没有上下文切换了。
    3. 你管这个叫测试?好好学学英语,这是一个研究者在某一个会议上发表的论文,目的就是网络调优。关于 x86 网络性能你可以读读腾讯云的文章: https://cloud.tencent.com/developer/article/1035503 中文的。
    4. DPDK 你都不知道是什么原理吧?找个文档就反驳我。实际上你这个回复是在帮我解释。这也反映了你真的完全不懂什么是协程,请再读一遍我上面的那条回复,学习一下什么是协程。等你明白了就知道你这个回复的逻辑错误在哪里了。
    5. 还是你不懂协程导致的。你不仅不懂协程,还不懂网络编程的本质,frame 依旧是 kernel 提供的,网卡那里就是一个又一个电信号,哪管你什么 frame 不 frame 的。多学习,你会明白的。
    6. 你拿着现有的多线程网络编程思想来看待我的话,自然无法理解。实际上我觉得你的这条回复不知所云,自己都乱了。还是建议你仔细读一下我上面的回复,学习一下什么是协程。

    总结:

    从你的回复来看,我上面的结论“写不出来的话,能一句话概括我也认。绝大多数人都不知道高性能服务器开发领域的协程概念。”是正确的。

    你真的要好好学习一个。“协程的开销会比手动接管 callback 来的要高”,协程调度器的本质就是手动接管 callback,你还是不懂协程,唉。

    如果你真的是 15 级本科生的话,真的不建议你出来误导人,你的道行还浅。水平低不可怕,出来误导人就是你的不对了。

    五年前我还在上大学的时候就断言过“知乎是技术的荒漠”,这五年来一直在应验我这句话,很遗憾,v2 不是技术的荒漠,说错了容易被分分钟打脸。

    归根到底,你要试着从技术的使用者的角度切换到技术的提供者的角度看待问题,这才是真正的技术进步之道。引用我很喜欢的一个大牛的话结束本次回复:水平和经验无关,大牛永远是大牛,如果不提高自己的知识水平,就算积累十年经验,也只是熟练的弱鸡。(况且你还没有实际经验,真的不建议你现在出来追求成就感,对你技术价值观的建立有害。)
    wekw
        106
    wekw  
       2018-05-31 11:14:50 +08:00   ❤️ 2
    @mashiro233 回复的是 #99 的内容

    node.js 的异步 IO 是用 libuv 来做的,这里是中文文档: http://luohaha.github.io/Chinese-uvbook/source/introduction.html

    简而言之,libuv 封装的是 libev (*NIX ) 和 IOCP ( Windows ),而 libev 使用的是 epoll ( Linux )和 Kqueue (*BSD ),归根到底都是操作系统提供的功能,我上面说过,这个功能是 CPU 和操作系统联合实现的。更多细节请参考《 CS:APP 》。

    另外稍微提一句,IO 的意思就是输入输出,Linux 下严格讲不存在“文件 IO ”这个东西,因为一切皆文件。
    wekw
        107
    wekw  
       2018-05-31 11:18:49 +08:00   ❤️ 2
    再附带一个小小的吐槽:node.js 的异步 IO 本质不是为了解决磁盘 IO,而是网络 IO ( MySQL、redis、RPC 等),磁盘 IO 已经超快了,不需要异步。
    farseeraliens
        108
    farseeraliens  
       2018-05-31 11:30:44 +08:00 via iPhone
    为什么你们都在讨论两年经验如何如何,难道超过两年就不写 cpp 了吗……
    Applenice
        109
    Applenice  
    OP
       2018-05-31 11:46:31 +08:00
    @season4675 谢谢谢谢~~~阿里的大佬...那个大佬我现在真的很菜的,简历就先不给您看了吧,真的很感谢,嘿嘿,杭州挺好的,一直想去一趟看看来着
    mashiro233
        110
    mashiro233  
       2018-05-31 12:18:14 +08:00 via Android
    @wekw

    首先感谢你的回复,我确实不懂协程,我在工程中并没有使用过协程,不算 go 的话。
    、我的之前回复语气可能有点冲,这里我道歉。我确实经验不足,毕竟我工作也没几年。既然 v2 是讨论技术的地方,那我继续向你请教。
    另外你认错人了。

    1.`第一操作系统会自动调控`
    在我的理解里,单线程的调控就是把之前在 A 核的任务挪到 B 核。并没有解决一个核满了一个核空的问题。

    2 `协程为什么性能高,就是因为没有上下文切换了`
    我的理解里协程里依旧有上下文切换。因为需要保存当前程序运行在了哪一句。这个就是上下文,否则我无法理解协程是如何恢复到原来运行环境的,只不过开销比较小。可以话提供一个协程实现库让我学习一下。

    3 ` 你管这个叫测试?好好学学英语,这是一个研究者在某一个会议上发表的论文`
    可能是我的描述有误,这里的测试指的是论文里的测试数据。这篇链接是用来反驳你`是无法实现 10Gbps 和 40Gbps 的网卡速度的`这句话的。这篇文章依旧用的是 linux 网络栈,之后还有 bbr 的测试数据。根据里面的测试数据在 100Gbps 下达到了 79Gbps 的成绩。100Gbps 都能达到有个还可以的成绩,何来无法实现 40Gbps 一说?另外你给的文章里面也提到了 `使用多核编程技术替代多线程,将 OS 绑在指定核上运行` `而多核则是每个 CPU 核一个线程` `DPDK 程序启动后只能有一个主线程,然后创建一些子线程并绑定到指定 CPU 核心上运行`(这个是我贴的文档里描述)。这里面都提到了线程,只不过是用的线程池(不是无脑的开新线程还是将任务分配到线程池)。我还是没有看到里面提到了协程。

    4. 同上

    5.是我的描述有误,这里的 frame 指的是 ethernet frames。我没有说不是内核提供的,tun 本身就是依赖内核实现的。

    6.我重新看了一遍,没有问题。goroutine 就是这么做的。

    7. 我研究过 libuv 源码,也给 libuv 提交过 pr,我现在做项目基本上都是基于 libuv 做的。所以我才会说提供给 nodejs 异步的 api,文件操作用的是线程池实现的。另外,你说的文件指的是 File descriptor,这里是单纯的 file,也是描述不清的问题。

    8.`你真的要好好学习一个。“协程的开销会比手动接管 callback 来的要高”,协程调度器的本质就是手动接管 callback,你还是不懂协程,唉。 `

    我这里指的是,与其在 callback 处放协程调度器,不如自己实现一套更加轻量的调度器,参考 libuv,libuv 没有使用协程,老一点的 libevent 也没有使用协程。

    总结下我的观点
    1. 你的协程高性能这点,是得力于异步 api,和协程本身没有任何直接关系,不是协程造就了高并发高性能,协程是用来减轻异步 api 带来的开发难度。
    2. 协程依旧需要切换上下文,因为需要恢复到 yield 的地方继续执行。
    mashiro233
        111
    mashiro233  
       2018-05-31 12:22:16 +08:00 via Android
    @wekw

    补充。在我看来,你是把协程和异步 api 混为一谈了。异步 api 能够使用协程的机制进行任务调度,但不是异步 api 必须使用协程。
    wekw
        112
    wekw  
       2018-05-31 13:04:04 +08:00   ❤️ 2
    @mashiro233 我并没有把异步和协程混为一谈,我完全没有谈异步。我仔细给你解释一下协程好了:

    Linux 下的线程只是共享内存的进程,所以线程在切换的时候还是需要上下文切换:CPU 的状态寄存器从用户态切到内核态,把寄存器里的内容存到内存的某个区域,从内存的另一个区域读出之前存储的某个线程的寄存器内容(包括“下一个指令”指针)写入到寄存器,再把状态寄存器切换到用户态,执行“下一个指令”,上下文切换完成。

    而协程不需要这样做,协程对操作系统来说没有发生任何上下文切换,寄存器的内容和“下一个指令”指针都是自己实时维护的,简单来讲就是维护一个“动态任务列表”,实时地修改这个列表调整下一个指令的顺序。

    所以这也就是为什么我说你没有理解协程:线程池技术也好,epoll 技术也好,都是操作系统级别的模型,协程是运行在某个线程内部的动态的自我维护的调用顺序,在操作系统看来,这个线程一直占用着 CPU,使用率可能都一直是 100%,但这并不影响协程的高效:由于在响应事件(如 TCP 有新的数据)的时候协程所在的线程以及所在的 CPU 没有发生中断,可以有效利用高速缓存(局部性),所以可以在一定的时间内处理巨量的请求,所以性能爆表。

    说到高性能 SDN,以前我一直不理解为什么要用软件来实现网络,直到我知道了 DPDK,因为 UNIX 1969 年被设计出来最初是为了管理电话交换的,而电话交换的两端都是有状态的,所以中断”就成了一个好工具;后来的 CPU 设计也沿袭了这个设计思路。而 在当下的高性能软件定义网络中,要实现的是 ip 层的超高速包转发,而不是 TCP 这种状态机通信,所以 x86 CPU 的设计思路就不再适合了。

    现实中 DPDK 的应用场景也是无状态的包转发,如负责 ip 包转发的网关,工作在 UDP 53 端口的 DNS 服务器等场景。有人把 DPDK 和 nginx 结合起来了,但是性能提升只有区区 2-3 倍,原因就是 TCP 是一个状态机,只提高自己的效率是不够的,还是要消耗很长的时间等待客户端的响应。

    x86 CPU 的性能可以说大部分来自于 缓存+乐观 的理念,“局部性” 是一个极好的特性。
    leviathan0992
        113
    leviathan0992  
       2018-05-31 13:06:14 +08:00
    @zhicheng 把你写的 OS 给我看看
    zhicheng
        114
    zhicheng  
       2018-05-31 13:24:50 +08:00 via iPhone
    @leviathan0992 你是谁?为什么要给你看?
    maxco292
        115
    maxco292  
       2018-05-31 13:26:52 +08:00
    @wekw 协程的是否发生操作系统级别上下文切换要看实现的栈模型吧,比如 stackless coroutine 可以认为没有任何上下文切换只是调用顺序改变,而 stackful coroutine 这种需要分配内存,寄存器入栈,是肯定发生操作系统上下文切换了。
    mashiro233
        116
    mashiro233  
       2018-05-31 13:45:22 +08:00 via Android
    @wekw

    破案了。
    你这么一解释问题就解决了。
    我们之间对协程这个定义理解的不一样。

    我认为你所说的协程就是 goroutine,boost::coroutine 这种,很显然并不是。

    举个 boost 的例子
    ```
    void foo(){
    std::cout << 1;
    std::cout << 2;
    std::cout << 3;
    }

    void bar(){
    std::cout << a;
    std::cout << b;
    std::cout << c;
    }

    ```
    利用协程,我们可以让在单线程的情况下,通过 yield,能够让程序输出 a 1 b 2 c 3。这个是协程,能够在单线程的情况下切换 context。让它看起来像多线程。

    你所说的“协程”,就是一种任务调度机制,你可以决定 foo 和 bar 的先后执行顺序输出可以是 1 2 3 a b c 或者 a b c 1 2 3。但是你无法做出 a 1 b 2 c 3 这种输出。

    libuv 做的就是你说那些工作,给不同 socket 针对 read,write 等事件调用绑定的回调方法,并且还提供了 timer,线程安全的 sync 等常用工具。
    leviathan0992
        117
    leviathan0992  
       2018-05-31 13:50:44 +08:00
    @zhicheng 是我把你写出来的
    zhicheng
        118
    zhicheng  
       2018-05-31 13:51:33 +08:00 via iPhone
    @leviathan0992 对不起,我哪儿得罪你了吗?
    liuminghao233
        119
    liuminghao233  
       2018-05-31 14:06:01 +08:00 via iPhone
    @mashiro233

    一直不懂他为啥说协程性能高

    确实协程保存栈恢复栈这个工作是少于线程切换
    但这没有关系啊

    协程是基于异步的
    下面还是 epoll kqueue 这些
    异步代码有 event 来了直接调 callback
    协程还得先恢复栈
    怎么可能更快啊
    这跟线程半毛线关系都没有啊
    mashiro233
        120
    mashiro233  
       2018-05-31 14:41:38 +08:00 via Android
    @liuminghao233

    你看他的说明,显然他说的"协程"和我们理解的协程不一样。

    按照他的说明,只要做到方法级别的调用顺序控制就行了,连 yield 都没有(或许 return 就是 yield ?)。大概就是`异步代码有 event 来了直接调 callback `这一步就是“协程”调度器。

    我们理解的协程就是参考 boost 的那个协程例子,能够在 foo 和 bar 函数里来回跳的那种切换,做到语句级的切换那种切换,让出后还有机会执行下面的语句。可能需要用到 setjmp 或者 ucontext 这种。
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2625 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 11:28 · PVG 19:28 · LAX 03:28 · JFK 06:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.