罗晨汛

罗晨汛

移动互联网开发者

1 什么是 OKR

OKR目标关键结果管理法。

**O**:即目标。企业层面的目标,来自企业对战略和业务逻辑的本质思考,好的目标,应该能把握主要矛盾,合理取舍,明确打法,从而形成有效的战略聚焦。团队、个人层面的目标亦如此。

**KR**:即关键结果,既是实现目标的策略,也是跟进目标落地的路径,衡量目标实现程度的里程碑。好的 KR,应该是兼顾长短期利益、ROI 更优的策略。

okr-hierarchy

阅读全文 »

1 例句摘抄

To understand what an API is, first let’s think about a technical product we all use, like Zendesk Support.

要理解什么是API,首先让我们想想我们都在使用的技术产品,比如Zendesk Support。

2 单词

2.1 invoice

音标
1
英  [ˈɪnvɔɪs]   美  [ˈɪnvɔɪs]

n. 发票;货物;发货单
vt. 开发票;记清单

in·voice (开发票声音要大一点 ^_^)

注意,不一定是我国意义上的“发票”,也可能是下单后的费用清单。

2.2 out-of-the-box

adj. 拆盒即可使用的;开箱即用的

Deliver rich, modern, and automated conversational experiences out-of-the-box on your website or mobile app.

在您的网站或移动应用程序上提供丰富、现代和自动化的对话体验。

2.3 marketplace

音标
1
英  [ˈmɑːkɪtpleɪs]   美  [ˈmɑːrkɪtpleɪs]

n. 市场;商场;市集

the activity of competing with other companies to buy and sell goods, services, etc. 市场竞争
例:

1
Companies must be able to survive in the marketplace. 公司必须有能力在市场竞争中生存下去。

因为我一来不是搞文学的,二来也非文科毕业,所以无法说鲁迅是我的师承。但是。从书本中收获最多的还是鲁迅的文章,而且身为理科生,尤其喜欢他的杂文。嬉笑怒骂,一气呵成。论点论据论述论证,排山倒海,顺理成章,应该算是理科生眼中最优雅的文体了。

但是近来我渐渐喜欢上了看小说。相比智慧机敏、嬉笑怒骂,一气呵成地讲道理。一波三折、娓娓道来,也有它独特的味道。

当然,在文学史上就你看,小说的地位独一档。诺贝尔文学奖大部分受奖者都是以小说深受大众所爱。经过我的思考,发现这其实是有原因的。讲道理,其实是一个收敛的过程。虽然讲道理会经过铺事实论据论证到结论这样一个逻辑推理的过程,但其实它是一个收敛的过程。因为一个道理需要听众,也就是接受者有足够丰富的阅历才能接受。

怎么说呢,举个例子,比如说《论语》中一句:

子在川上曰,逝者如斯夫

我们看这本书这句话。表面上只是表达了时间的紧迫,时间的流逝,当然你就可以这样理解,孔子是在告诉我们一寸光阴一寸金,要珍惜时间,时间一去不回头。

但实际上你真要读懂这句话,是需要通过一些阅历,特别是人生经过一些未完成的志愿或者说遗憾的事,你才可以明白孔子在川上面对滚滚黄河体会到的时间的那种匆忙的流逝,奔腾流去的那种紧迫感、那种窒息感。特别是那个“逝”,奔流而去的河水仿佛是生命体,会因流失而逝去。

所以我说讲道理是一个收敛的过程,它需要受众有一定的阅历才能更好地明白,比如说孔子这句话。表示的是一个深刻入木三分的一个人生哲理,但如果你没有作者的阅历,你无法跟着他一起收敛。

而小说,则为读者营造了特定的上下文。在阅读小说的过程之中,读者与书中的人物同呼吸共命运,感受了他的感受,体会着他的体会。就算是与同一篇杂文要表达一样的观点,但是因为你有了书中人物的经历和环境上下文之后。更有助于你体会作者想要表达的意思,而这种体会也会更加刻骨铭心。讲故事也是一个发散的过程,正像我们所说的一千个人眼中有一千个哈姆雷特。人们在讲故事者的娓娓道来之中,会有自己发散的各种体会。

莫言当然是一个优秀的讲故事者。《蛙》这本书正如他所说,表面上讲的是计划生育,但实际上不止于计划生育的还是中国社会的风土人情。用回他老人家的话就是,如果不了解计划生育,就别说自己了解中国。

正如这本书的标题,他在书里说,蛙,也就是与娃同音。同样,这本书不仅描述了中国在计划生育中的一些故事,其实也描述了中国人对待下一代的一个态度的一个历史变迁。

大陆的计划生育,实行三十年来,的确减缓了人口增长的速度,但在执行这“基本国策”的过程中,确也发生了许多触目惊心的事件。中国的问题非常复杂,中国的计划生育问题尤其复杂,它涉及到了政治、经济、人伦、道德等诸多方面。尽管不敢说搞明白了中国的计划生育问题就等于搞明白了中国,但如果不搞明白中国的计划生育问题,那就休要妄言自己明白了中国。

