Loading...
墨滴

公众号:offer多多

2021/07/25  阅读:111  主题:橙心

腾讯笔试-请问下面的程序一共输出多少个"hello,world”

腾讯笔试-请问下面的程序一共输出多少个"hello,world”

大纲

欢迎 欢迎关注公众号 “Offer多多” 一、为什么要做:给自己一次主动思考机会,看看你现在真实水平(可以跳过看第三点)

  • 1.1 自己没有方法:公司也不会主动去培养你
  • 1.2 来自面试官架构师的视角

二、做什么:从知识图谱中寻找真正问题是什么 (可以跳过看第三点)

  • 2.1 第一步 思考角度:把自己当作业务,我调用下api ,我需要考虑做什么事情。不靠技术实现 (对你有啥帮助)
  • 2.2 按照步骤在学习一边。
  • 2.3 调度知识卡- 意识到问题存在。

调度能力 是单机数据库和分布式数据库最大区别

也是一个软件实现开放,连接,面向未来的基础。

存储能力:了解io栈

三、怎么做,60秒问答,小例子开始。

请问下面的程序一共输出多少个"hello,world”

 for ( int i = 0; i < 2; i++) {
        fork();
        printf("hello,world1"); //
        printf("hello,world2 \n"); //hello,world
    }

回答:

四个进程,hello,world1 输出8个,hello,world2 就是6个。

60秒完成。阅读这里 可以解释来哦,下面是分析过程。


一、为什么要做:给自己一次主动思考机会,看看你现在真实水平(可以跳过看第三点)

1.1 自己没有方法:公司也不会主动去培养你

因为在工作中,不是每一个研发都有机会参与架构设计;

很多公司也不会主动去培养你成为架构师。

所以,有很多职场人在一家公司工作三年或五年之后并没有多大的提升。

而很多的架构师都是研发自己在机遇巧合下,遇到大项目、参与其中、趟了坑、解决了问题,最终形成自己的知识体系和解决问题的能力之后才成长起来的。

那么如果没有这些条件,你还有没有途径成为一名架构师呢?

当然有,在我看来,你要先掌握架构师的知识体系,

然后再通过实践进行检验,这样才能逐步成长为一名架构师。

送给老人的四条建议

  • 思考

你要有敏感的思考能力(这里用的是敏感,不是敏捷或敏锐)。因为对于同样一个问题,每个人都有自己的理解方式,不同人由于学历、阅历、经历的不同,对问题的理解深度也会有所不同,所以不是所有人天生就能有敏锐的视角,这个很正常。

但我希望你的思维是敏感的,通过敏感驱动思考,通过思考驱动学习和总结,直至敏锐。这确实需要大量的练习,它也是一个潜移默化的过程,最终你会因为这个习惯受益一生。

  • 表达

你要有良好的表达能力,无论是和同事还是领导之间的沟通,这里的沟通并不是指会说话,而是会表达、敢表达、表达准确。

有一点你要注意,表达不是指口才好,而是建立在你充分思考基础之上的分析,而我建议你多学习一下结构化思维,比如《金字塔原理》。相信你会发现表达、汇报、甚至 PPT 功底都会有所提升。

  • 惊艳

这一点其实是我对自己的要求,我会暗示自己,当作一件很有价值的事情时,评估的方式就是要惊艳到自己。

因为只有惊艳到自己,你做的事情才会超出别人的预期,超出领导对你的期望。领导要的可能是 1,你要尽力做到 1.2,甚至 1.5,因为 1 谁都能做到,而超出的 0.2 / 0.5 就是你与其他人拉开的差距。事事有回应,件件有着落,回应和着落都要超出预期。 千万不要当职场老油条,因为懒惰会变成习惯,最终会影响你的判断力。

  • 认知

工作几年的职场老人,一定要对“地位、格局、方法论、手段”,这些看似很空的词有明确的认知,你要让这些极空的词儿变得很具体。举个例子,比如一道面试题“什么是架构设计?”,作为一名合格的职场技术人,至少要有以下的认知。

和一面解释:架构就是系统设计,比我在做 A 项目时,考虑到问题 X,我的解决办法是 Y。

和二面解释:架构就是业务发展中将系统变得有序,比如架构设计就是合理的组织系统、模块、组件,让它们更加有序,为的是让系统有能力快速响应(需求/用户/市场)变化。

和部门总监解释:架构即管理

送给新人的四条建议

对于职场新人,我也有几条建议送给你。

  • 要有计划,有积累:在寻求公司价值的同时,要对自己个人未来的价值有追求和计划。

  • 学习一些时间管理四象限:重视重要不紧急的事情,新人不要觉得时间多就随意挥霍,你的价值才能决定你的圈子和你的人脉。

  • 要自己定位自己:不要让别人或你的上级定位你,虽然屁股决定脑袋,但你对自己的定位会决定你屁股的位置。

  • 要善于归纳总结和思考:这会让你和其他人拉开差距

