小菜虎的窝
火星日记 ~ 第一千四百一十天 ~ 中秋节快乐
Lee.MaRS 发表于 2009-10-03 19:06:57
比如2009.9.14, 也就是我加入公司快满第二个月的时候, 第一次加班加到了第二天凌晨3:30.
打车回去到小区门口的时候, 连车门都摸了好半天才打开.
师傅说困糊涂了吧, 我笑笑, 恩.
车开走之后, 整个世界就只剩下寂静.
不自觉地抬头望天, 才发现满天繁星, 在黑夜中是那样的璀璨.
北京的秋天来得很早, 深夜的风已然带些一丁点刺骨的寒意.
我下意识地把手环在胸前, 却只能感受到自己的温度.
多么希望能有你陪在我身边.
==================我是里世界和表世界的分隔符=====================
话说我到了北京之后一直过得很沉沦, 连中秋是哪天也没搞清楚.
一直以为是10.8, 结果今天收到祝中秋快乐的短信才发现还没买月饼...
还好我们部门已经发了一大盒=_=, 不然和在大学里面就没区别了.
最后祝大家中秋节快乐~
火星日记 ~ 第一千三百六十二天 ~ 入职一个月
Lee.MaRS 发表于 2009-08-16 23:02:58
火星日记 ~ 第一千三百二十七天 ~ 回归
Lee.MaRS 发表于 2009-07-12 00:28:06
这103天, 经历了太多的事情.
生活如峰回路转般变化着.
总结一下, 大概就是.
我大学毕业了, 离开了生活了近5年的地方.
我拿到了新的offer, 成了北漂一族.
大致就这样吧.
btw: 其实本篇的主要目的, 是回来拔个草, 呵呵..
火星日记 ~ 第一千二百二十四天 ~ 半年的终结符
Lee.MaRS 发表于 2009-03-31 18:56:03
经历波澜起伏.
经历漫长等待.
终于等到了.
幻想的破灭.
赶在这三月的最后一天.
丝毫不用怀疑这可能是个April Fool的玩笑.
Reject @ Google, SET
Farewell, Google.
火星日记 ~ 第一千一百三十四天 ~ Happy new year!
Lee.MaRS 发表于 2008-12-31 22:58:31
祝大家新年快乐,心想事成!
Python源码剖析读书笔记可能还会暂停一段时间,因为这项工作实在是非常耗费时间的一件事情,而我现在无法集中精力,静下来把笔记写上来。
不过这项工作还会继续下去,我现在也还在继续阅读这本书,在书上乱涂乱画。
希望大家在新的一年,还能把我的Blog留在你们的Google Reader里面。:-)
火星日记 ~ 第一千一百三十四天 ~ 人生第二封拒信
Lee.MaRS 发表于 2008-12-31 22:22:09
有人和我说过,其实今年百度和微软还是比较好进的。
我和这两家今年都是各有两次机会,也就是说,一共有四次机会摆在我的眼前。
可惜我都没能拿到offer。
第一次是内推面百度。
详情之前我也提到过一些。
总体来说,那次面试面得相当失败。
技术的问题答得一塌糊涂。
一些文化上的问题也冲突严重。
自然是直接被拒了。
第二次是面M$ STBC。
也许是没有经过内推的原因,我接到的是HR电面。
我那一口结巴的英语被HR直接教育了。
然后做Open Problem,SDET职位的。
大概是HR觉得我没有什么资质吧。
收到了人生的第一封拒信。
第三次还是面M$,换了另外一个组。
这次是直接面试。
面试的情况应该还行,考的题目都非常trivial。
就是这样trivial的题目,当时还是让我做得挺难受的。
我自己都不知道该如何解释为什么会这么难受。
然后被电面,问到了一些数据库的简单的东西。
我关系数据库基本上就没有用过,MySQL什么的基本算是不懂。
然后就算电面跪了。
最后没有收到offer,只是问我有没有兴趣去实习,时间是三个月。
我想了一下,拒绝了。
第四次是Baidu。
先是在线笔试。
题目应该算不上很难,但是感觉是挺开放式的题目。
时间也挺紧的。
最后还是通过了在线笔试。
后来接到了电面。
虽然我很想针对面试官提的那些问题吐槽,但这些其实不是最重要的。
对于这次电面,我只后悔一件事情。
就是我在电面的时候由于某种鬼使神差的因素,上网查资料了。
然后也不知道为什么,面试官知道了。
最后,从内部人士那里听说,面试官以这个理由拒了我。
如果是别人的错还好说。
自己犯错误就觉得非常可惜了。
于是,我在2008年的最后一天,收到了来自Baidu的拒信。
=================================================我是拒信的分隔线=================================================
您好!
感谢您应聘“电子商务事业部”职位,通过笔试、面试,
再次感谢您对百度一直以来的关注与信任,以及对我们工作的支持,
谢谢!
百度电子商务事业部
=================================================我是拒信的分隔线=================================================
可以说Baidu毫无人性,在2008年的最后一天发拒信,不让人家过个欢乐的新年。
也可以说Baidu做了件好事,至少不让我把霉运带入2009年。
我和Baidu,和M$,注定是没有缘分的。
火星日记 ~ 第一千一百二十八天 ~ Merry Christmas
Lee.MaRS 发表于 2008-12-25 02:20:29
圣诞夜没闲着, 参加合唱团的走穴活动去了.
四首歌, 唱了两次, 然后就搞定了...
收入两张大红纸...
唱得如何?
恩... 感觉唱得相当的囧...
不过现场的客人看上去根本不在乎你唱什么...
于是我也无所谓了...
反正明年就没我的份了 -.=b
上台唱的时候大家都很矜持.
反倒是在休息的时候唱得很high.
一堆人在那里拼命唱我不会的曲子, 郁...
害得我只好一个人在那里默默地看书...
圣诞夜看别人来吃天价自助餐, 其实心情有一点奇怪的.
zhouye小朋友说以后有钱了也要来这里吃, 再带个小MM...
我就囧住了...
我以后大概没什么机会来吃这种天价自助餐吧...
一是穷...
二是以我的勤俭持家的性格来看应该也不会做这样的事情...
最后离开酒店了以后, 一堆人在路口等着过马路时吃错药了开始唱 Ezekiel Saw The Wheel...
引来无数人侧目...
于是我们开始大声自称是交大的...
回来的时候坐在出租车上, 想想以后要是工作了, 一天的收入还没有一个晚上这样随便唱唱的收入多...
继续囧...
Python源码剖析学习 - Chap3 - Python中的字符串对象 - Part2
Lee.MaRS 发表于 2008-12-14 20:06:00
望对Python有爱的筒子都能购买一本, 支持这本国内难得一见的好书.
转载本文, 请注明作者leemars. 欢迎大家访问作者的博客 http://leemars.ycool.com
[创建PyStringObject对象]
Python提供了两条路径, 从C的原生字符串创建PyStringObject对象. 这两条路径分别是
PyString_FromString和PyString_FromStringAndSize.
先来看PyString_FromString:
[Objects/stringobject.c]
PyObject *
PyString_FromString(const char *str)
{
register size_t size;
register PyStringObject *op;
assert(str != NULL);
size = strlen(str);
if (size > PY_SSIZE_T_MAX - sizeof(PyStringObject)) { /* 1 */
PyErr_SetString(PyExc_OverflowError,
"string is too long for a Python string"); /* 2 */
return NULL;
}
if (size == 0 && (op = nullstring) != NULL) {
#ifdef COUNT_ALLOCS
null_strings++;
#endif
Py_INCREF(op); /* 3 */
return (PyObject *)op;
}
if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) {
#ifdef COUNT_ALLOCS
one_strings++;
#endif
Py_INCREF(op); /* 4 */
return (PyObject *)op;
}
/* Inline PyObject_NewVar */
op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size);
if (op == NULL)
return PyErr_NoMemory(); /* 5 */
PyObject_INIT_VAR(op, &PyString_Type, size);
op->ob_shash = -1;
op->ob_sstate = SSTATE_NOT_INTERNED;
Py_MEMCPY(op->ob_sval, str, size+1); /* 6 */
/* share short strings */
if (size == 0) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
nullstring = op;
Py_INCREF(op);
} else if (size == 1) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
characters[*str & UCHAR_MAX] = op;
Py_INCREF(op);
}
return (PyObject *) op;
}
代码还是比较长的. 下面简单说明一下, 顺便提一些Python2.6的变化, 标号对应代码中
注释处:
1. 判断字符串的长度加上PyStringObject本身的大小(即整个变长对象PyStringObject
的实际大小)后, 是否超过系统限制的最大大小. 书上的Python旧版代码中仅判断
size > PY_SSIZE_T_MAX, 也就是没有考虑对象自身的大小, 是不完善的.
2. 当需要分配的内存超过系统限制的上限时, 抛出异常PyExc_OverflowError, 即溢出.
书上的Python旧版代码没有抛出异常.
3. 对于长度为0的空串(即"", 而非NULL), 若nullstring已经被初始化, 则返回
nullstring. 这是intern机制的一部分. 书上的Python旧版代码没有对nullstring增加
引用计数.
4. 对于长度为1的字符串, 若字符表中该字符对象已经初始化, 则返回该字符对象. 这是
intern机制的一部分. 书上的Python旧版代码没有对该字符对象增加引用计数.
5. 若申请内存空间失败, 则调用PyErr_NoMemory()处理. 书上的Python旧版代码中没
这一部分.
6. 使用Py_MEMCPY代替直接使用memcpy. 贴一下Py_MEMCPY的代码:
[Include/pyport.h]
/* Py_MEMCPY can be used instead of memcpy in cases where the copied blocks
* are often very short. While most platforms have highly optimized code for
* large transfers, the setup costs for memcpy are often quite high. MEMCPY
* solves this by doing short copies "in line".
*/
#if defined(_MSC_VER)
#define Py_MEMCPY(target, source, length) do { \
size_t i_, n_ = (length); \
char *t_ = (void*) (target); \
const char *s_ = (void*) (source); \
if (n_ >= 16) \
memcpy(t_, s_, n_); \
else \
for (i_ = 0; i_ < n_; i_++) \
t_[i_] = s_[i_]; \
} while (0)
#else
#define Py_MEMCPY memcpy
#endif
看注释应该就明白了, Py_MEMCPY是为跨平台优化而提供的一个宏. 因为在有些平台上,
调用mempcy的代价比较高, 所以对于小数据量的拷贝就原地展开成循环. 那Python觉得
哪些平台需要这样的优化呢? 看到_MSC_VER了吧, 这个是M$的C编译器特有的宏, 看来,
需要特别优化的就是Windows下了.
书上贴出的Python代码可能出于简化的考虑, 与实际的Python2.5的代码有所出入, 故再
次强调上述几点描述的差异乃是对比Python2.6与书上的代码.
我们不妨也来一次简化, 把所有的异常处理以及intern机制相关内容去掉, 看看这段代
码的核心是什么:
PyObject *
PyString_FromString(const char *str)
{
register size_t size;
register PyStringObject *op;
size = strlen(str);
/* Inline PyObject_NewVar */
op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size);
PyObject_INIT_VAR(op, &PyString_Type, size);
op->ob_shash = -1;
op->ob_sstate = SSTATE_NOT_INTERNED;
Py_MEMCPY(op->ob_sval, str, size+1);
return (PyObject *) op;
}
是不是变得非常清爽呢? 依次说来就是:
1. 求str的长度
2. 为变长对象PyStringObject申请内存, 地址赋给op.
3. 用宏PyObject_INIT_VAR, 初始化op的头部(包括ob_refcnt, ob_type, ob_size)
4. 将op->ob_shash初始化为-1(未计算)
5. 将op->ob_sstate初始化为SSTATE_NOT_INTERNED(未interned)
6. 将str复制到ob_sval
7. 返回op
之前我们还提到过PyString_FromStringFromSize, 它与PyString_FromString有什么不
同呢? 我们把代码单独摘出来, 用diff比较一下代码:
% diff -uN PyString_FromString.c PyString_FromStringAndSize.c
--- PyString_FromString.c 2008-12-14 17:03:53.945677523 +0800
+++ PyString_FromStringAndSize.c 2008-12-14 17:04:25.054637950 +0800
@@ -1,14 +1,10 @@
PyObject *
-PyString_FromString(const char *str)
+PyString_FromStringAndSize(const char *str, Py_ssize_t size)
{
- register size_t size;
register PyStringObject *op;
-
- assert(str != NULL);
- size = strlen(str);
- if (size > PY_SSIZE_T_MAX - sizeof(PyStringObject)) {
- PyErr_SetString(PyExc_OverflowError,
- "string is too long for a Python string");
+ if (size < 0) {
+ PyErr_SetString(PyExc_SystemError,
+ "Negative size passed to PyString_FromStringAndSize");
return NULL;
}
if (size == 0 && (op = nullstring) != NULL) {
@@ -18,7 +14,9 @@
Py_INCREF(op);
return (PyObject *)op;
}
- if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) {
+ if (size == 1 && str != NULL &&
+ (op = characters[*str & UCHAR_MAX]) != NULL)
+ {
#ifdef COUNT_ALLOCS
one_strings++;
#endif
@@ -26,6 +24,11 @@
return (PyObject *)op;
}
+ if (size > PY_SSIZE_T_MAX - sizeof(PyStringObject)) {
+ PyErr_SetString(PyExc_OverflowError, "string is too large");
+ return NULL;
+ }
+
/* Inline PyObject_NewVar */
op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size);
if (op == NULL)
@@ -33,7 +36,9 @@
PyObject_INIT_VAR(op, &PyString_Type, size);
op->ob_shash = -1;
op->ob_sstate = SSTATE_NOT_INTERNED;
- Py_MEMCPY(op->ob_sval, str, size+1);
+ if (str != NULL)
+ Py_MEMCPY(op->ob_sval, str, size);
+ op->ob_sval[size] = '\ 0';
/* share short strings */
if (size == 0) {
PyObject *t = (PyObject *)op;
@@ -41,7 +46,7 @@
op = (PyStringObject *)t;
nullstring = op;
Py_INCREF(op);
- } else if (size == 1) {
+ } else if (size == 1 && str != NULL) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
我们把PyString_FromString称为A, PyString_FromStringAndSize称为B. 从diff的结果
分析, 我们可以知道:
1. A用assert假设str不为NULL; B接受str为NULL的情况.
2. A的用strlen计算size, size必然非负; B对于传入的size为负数的情况, 抛出异常,
类型为PyExc_SystemError.
3. A对于字符串str, 要求以'\ 0'结尾, 而且中间不能包含'\ 0'; B对于字符串str, 并不
要求以'\ 0'结尾, 且允许字符串中间包含'\ 0', 但要求字符串必须至少含有size个字符.
看看简化之后的代码:
PyObject *
PyString_FromStringAndSize(const char *str, Py_ssize_t size)
{
register PyStringObject *op;
/* Inline PyObject_NewVar */
op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size);
PyObject_INIT_VAR(op, &PyString_Type, size);
op->ob_shash = -1;
op->ob_sstate = SSTATE_NOT_INTERNED;
if (str != NULL)
Py_MEMCPY(op->ob_sval, str, size);
op->ob_sval[size] = '\ 0';
return (PyObject *) op;
}
不过就是size不需要自己计算, 改为传入了而已. 不过这一小小的变化, 却导致这两个
函数可以接受的字符串性质的不同.
[注]该死的Ycool, 代码大概有问题, 会把\ 0(中间空格去掉)替换成#CONTENT#....