直面社会敏感问题是我写作以来的一贯坚持,因为文学的精魂还是要关注人的问题,关注人的痛苦,人的命运。而敏感问题,总是能最集中地表现出人的本性,总是更能让人物丰富立体。

好的道理,好的观点应该尽可能的收敛,尽可能的精炼,意味深长。而一个好的故事应该尽可能的发散,尽可能多的引发出读者更多的想象与思考。《蛙》,就这样来说,无疑是篇优秀的小说。

线性表 可是算是最基础的数据结构了,但是你不应该看不起他。实际上,线性表 相关的知识可以很基础,也可以很深入。我们平常编码工作可以说有 50% 的时间都在使用他,鉴于他的应用如此之广泛,我们不妨从身边最常应用的工具入手,扒一扒这个可爱且趁手的工具。

1 线性表与数组

对于线性表,众所周知常用的两种实现 – 数组链表。这两种实现的复杂度也是我们熟知的:

(时间复杂度) 头插 尾插 随机插 随机删除 随机访问
数组 O (n) O (1) O (n) O (n) O (1)
链表 O (1) O (1) O (1) O (1) O (n)

数组的 操作(插入与删除)效率较低,这是因为在数组中间位置插入与删除元素,都需要移动位置后面的所有元素。而链表的 操作效率低,因为访问链表元素得一个接一个访问,不能利用到内存的随机访问特性。所以这是我们平时采用哪种数据结构的依据,比如在使用 Java 中我们常要思考使用 ArrayList 还是 LinkedList

而在 Objective-C 编写中就没那么头疼了,只有一个选择就是 NSMutableArray(对于只读的 NSArray,必定是使用简单数组,这就不深扒了)。为啥 OC 中如此设计呢,想必是实际的编程过程中数组的使用要多于链表。

1.1 为什么用 array 多于 linkedList?

因为在实际项目中,对于数据成员我们使用 array [i] 索引读取的操作的情况一般来说总是较从数据中间插入数据更常见。

但是,使用普通的 array 还是许多局限,比如说,队列 是个很常用到的数据结构,其中涉及到许多从队尾入队列,从队头出队列的操作。这个很常用到的数据结构用简单的数组操作起来就会比较低效。经过分析我们可以知道,其主要复杂度在于从列表头出列,后面的元素都要逐个往前移一位,这样的操作会非常低较。

而采用环形缓冲区则可以优化这一块,整个缓冲区的头与尾在逻辑上是相连的,任一头的插入或删除元素都是自由的,无需整体移动。如下图:

1
2
3
4
5
6
7
8
9
10
11
# 原数组:
┌──────┬──────┬──────┬──────┐
| │ A │ B │ │
└──────┴──────┴──────┴──────┘
0 1 2 3

# 在队列尾插入 C,然后队列头出列 A:
┌──────┬──────┬──────┬──────┐
│ │ │ B │ C │
└──────┴──────┴──────┴──────┘
0 1 2 3

2 环形缓冲区的设计与实现

要实现这样一个环形缓冲区并不复杂,只需要下面几个变量:

1
2
3
4
list 缓冲区指针,指向缓冲区的首地址。
size 缓冲区大小,表示该缓冲区的大小,当缓冲区大小与实际存储的元素数量相同时,就需要动态地扩张缓冲区了。
used 缓冲区内实际存储元素的计数,表示缓冲区内实际上有多少个元素。
offset 缓冲区里的数组的第一个元素索引

我们可以看出,使用 class-dump 出来的 NSMutableArray 确实差不多就是这样的结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
@interface __NSArrayM : NSMutableArray
{
unsigned long long _used;
unsigned long long _doHardRetain:1;
unsigned long long _doWeakAccess:1;
unsigned long long _size:62;
unsigned long long _hasObjects:1;
unsigned long long _hasStrongReferences:1;
unsigned long long _offset:62;
unsigned long long _mutations;
id *_list;
}
@end

去除一些与环形缓冲区不太相关的字段:

class-dump 出来的 NSMutableArray 私有数据结构(去掉了一些不相关的字段)
1
2
3
4
5
6
7
8
@interface __NSArrayM : NSMutableArray
{
id *_list; // 最重要的数据结构 -- 缓冲区的指针
unsigned long long _size; // 缓冲区大小
unsigned long long _used; // 缓冲区计数
unsigned long long _offset; // 缓冲区中第一个元素的索引
}
@end

下面我们来看看利用这几个变量设计出的环形缓冲区的基本操作

2.1 索引

环形缓冲区的索引有两种情况:

  • 一种是整个数组刚好在缓冲区中间,头尾都还有空间的情况。此时 offset + use <= size.
  • 另一种是数组已达缓冲区末尾,另一部分复用了缓冲区头部区域,此时 offset + use > size.

2.1.1 数组刚好在缓冲区中间

1
2
3
4
5
6
7
8
┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ │ │ A │ B │ C │ D │ E │ │ │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5 6 7 8

# size = 9
# use = 5
# offset = 2

比如上面这个例子,offset + use = 7 <= size (9),从而判断出整个都数组在缓冲区中间。
此时要访问数组中的元素 i,直接 list [offset + i] 就可以了。比如要访问队头元素 queue [0],就相当于访问 list [2 + 0] = list [2] = A;访问 queue [4] = list [2 + 4] = list [6] = E