总而言之,作为一名技术人,我们既然选择了这个职业,就一定要有上进的决心,不能只顾写代码,一定要提升架构设计能力。因为即使代码写得再好,做的也是执行层面的事儿,就会有收入的天花板,想要突破它,就要突破你做事儿的边界

1.2 来自面试官架构师的视角

一个例子:

  • 首先,你们系统里面为什么要用MQ

不少去面试的人,都知道自己以前项目里面用过MQ、Redis,但是为什么用这个,却不知道,这种人说白了就是为了用而用,又或者这个框架就是别人设计的,他自己都没了解过里面的东西,自然也不知道为什么要用。

如果面试的时候面试官问你这种问题你答不上来,可能已经被pass百分之三十了,面试官通常对这种人印象很不好,他怕你进了公司只会埋头苦干,不懂得自己思考。

  • 第二,你既然用了MQ,那你知不知道MQ有什么好处和坏处 如果没考虑过这个问题一定要慎重回答,因为你没考虑过这个,盲目的弄个MQ进系统,当下的问题可能是解决了,

但万一后面出了问题不是给公司留坑吗,面试官就怕这样的人,招进来干了一年,自己跳槽了,给系统挖一堆坑,留下无穷祸患。

  • 第三,既然你用了MQ,比如其中一种MQ,那你当时做没做过调研

别看别人用了MQ,咦,感觉挺好的,就自己瞎弄了一个,根本没考虑过MQ的选型,比如kafka,每个MQ并没有绝对的好处和坏处

现在业界流行的MQ各有各的好处,各有各的坏处,你要做的就是扬长避短,挑选最适合自己系统的MQ。

同一思维层次解决不了同一思维层次上产生的问题”
同一思维层次解决不了同一思维层次上产生的问题”

其实简单一句话,

所谓的架构师视角就是全局的视角,这里的全局包括空间全局和时间全局,在空间全局上你要看到整个系统的领域边界,在时间全局上你要看到整个系统的发展周

  • 我同时也是一位面试官,在面试过程中我发现了一个共性问题:很多研发工程师在基础问题上答得不错,却往往栽在架构设计问题上。 要么回答的不够有深度,要么考虑的不够全面,或者干脆直接把网上看到的方案抄过来,哪里有坑都不知道。

很多同学都会面临这样的局面,切忌不要在网上搜索一些高性能高可用的架构设计方案 ,因为你没有实际踩过坑,很难分辨哪些技术场景下的设计仅仅是为了公关,很难落地, 在面试中也很容易被面试官识破,怀疑你的技术能力的真实性。

  • 架构最重要的是要解决本质复杂性,这包括人的复杂性和业务的复杂性。

二. 做什么:什么知识体系,大纲在哪里(也就是第一点)

那架构师的能力到底由哪几部分组成呢?

  • 基础技术架构:这部分是纯技术架构,所有非功能性的技术都是基础技术的范畴。

  • 业务架构:在业务场景下对业务需求的抽象。

  • 开发技能:这是架构师落地架构的能力。

2.1 第一步 思考角度:把自己当作业务,我调用下api ,我需要考虑做什么事情。不靠技术实现 (对你有啥帮助)

  1. 为什么这么做1 ?帮助你实现了什么目标,了什么问题
  2. 为什么这么做2 ?然后抽象什么业务场景适合,什么业务场景不适合.优缺点,也是才过的坑
  3. 为什么这么做3 ?不同技术的对比。

2.2 按照步骤在学习一边。

一、这个技术出现的背景、初衷和要达到什么样的目标或是要解决什么样的问题

二、这个技术的优势和劣势分别是什么

劣势

三、这个技术适用的场景。任何技术都有其适用的场景,离开了这个场景

四、技术的组成部分和关键点。

五、技术的底层原理和关键实现

六、已有的实现和它之间的对比

2.3 调度知识卡- 意识到问题存在

2.4 存储知识卡 --io栈

io栈
io栈

三、怎么做,60秒问答,小例子开始

例子1

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>

int main(void)
{
  
    for ( int i = 0; i < 2; i++) {
        fork();
        printf("?"); //hello,world
    }
    return 0;
}

例子2

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>

int main(void)
{
    int i;
    for (i = 0; i < 2; i++) {
        fork();
        printf("?\n");//hello,world
    }
    return 0;
}

答案:傻傻分不清楚 例子1 8个,例子2 6个

问题拆分:一共产生几个进程

1. 青铜:小王的分析第一次,结果肯定是错误的

循环里有fork ,fork 里面有循环 结果是死循环 ,造成stack溢出呀,根本不会输出 在哪里思维停顿了。

