Lost:有道运维开发面试
上周找同学内推的有道运维开发的实习,然后前几天收到面试通知,今天下午四点面试。
怕路上堵车,于是骑自行车去的,3:50到了创业大厦。找到前台,说明是来面试的。还没到点,让再边上一个屋子等着,里面已经有两个同学在等了。
坐那等着,顺便小聊了一会,那俩面的都是研发岗位,有一个是北交的,另一个还没来得及问,他就进去面试了。
然后,一直等,等他俩都进去面试了,还没到我,囧。然后来了一位美女,搭讪后发现居然也是北邮的,是网研交换中心的,面的是词典部门,上午刚面完广移。
都5点了,还木有轮到,于是跑前台在去问问,然后前台发现好像忘记和里面联系了,囧死。
再等了一会,面试官出现,带到一个会议室面试,1v1面试。
面试官翻了一下简历,让介绍一下简历上的项目,然后balabala开始介绍。
说完一个,问在项目中做了那些事,说明是项目负责人,完成项目的大部分工作。然后问为什么要这么设计,有说了一堆。
然后第二个,DM642那玩意。这个东西说实话,不太懂。说明只负责了其中的一部分工作,做了流量控制和丢包处理这一块。然后问了丢包检测怎么做,说了在每个包加序号,包长,偏移量,然后这个系统是单向的,没有反馈,错误的包直接就丢了。然后问了采集,编码,发送三个进程之间的关系,为什么这么做。这个也答的迷迷糊糊的。。。就说了一下消息队列,用这个队列来缓冲编码和发送任务的时间差。
第三个项目,javatweet那个,没问啥。
然后问我,top里头load那三个数字的具体含义。这玩意天天看,但是还真没去关注具体的含义,囧死。说是系统负载,平时只关注它会不会超过1,超过1就是过载了,多核的cpu可以允许超过1小于cpu数目。面试官不太满意,我也知道这答案肯定不靠谱。
下面是回来查到的正确答案。
系统平均负载被定义为在特定时间间隔内运行队列中的平均进程树。如果一个进程满足以下条件则其就会位于运行队列中:
- 它没有在等待I/O操作的结果
- 它没有主动进入等待状态(也就是没有调用’wait’)
- 没有被停止(例如:等待终止)
load 后面分别是1分钟、5分钟、15分钟的负载情况。数据是每隔5秒钟检查一次活跃的进程数,然后根据这个数值算出来的。如果这个数除以CPU 的数目,结果高于5的时候就表明系统在超负荷运转了。
然后,面试官又看了一眼简历,说,你写个程序吧,把一个字符串转换为浮点数。
想了一下,开始在纸上写的是先用strch函数确定小数点的位置,然后分别对付整数部分和小数部分。写完发现这办法不好,然后又写了个用while循环,直接处理,遇到小数点跳出循环然后处理小数部分(小数部分用了堆栈)。写完发现,是不是可以直接根据float数据类型在内存中的结构有跟好的处理方式,但是死活想不起float在内存中什么结构了,唉,真是准备不足啊。只好把前面的程序交了,然后说了一下后面的想法。
IEEE 双精度格式为8字节64位,由三个字段组成:52 位小数 f ; 11 位偏置指数 e ;以及 1 位符号 s。这些字段连续存储在两个 32 位字中。
在VC里面,double型数据占据了8个字节,共64位。
最高位是符号位,0表示正,1表示负。
接下来的11位表示指数,用移码表示,关系为:11位数组成的值(无符号)-1023=指数,如上所示5.0的指数部分是2,11位数组成的值应该是1025,即100 0000 0001
余下的52位是小数位,其中1.0……中的1是默认的,没有占据位数。5.0的小数部位是1.01,则它的小数位在内存中应该表示成0100 0000 0000 ……0000(共52位)
所以+5.0在内存中存储的形式应该是0100 0000 0001 0100 0000 …… 0000即0×40140000 00000000。float型和double型基本一样,只是它用8位表示指数,用23位表示小数,另外它的移码表示不是相差1023(2的10次方-1),而是127(2的7次方-1)。
下面是C代码库中的atof函数源码,看了一下,和我写的程序思想一致,但是没有用堆栈,确实更方便,我当时为啥没有想到呢。而后面那个采用内存结构的方法应该是行不通的。而且这个函数确实考虑特别周到,考虑到了符号和E的问题。
#if HAVE_CONFIG_H
# include <config.h>
#endif#include <errno.h>
#ifndef errno
extern int errno;
#endif#include <ctype.h>
#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
# define IN_CTYPE_DOMAIN(c) 1
#else
# define IN_CTYPE_DOMAIN(c) isascii(c)
#endif#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
#define ISDIGIT(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
#define TOLOWER(c) (IN_CTYPE_DOMAIN (c) ? tolower(c) : (c))#include <math.h>
#include <float.h>
#include <stdlib.h>
#include <string.h>/* Convert NPTR to a double. If ENDPTR is not NULL, a pointer to the
character after the last one used in the number is put in *ENDPTR. */
double
strtod (const char *nptr, char **endptr)
{
register const char *s;
short int sign;/* The number so far. */
double num;int got_dot; /* Found a decimal point. */
int got_digit; /* Seen any digits. *//* The exponent of the number. */
long int exponent;if (nptr == NULL) /*如果为空串,则结束转换*/
{
errno = EINVAL;
goto noconv; /*转向处理无法转换的代码*/
}s = nptr;
/* Eat whitespace. */
while (ISSPACE (*s))
++s;/* Get the sign. */
sign = *s == ‘-’ ? -1 : 1;
if (*s == ‘-’ || *s == ‘+’)
++s;num = 0.0;
got_dot = 0;
got_digit = 0;
exponent = 0;
for (;; ++s)
{
if (ISDIGIT (*s))
{
got_digit = 1;/* Make sure that multiplication by 10 will not overflow. */
if (num > DBL_MAX * 0.1)
/* The value of the digit doesn’t matter, since we have already
gotten as many digits as can be represented in a `double’.
This doesn’t necessarily mean the result will overflow.
The exponent may reduce it to within range.We just need to record that there was another
digit so that we can multiply by 10 later. */
++exponent;
else
num = (num * 10.0) + (*s – ’0′);/* Keep track of the number of digits after the decimal point.
If we just divided by 10 here, we would lose precision. */
if (got_dot)
–exponent;
}
else if (!got_dot && *s == ‘.’)
/* Record that we have found the decimal point. */
got_dot = 1;
else
/* Any other character terminates the number. */
break;
}if (!got_digit)
goto noconv;if (TOLOWER (*s) == ‘e’)
{
/* Get the exponent specified after the `e’ or `E’. */
int save = errno;
char *end;
long int exp;errno = 0;
++s;
exp = strtol (s, &end, 10);
if (errno == ERANGE)
{
/* The exponent overflowed a `long int’. It is probably a safe
assumption that an exponent that cannot be represented by
a `long int’ exceeds the limits of a `double’. */
if (endptr != NULL)
*endptr = end;
if (exp < 0)
goto underflow;
else
goto overflow;
}
else if (end == s)
/* There was no exponent. Reset END to point to
the ‘e’ or ‘E’, so *ENDPTR will be set there. */
end = (char *) s – 1;
errno = save;
s = end;
exponent += exp;
}if (endptr != NULL)
*endptr = (char *) s;if (num == 0.0)
return 0.0;/* Multiply NUM by 10 to the EXPONENT power,
checking for overflow and underflow. */if (exponent < 0)
{
if (num < DBL_MIN * pow (10.0, (double) -exponent))
goto underflow;
}
else if (exponent > 0)
{
if (num > DBL_MAX * pow (10.0, (double) -exponent))
goto overflow;
}num *= pow (10.0, (double) exponent);
return num * sign;
overflow:
/* Return an overflow error. */
errno = ERANGE;
return HUGE_VAL * sign;underflow:
/* Return an underflow error. */
if (endptr != NULL)
*endptr = (char *) nptr;
errno = ERANGE;
return 0.0;noconv:
/* There was no number. */
if (endptr != NULL)
*endptr = (char *) nptr;
return 0.0;
}
然后问我会不会perl和python,回答会基本的python,不会perl。然后就没有问问题了。
最后问了一个问题,就是如果你写了一个服务程序,那么你怎么通过另一个程序来监控这个服务。首先回答的是服务程序产生日志,然后另个一程序分析日志。面试官表示同意,然后问还有什么方法。我说可以通过进程间定时发送状态消息的方法,面试官继续问还有什么方法。我又说可以通过监视服务器所在进程的进程号。然后问题就来了,问我一个进程起来后怎么获得自己的进程号。我就记得有一个系统调用的干这事的,具体忘了,没答上来。。。。回来查了一下,应该就是getpid()。
然后问我有什么问题,问了一下这个工作具体是偏向运维还是开发。回答,基本不负责维护,主要是开发,开发运维用的工具。然后问了一下时间要求,说是一周3天。
最后,面试官告诉我一周内会有结果,撤!
大概就是这样,处女面,没有经验,表现的很差。。。估计要杯具。
去之前,以为要问算法,要问计算机网络,要问脚本,于是特别看了很多算法,计网,python东西。结果一个算法都没有问,计网的东西也没有问,囧死。看样子还是对职位要求不清楚。。。
总算处女面是有了,以后加油吧,对职位的要求还是要弄清楚,不然杯具会更多的。