2.1.2 数组复用了缓冲区头部空间

1
2
3
4
5
6
7
8
┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ D │ E │ │ │ │ │ A │ B │ C │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5 6 7 8

# size = 9
# use = 5
# offset = 6

而在上面这个例子中,offset + use = 11 > size (9),从而判断出数组已达缓冲区末尾并复用了缓冲区头部空间.
此时要访问数组中的元素 i,直接用 offset + i 就不行了,因为此索引已超出了缓冲区的大小。
值得关注的小技巧是这里一般需要对 offset + i 后的新索引取模,但是鉴于超出的部分不可以大于一个缓冲区 size 的大小,可以简单地减去缓冲区的大小即可 (既此时 (offset + i) % size == offset + i - size)。

因此,我们就需要判断 offset + i 是否大于 size, 大于的话就减去 size 得到模的部分。比如要访问队头元素 queue [0],此时 offset + i = 6 + 0 < size (9),因此相当于访问 list [6 + 0] = list [6] = A;访问 queue [4] = list [6 + 4 - 9](因为此时 offset + i > size) = list [1] = E。这看上去非常简洁、合理,多么优雅的设计啊!

写成 OC 代码如下:

objectAtIndex
1
2
3
4
5
6
7
8
9
10
11
- (id)objectAtIndex:(NSUInteger)index
{
if (_used <= index) {
goto ThrowException; // 超界
}
NSUInteger fetchOffset = _offset + index; // 就是我们上面分析的 offset + i
NSUInteger realOffset = fetchOffset - ( (_size > fetchOffset) ? 0 : _size);
return _list[realOffset];
ThrowException:
// exception throwing code
}

2.2 插入与删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
┌───┬───┬───┬───┬───┬───┐
│ A │ B │ C │ D │ │ │
└───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5
# size = 6
# use = 4
# offset = 0

--> 从头部删除元素 A ( use - 1, offset + 1 )
┌───┬───┬───┬───┬───┬───┐
│ │ B │ C │ D │ │ │
└───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5
# size = 6
# use = 3
# offset = 1

--> 从尾部删除元素 D ( use - 1 )
┌───┬───┬───┬───┬───┬───┐
│ │ B │ C │ │ │ │
└───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5
# size = 6
# use = 2
# offset = 1

--> 从头部插入元素 F ( use + 1, (offset - 1) < 0 ? (offset - 1 + size) : (offset - 1) )
┌───┬───┬───┬───┬───┬───┐
│ F │ B │ C │ │ │ │
└───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5
# size = 6
# use = 3
# offset = 0

--> 从头部插入元素 A ( use + 1, (offset - 1) < 0 ? (offset - 1 + size) : (offset - 1) )
┌───┬───┬───┬───┬───┬───┐
│ F │ B │ C │ │ │ A │
└───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5
# size = 6
# use = 4
# offset = 5

可见,环形缓冲区中数组的头插、尾插、头删、尾删,都不需要移动数组整体了,除去几个标志变量的修改忽略不计,就是 O (1) 的时间复杂度。

2.3 性能

经过上面的分析,我们基本知道了环形缓冲区的内存形态及工作方式。可以知道,头插尾插的时间复杂度为 O (1)。 但遗憾的是,数组毕竟是数组,如果在数组中间插入数据,或是我们常用的随机插入数据的情况,还是需要逐一移动后面的元素以给要插入的元素空出位置。

基于这个分析,我们写下如下测试代码:

性能评估代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//-- 头插耗时
NSMutableArray *array = [NSMutableArray array];
// 创建一个有一定规模的数组
for (int i = 0; i < 1000 * 1000; i++) {
[array addObject:@(i)];
}
// 头插耗时
CFAbsoluteTime startTime =CFAbsoluteTimeGetCurrent();
for (int i = 0; i < 1000 ; i++) {
[array insertObject:@(i) atIndex:0]; // 头插
}
CFAbsoluteTime consumeTime = (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0;
NSLog (@"头插耗时 % f ms", consumeTime);

//-- 中间插耗时
NSMutableArray *array2 = [NSMutableArray array];
// 创建一个有一定规模的数组
for (int i = 0; i < 1000 * 1000; i++) {
[array2 addObject:@(i)];
}
// 中间插耗时
startTime = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < 1000 ; i++) {
[array2 insertObject:@(i) atIndex:5 * 1000]; // 中间插耗时
}
consumeTime = (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0;
NSLog (@"中间插耗时 % f ms", consumeTime);

//-- 尾插耗时
NSMutableArray *array3 = [NSMutableArray array];
// 创建一个有一定规模的数组
for (int i = 0; i < 1000 * 1000; i++) {
[array3 addObject:@(i)];
}
// 尾插耗时
startTime = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < 1000 ; i++) {
[array3 insertObject:@(i) atIndex:array3.count]; // 尾插耗时
}
consumeTime = (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0;
NSLog (@"尾插耗时 % f ms", consumeTime);

运行上述代码,下面的输出也印证了我们的分析,中间插入耗时显高于头尾插入:

1
2
3
头插耗时:  0.023961 ms
中间插耗时: 0.724912 ms
尾插耗时: 0.025988 ms

2.4 优化

作为对环形缓冲区的分析,本文要说的基本就结束了,最后从 参考文章 1 中,我们又学到了一些 OC 中对环形缓冲区的优化操作。

2.4.1 增长因子

当缓冲区空间满了的时候,NSMutableArray 会动态地扩充自己的缓冲区大小,从 参考文章 1 中我们知道大概是 1.625

2.4.2 一旦增长,不再缩小

此外,缓冲区的空间只会增长,不会缩小。也就是即使你 remove 了其中的元素,缓冲区的大小并不会随之改变。

2.4.3 初始化容量几乎完全不重要

这个其实大多数 iOS developer 应该都知道了,就是 initWithCapacity 中指定的 Capacity 其实并没有什么卵用。

2.4.4 在删除的时候不会清除指针

这个特性挺有趣的,其实就是当我们从 NSMutableArray 中 remove 元素时,并不需要真正将之从数组移除,只要移动引用指针即可。这样可以省去清除空间的时间,但是当然,因为数组中存的是对象引用,所以 ARC 还是要隐式插入相应的 retain/release 操作。

remove 并没有清空元素的空间,只是改变了引用指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 源数组
┌───┬───┬───┬───┬───┬───┐
│ A │ B │ C │ D │ │ │
└───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5
# size = 6
# use = 4
# offset = 0

--> 从头部删除元素 A (并不需要将 A 元素当前内存清空)
┌───┬───┬───┬───┬───┬───┐
│ A │ B │ C │ D │ │ │
└───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5
# size = 6
# use = 3
# offset = 1

像上面,实际删除 A 并没将之单元清空,只是移动的 offset + 1.

3 参考

  1. 《NSMutableArray原理揭露》 - Joying Xie 本文主要参考之一,其实这是一篇译文。此文不仅仅是揭露NSMutableArray的原理,还手把手介绍了通过反编译来窥探Objective-C源码的技巧和思想,作者非常地厚道,非常地推荐。

我有一个习惯,就是我喜欢的小说,我会反复阅读。就像我以前一个室友,每隔个几天就要看一回周星驰的电影。的确,阅读经典,已经不再是品味故事而已,你能从中体会到艺术的味道。

我觉得经典的书最起码值得阅读三遍。第一遍是读其故事,一般来说,一本书就是讲一个故事,融入其中、跌宕起伏、荡气回肠,是超越电影等媒体的心灵上的体验。第二遍是读其思想,为什么要讲这个故事、这个故事为什么要这样讲、作者还想表达什么,这是一个探索的过程,如同解迷一般从作者的字里行间抽茧剥丝找到真谛。我们常说的读一本书,人生每个阶段读到不一样的东西,大致就是如此。而第三遍则全然跳出书中的故事,体会书中描写的几个人物、几处风景,就犹如是欣赏一幅名画、一件艺术品,感受的是作者的才情、气息、智慧或历练。

其实品味一幅名画,也起码得看三次,但是体验刚好与读书相反

看一幅画,你是先感觉到画面,从中体味到作者的才情、笔触、线条、色彩、阴影。第二眼,则是看出作者的思想,他要表达什么。最后,你能从画中读出故事,作者的故事或是你自己的故事、亦或是结合眼界想像到的故事。

最后,书便成了画,画便成了书,一个挂在明亮厅堂,一个挂在你内心深处。

让我们带着这样的三重体会,最后看一眼《罐头厂街》:

我们先看故事 – 书中的主要故事是一堆厂街上的经历过大萧条的颓废的人们。他们有流浪汉、有破旧小商店店主、有妓女、有生活艰难的工人。他们因为平日受了医生很多恩惠,所以决定给他办一场生日 party,就像是人们在艰难生活中一剂苦中作乐。

在那个困难的时代,这个 party 就像是黑暗夜中的一剂烟花,大家与其说是给医生过了个生日 party,不如说是给自己的一个难得的放纵、一次尽情的释放 (比如我摘录的小段中,在兴奋时自己跑去医生办公室独自跳一段踢踏舞的艾迪)。书尾最后的这次聚会让人难忘与心,医生在会上放起了优美的音乐,朗诵几首优美中带着忧伤的诗。我们看看其中的一些描写:

厨房里,医生同时用三个煎锅煎着牛排,同时切着西红柿,并把切成片的面包摞到一起。他也觉得非常愉快。麦克自告奋勇地守着点唱机,发现了一张本尼・古德曼的三重奏专辑。人们跳起了舞,聚会逐渐有了深度和活力。艾迪走进医生的办公室,跳了一段踢踏舞。医生拿了一品脱啤酒进厨房,自斟自饮,感觉越来越愉快。当他端出牛排时,大家都很吃惊。没人真觉得饿,但还是迅速就清空了盘子。
….
麦克说:“老天爷,这可太美了。让我想起一位夫人 ——” 他没再说下去。他们重新斟满酒杯,沉默不语。聚会的气氛在甜蜜的感伤中逐渐低落下去。艾迪进医生的办公室跳了阵踢踏舞,又回来坐下了。

这场架打得相当不错。海瑟绊了一跤,被人在脸上踢了两脚才重新爬起来。富兰克林牌的炉子轰隆一声倒在地上。新来的船员们被众人逼到了角落,拿起书架上沉重的书本保护自己,但还是逐渐被宾客们赶了出去。两扇前窗都碎了。阿尔弗雷德在街对面听见动静,抄起他最爱的室内球棒冲了过来,从后面发起了突袭。男人们扭打着下了楼梯,战场转移到了街对面的空地上。实验室的前门又只剩下一条铰链挂在墙上了。医生的衬衫扯掉了,瘦削而强壮的肩膀上划出了伤口,淌着血。他们刚把敌人往空地对面赶了一半,警笛响了。医生和庆祝生日的人群一起奔回实验室,把掉下的前门强行装上,刚关上屋里的灯,警车就呼啸而来。警察什么也没发现,众人坐在黑暗里喝着葡萄酒,开心地笑个不停。熊旗餐厅的姑娘们换了班,新一波姑娘气势汹汹地冲了过来。聚会终于达到了高潮。不久警察又回来了,探头看了看情况,砸了咂舌,也加入了聚会。麦克一伙坐着警车去吉米・布鲁西亚那儿买葡萄酒,结果吉米跟着他们回来了。聚会的喧哗声响彻整条罐头厂街,这是一场将暴动与保卫战所有优点集为一体的狂欢。圣佩德罗捕鱼队的船员们低调地溜了回来,受到众人的拥抱和爱戴。五条街开外的一位女士打电话报警,想抱怨噪声太吵,结果电话根本没通。警察向局里报告说警车被偷了,后来发现车在海滩上。医生盘腿坐在桌子上,微笑着,手指轻轻拍打着膝盖。麦克和菲莉斯・梅在地板上玩起了印度摔跤。凉爽的海风透过破碎的窗户吹进屋里,有人点燃了二十五英尺长的鞭炮。

快乐会传染,传染给了上门找事,然后莫名其妙打了一架的捕鱼队的船员们,传染给了上门查看问题的警察。人们在这次狂欢的聚会上尽情地喝、笑、唱、叫、打架,甚至在午夜放起了二十五英尺长的鞭炮。

斯坦贝克 写这样的一个故事,固然是因为他的心还没死,虽然也写过《人鼠之间》、《愤怒的葡萄》,但他希望人们善良慷慨、诚实、善解人意、富有同情心等品质没有缺失。人们应该思考为什么在自己的追求中丧失了这些品质:

“我一直都觉得很不可思议,” 医生说,“我们所欣赏的那些品质:善良慷慨、心胸宽广、诚实、善解人意、富有同情心 —— 在我们的系统里,这些品质往往伴随着失败。而我们为之不齿的那些品质:敏锐、贪婪、物欲、卑鄙、狂妄和自私,它们都标志着成功。人们一边欣赏前一种品质,一边追求后一种品质所带来的结果。”

最后,如果你也读过本书,你一定能很快地浮现书里的这些画面,因为他就如我所说,成了一幅幅画,已经种在我们心底了:

孤独的医生,你我是否有曾在人群拥挤中感受过同样的孤独,即便是在和姑娘亲密接触的时候;

尽管医生待人热情、有不少朋友,他仍然是个孤独而离众的人。对这一点观察得最仔细的恐怕是麦克。在人群中,医生似乎总是独自一人。当实验室亮起灯、巨大的留声机放起格林高利音乐,麦克总会从宫殿旅舍向山下张望。他知道医生带了女人回家。但麦克心里总有种可怕的感觉,觉得这景象十分孤独。麦克觉得,即便是在和姑娘亲密接触的时候,医生也是孤独的。医生是个夜行者。每晚,实验室的灯都会亮上一整夜,而白天他还是一样活跃。实验室传出音乐的时间则不分日夜。有时天色漆黑,实验室中似乎终于有睡意降临,但窗户里又会飘出西斯廷唱诗班的孩子们如钻石般完美的歌声。

罐头厂街最后的日常剪影:

罐头厂街的每个清晨都是一段颇具魔力的时光。在太阳升起、白昼来临之前,街道沐浴在银灰色的光线中,仿佛悬挂在时间长河之外。街灯灭了,野草映出一片明亮的绿色。罐头厂的波形铁板反射着铂或旧锡的珍珠色光泽。街上没有车,没有任何事情发生,也没有店铺开门。海浪在几座罐头厂之间拍打,冲刷的浪声清晰可闻。这是一段被人遗忘、专供停歇休憩的静谧时光。猫像粘稠的液体一样从篱笆上沉沉坠下,在地面上缓缓滑动,寻找剩鱼头。早起的狗一声不出,大摇大摆地走在街头,精明地挑选着小便的最佳地点。海鸥拍打着翅膀飞来,在罐头厂屋顶上肩并肩地挤成一排。霍普金斯海洋研究站附近的礁石上传来海狮如同猎犬一般的嚎叫。空气冰冷而清新。后花园里的地鼠推开新鲜潮湿的泥土钻出地面,又拖着花朵钻回洞里。在这个时间出门的人很少,衬托得街道比无人时更加荒凉。有个朵拉店里的姑娘刚赶回家——前晚的客人要么太富有,要么病得太厉害,没法亲自到熊旗餐厅来。她脸上的妆有点儿发黏,双脚疲惫不堪。李忠将垃圾桶一个一个推出来,摆到街边。中国老人从海边回来了,上坡时从宫殿边经过,松掉的鞋底拍打着地面。罐头厂的警卫向门外张望,在晨光中使劲眨着眼睛。熊旗餐厅的保镖没披外衣就走到了门外,打着哈欠伸了个懒腰,挠了挠肚子。马洛伊先生那些住在管道里的租客发出响亮的鼾声,带着管道引起的特殊回音。这是珍珠般宝贵的时刻——在夜晚与白天的交界处,时间停下脚步,审视自身。

我有一个多年好友,一次给我分享一个心路历程。大意就是其之前喜欢上一个女孩,此女孩貌似也对其有意。但之后经历了一些事,此女孩貌似对之无意了。于是他觉得很失落,觉得很失落之余又觉得无可奈何,于是便奋发学习。他说奋发学习有两个好处,一个是可以忘记伤痛,另一个是要是真学出来了,后面肯定可以找到更好的。 – 阿,人需要逃避问题!

说回《罐头厂街》,其实在写书评之时,我已读完全书了,当下我正在读 斯坦贝克的另一本 《愤怒的葡萄》。我觉得 斯坦贝克简直就是美国的余华吧(或者说余华是中国的斯坦贝克) – 《罐头厂街》就是《许三观卖血记》,都是诙谐小品但骨子里透着无耐心酸与黑色幽默。而《愤怒的葡萄》 tmd 就是美版的《活着》吧。

说回今天要分享的故事。《罐头厂街》中弗兰基与医生的故事。

医生之所谓”医生”,其实并不是真正的医生。他的真实身份应该是一家海洋生物研究所的所长,研究所主要经营各种生物(不限于海洋生物)的标本贩卖,比如买青蛙、鲨鱼、蛇、小白鼠给各大院校做实验或研究所用。但因为在罐头厂街这一片区中,他是唯一比较有学问之人,加上生物学的知识使他可以医治些小病,于是大家都称之为”医生”。

而弗兰基,是一个幼年丧父的少年,他母亲忙着结交各男友,根本不想理他(实际上也是抛弃了他)。而且因为先天的智商发育不全及缺少教养,弗兰基可谓是真正的“问题少年”。

一个偶然机会,医生收留了弗兰基:

医生给弗兰基剪了头发,除去了他身上的虱子。他去李忠店里给弗兰基买了一身工作服和一件条纹状的毛衣,弗兰基就成了他的奴隶。

注:— 我要注明下,这里的“奴隶”是个黑色幽默,其实收留一个有问题的人,难说谁是谁的“奴隶”。怕你们误会,多嘴提醒下 ^_^

但是弗兰基并不能适应正常的生活,他智商有问题,他自己也知道自己智商有问题(因为和你身边现实一样,人们总是会“善意”地提醒有问题的人 – “喂,你脑袋有问题”)。于是弗兰基是个极度自悲的小孩。

医生给他的活他一个都干不好,而只要他遇到失败、挫折,他就会钻进刨花箱里,躲在里面,半天不出来。

医生让他把龙虾归类,他努力了半天,一直做不到,钻进刨花箱里,躲在里面,半天不出来。

医生的聚会,他尝试给大家倒酒,结果酒一端出来,全洒了,他迅速地跑进地下室,整个人埋在刨花箱里,医生只能只见他在里面啜泣。

这个小故事的结局发生在某一天,弗兰基荡在街上,发现一座高贵的座钟,他发现上面的人物和医生很像,他很爱医生并想将之献给医生当礼物 – 但当然,他没钱。

于是弗兰基偷了这座钟,合情合理,偷这么大座钟马上就被人发现,并被警察捉拿。最后警察通知医生前来,于是有了下面这一段:

“弗兰基——你不该这么做。”医生说。他的心因为预想到无法避免的结果而压上了沉重的石头。“能不能让我保释他?”医生问道。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“我不认为法官会同意,”警监说,“我们有他的精神状况报告。你知道他有什么问题吧?”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“嗯,”医生说,“我知道。”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“你知道他到了青春期会是个什么样子?”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“嗯,”医生说,“我知道。”他心里的石头更沉了。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“医生认为,我们最好把他关起来。之前我们没理由抓他,但现在他犯了重罪,我觉得这是最好的选择。”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;弗兰基听着他们的对话,眼中欢喜的光芒暗淡下去。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“他偷了什么?”医生问。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“一座挺大的钟,还有一座青铜雕像。”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“我来赔。”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“哦,已经都拿回来了。我不认为法官会听你的话。这种事总会发生第二次的,你也清楚。”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“嗯,”医生说,“我知道。但也许他这么做是有理由的。”“弗兰基,”他说,“你为什么要偷东西?”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;弗兰基盯着他看了很久。“我爱你。”他说。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;医生狂奔出门,钻进汽车,跑到罗伯斯角的岩洞里去采集标本了。

阿,人就是需要逃避问题!

事实就是这样的,无论你是弗兰基,还是医生,当生活无可奈何地给你一击而你又无力反抗之时,你能做些什么呢?无论是躲进刨花箱、还是跑去采集标本、或者是一门心思努力学习、像鲁迅一样写碑帖。你可以从励志学的角度说,我们应该把心沉下来做些有意义长远有用的事。但是,人生就是需要逃避问题的。无论方式是什么,成年人,也需要一只刨花箱。

大自然中的造物者将生存的本领赠给了世间所有生灵,不管是郊狼、褐家鼠、麻雀、苍蝇还是飞蛾。对废物、污点和乞丐,他一定也怀着同样伟大而深厚的爱。

约翰・斯坦贝克(Steinbeck John)

约翰・斯坦贝克(Steinbeck John) 的得奖评价中有一个对其的称呼 – 行吟诗人。这引起了我的一个思考,究竟什么是诗人?

昨天看梁文道的一个节目,里面在讨论什么叫艺术,有一个节目的观众问之“艺术的东西这么难懂,艺术不应该是让大多数人懂得并能欣赏的东西吗?” 梁的回答是,是否是艺术和你能否懂或是否易懂没关系,这是两个概念。能启发大家的思考、带来不一样的视角、触动你去追求,那就是艺术。当然,他的原文我已记不太清,这是我添油加醋的总结。

那么我们怎么评价一位文学家为诗人呢?我认为其实不在于其辞藻的华丽、语言有多优美、描写有多细腻。而主要在于其眼光的独到、思想的深远,是否能启发你些什么。能够看到普通人看不见的东西、想不到的东西,并优雅地表达出来,此之可为诗人了吧。

想到这里,我仿佛恍然脑路顿开,怪不得顾城写下:黑夜给了我黑色的眼睛,我却用它寻找光明。这样的诗句。

那为何称斯坦贝克为行吟诗人呢?大概就是因为其视角的于众不同吧。当我们遇到流浪汉的时候,我们往往会想到第一个就是他贫穷。而“贫穷”主要指的就是物质上极其匮乏的状态,因为我们看待大多数人不可能会去思索其精神状态怎样,看人停留在表面是这个时代大家普遍的视角。而斯坦贝克能看出他们在精神层面上的富有、充实、甚至于优雅。

让我们看看他是怎样描写流浪汉麦克的:

麦克是一群男人中最年长的,是其他人的领袖兼老师,偶尔也是他们的剥削者。这群人都没有家庭,没有钱,除了食物、酒精和个人满足外也没有别的追求。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 很多人都会在追求满足的过程中毁了自己,在疲惫中半途而废,麦克这群人却不一样。他们追求满足的方式随和低调,不走极端。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 他们现在就住在李忠店外空地上巨大的生锈管道里,而天气好的时候,他们就睡在空地最高处的黑丝柏树下。黑丝柏树低垂的树枝搭成了凉棚,让人可以躺在底下,眺望罐头厂街生机勃勃的人群。

麦克那群人也同样有各自的运行轨道。他们是德行、典雅与美的化身。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在蒙特利这个匆忙疯狂、不成模样的宇宙里,为了寻找食物,恐惧饥饿的人在争夺中吃坏自己的胃;为了得到爱,缺爱的人在渴求中毁掉了自己身上所有可爱的部分。而麦克和他的同伴们就是美,就是德行,就是典雅。在这世界上,得了溃疡的老虎统治天下,严苛的公牛践踏大地,盲目的豺狼以腐肉为食。麦克和同伴们优雅地与老虎共进晚餐,爱抚狂暴的野牛,小心包起面包屑,去喂罐头厂街的海鸥。如果一个人胃里长了溃疡,前列腺也不中用了,戴着双光眼镜才能看清东西,就算赢得了全世界,对他又有什么好处?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 麦克和同伴们小心地绕过陷阱,远离监狱,避开绞索。整整一代走投无路、酒精中毒、进退维艰的男人则对他们大喊大叫,骂他们是没用的废物,说他们没有好下场,是整个城镇的污点,叫他们小偷、无赖、乞丐。大自然中的造物者将生存的本领赠给了世间所有生灵,不管是郊狼、褐家鼠、麻雀、苍蝇还是飞蛾。对废物、污点和乞丐,他一定也怀着同样伟大而深厚的爱。麦克和他的同伴们。德行和典雅,懒惰与热情。大自然中的天父啊。

当然,麦克也许只是理想中的麦克。在那个经济大萧条的年代,人们笑贫不笑娼,有把牛奶倒进河流的资本家、有颓废人生放纵甚至走向极端的破产青年。人们要保持纯真的心不容易。当然,这只是斯坦贝克的一篇小品式的小说,他只想诙谐地写几个回忆中的故事激励萧条中的大众,即使是流浪汉也能在这个动乱的社会中保持人性的纯真,所以他们是德行、典雅与美的化身,德行和典雅,懒惰与热情。

最近我刚查过——这是种非常常见的动物,经常把尾巴翘起来。但没有一本书提到它们会翘尾巴,更不用说为什么了。”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 海瑟用潮湿的网球鞋冲臭虫踢了一脚,让它翻了个个。闪亮的黑色甲虫奋力踢腿,想要翻回身来。“嗯,那你觉得是为什么?”
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “我觉得它们在祈祷。”医生说。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “什么!”海瑟震惊不已。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “真正了不起的,”医生说,“不是它们会把尾巴翘起来——真正了不起的是我们觉得这件事很了不起。我们只能将自身视作标尺。如果我们做出这样无法解释的奇特行为,我们很有可能是在祈祷——所以也许它们也是在祈祷。”

看待一些人或事时,勿以自身视作标尺,这是我今天学到的。我们永远无法知道一些人行为的用意,与其费尽脑汁去猜测,不如给之下个浪漫的定义。

罐头厂街位于加利福尼亚州的蒙特利半岛。它是一首诗,一股恶臭,一阵刺耳的噪声,一片深浅不变的光,一个音调,一种习惯,一阵思乡之情,一个梦。

Cannery Row in Monterey in California is a poem, a stink, a grating noise, a quality of light, atone, a habit, a nostalgia, a dream.

约翰・斯坦贝克(Steinbeck John)

很久以前,读了 约翰・斯坦贝克 的一本小说 《人鼠之间》。正好联想到现在中美贸易战大家对老美的看法,为啥老美现在在我们眼睛里变成 “不守信用”、“狂妄自大” 的形象呢(多半拜 特朗普 所赐)?但起码在 《人鼠之间》 里,我们能看到人性的辉光。

这激起了我了解美国现代文学的兴趣(了解下老美的人文思想),于是又顺着读了这本 《罐头厂街》。简单介绍下作者 – 1962 年诺贝尔文学奖得主 约翰・斯坦贝克

essays-note-Steinbeck

约翰・斯坦贝克(Steinbeck John,1902 年 2 月 27 日~1968 年 12 月 20 日),20 世纪美国作家。代表作品有《人鼠之间》、《愤怒的葡萄》、《月亮下去了》、《伊甸之东》、《烦恼的冬天》等。

1937 年发表小说《人鼠之间》,1939 年出版小说《愤怒的葡萄》。1962 年获得诺贝尔文学奖。

1968 年 5 月,他的身体开始垮下来,1968 年 12 月 21 日,他因心脏病发作逝世。

《罐头厂街》 简单来说是一篇中短篇幅的小说,故事发生在二次世界大战前,加利福尼亚洲(State of California) 的一个海湾城市 –蒙特利县 (Monterey)(也有译为蒙特里、蒙特雷)。

首先我们必须要了解一下,这个故事发生的背景是发生在世界大战之前,美国的一个经济萧条的时期(20 世纪二三十年代,美国经济大萧条 The Great Depression)。故事发生的地点这个蒙特利海湾,以前曾经有一个沙丁鱼罐头厂,曾经经历过一个辉煌的发展时期。那么在经济萧条时,可想而知,当地的人们的生活状态应该是受到了很大的改变。

在这么一个前提下,罐头厂街,也就是靠近罐头厂的一角街景,一块空地、一个杂货铺、一间妓院、一个海洋研究所,在这么一角破旧的区域发生的故事。作者在这个布景下构建了他回忆中的这个故事,这是一个既真实又理想的生活,肮脏、美好、又甜蜜。人们的生活简单、虽没理想但有欲望,不被金钱所腐蚀、为人真诚。

有了这个前提,我们就可以理解作者在开头的这一段话了,为什么在他的记忆中,罐头厂街这片区域既是一首诗又是一股恶臭;既是一阵刺耳的噪声,又是一个音调,一种习惯。

我听过阿城还是蔡澜 (记不清到底是谁也无从考究了 - -!),讲了关于回忆的故事。就是往对往事的回忆,虽然以前的经历不一定都是美好的,但是回忆起来,总是有味道的。他就说当初他写作或者奋斗过的地方,旁边是个菜市场。所以每天写作的时候就闻到那个菜市场的烂菜帮子味。致使现在只要一闻到烂菜帮子味,就会忆起当时自己写作的那个地方,回忆起当时工作的那个情景。虽然那气味不是什么好闻的气味,生活也很枯燥,但是却是一个美好的回忆,就像作者写的一样,是一首诗、一个甜蜜的梦。

那么怎样把这些回忆中的故事记录下来呢?你不该带着当前眼下的思想偏见,也不该带着对过去过多的粉饰,真诚地写下来,让我们欣赏下作者是如何说的:

怎样才能鲜活地描绘出那缕诗意,那股恶臭,那阵刺耳的噪声 —— 还有光线的质地,音色,习惯和梦?采集海洋动物标本的时候,有些扁虫一碰就碎,脆弱得几乎不可能保存完整。你只能凑近一把小刀,让它们自己扭动着爬上来,再小心地移入装满海水的瓶子。也许这本书也该以同样的方式来写 —— 展平书页,让故事自己爬进来。

And perhaps that might be the way to write this book – to open the page and to let the stories crawl in by themselve.

约翰・斯坦贝克(Steinbeck John)

0%