点评:

  1. 虽然看很多次,对fork原理还是不懂,
  2. 之前对:线程,协程 切换概念感觉很了解,stack存储局部遍历,寄存器
  3. 之前对gdb, 白学习了,stack存储局部遍历,你这个却理解不了

补充最少知识

  • fork的实现

fork的实现分为以下两步

  1. 复制进程资源
  2. 执行该进程

复制进程的资源包括以下几步

  1. 进程pcb
  2. 程序体,即代码段数据段等
  3. 用户栈
  4. 内核栈
  5. 虚拟内存池
  6. 页表

2. 白银:小王的分析第二次,打印多少?不知道,必须分析多个个进程

你现在任务分析多少个进程,不考虑打印多少?

相同颜色的是同一个进程
相同颜色的是同一个进程
相同颜色的是同一个进程
相同颜色的是同一个进程
[misaki@localhost test]$ ./main
ppid:2221, pid:4846
ppid:4846, pid:4847
ppid:2221, pid:4846
ppid:4846, pid:4848
ppid:4846, pid:4847
ppid:4847, pid:4849


[misaki@localhost ~]$ pstree -ap misaki
sshd,2220
  ├─bash,2221
  │   └─main,4846(P1)
  │       ├─main,4847(P2)
  │       │   └─main,4849 P(3)
  │       └─main,4848(P4)
  └─bash,3571
      └─pstree,4850 -ap misaki
  • p1 进程 首先程序一开始,bash产生一个进程P1执行此程序,P1进入程序。
  • P2进程 当i=0时: fork()产生一个子进程P2,同时它自己输出一个'-'。P2继承P1的诸如环境变量,P2首现会输出一个'-'。

当i=1,会继续执行for循环---P2先fork()出一个子进程P3,同时再输出一个'-'。

  • P3进程 P3进程为P2的子进程,它会复制其父进程P2的指令,变量值,程序调用栈,环境变量,缓冲区等,它会输出一个'-'。

  • P4
    此时P1进入程序后,当i=1时,fork()产生另一个它的子进程P4,同时输出一个'-'。P4同样会输出一个'-'。

## 打印多少?
 
 ###  1. 青铜:小王的分析第一次,结果肯定是错误的 
 
  > 被多个fork 吓住了,却没想到 块设备 和字符设备的区别?
  
  点评:cout flush函数都不懂,差
 
 

- 打印4个 hello

#include <stdio.h> #include <unistd.h> #include using namespace std; int main(void) { cout<< "hello" ; fork(); cout<< "hello" ; return 0; }


- 打印3个 hello

#include <stdio.h> #include <unistd.h> #include using namespace std; int main(void) { cout<< "hello" << endl; fork(); cout<< "hello" << endl; return 0; }

最少知识

我们的子进程会复制父进程的缓冲区。

  • 关于缓冲区,Unix下的设备块设备和字符设备的概念, 所谓块设备,就是以一块一块的数据存取的设备,字符设备是一次存取一个字符的设备。 磁盘、内存都是块设备,字符设备如键盘和串口。块设备一般都有缓存,而字符设备一般都没有缓存。

程序遇到“\n”,或是EOF,或是缓冲区满,或是文件描述符关闭,或是主动flush,或是程序退出,就会把数据刷出缓冲区。

  • 需要注意的是,标准输出是行缓冲,所以遇到“\n”的时候会刷出缓冲区, 但对于磁盘这个块设备来说,“\n”并不会引起缓冲区刷出的动作,那是全缓冲,你可以使用setvbuf来设置缓冲区大小,或是用fflush刷缓存。

———————————————— 版权声明:本文为CSDN博主「MisakiFx」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_41669298/article/details/102720096

  • 块设备通过系统缓存进行读取,不是直接和物理磁盘读取。字符设备可以直接物理磁盘读取,不经过系统缓存。(如键盘,直接相应中断)

    • 因为P4为P1的一个子进程它会继承P1的缓冲区,其中有一个'-',所以P4会输出两个'-'.
    • 因为这里P3会继承P2的缓冲区,其中有一个'-',所以P3会输出两个'-'.

    这是因为printf(“-”);语句有buffer,所以,对于上述程序,printf(“-”);把“-”放到了缓存中,在fork的时候,缓存被复制到了子进程空间,所以,就多了两个,就成了8个,而不是6个。

塔山

  • linux 进程 fork() https://zhuanlan.zhihu.com/p/53527981

  • fork创建子进程(printf的打印次数问题)

  • 一个关于fork()的面试题

  • https://blog.csdn.net/yao5hed/article/details/81273677

  • fork()的底层实现机制 https://blog.csdn.net/dianacody/article/details/22401475

  • fork()函数的面试题

  • C++之标准设备IO操作流

公众号:offer多多

2021/07/25  阅读:111  主题:橙心

作者介绍

公众号:offer多多