用算法来规划行动

老生常谈且不靠谱的新年计划

新年立志虽然相当的不靠谱,但立几个又何妨,反正2017年已经来了!所以在2016年的最后一晚就给自己订了个计划,其中之一是坚持每周写一篇blog。但是2017年第一周刚刚过完,我的2017 No. 1 blog却只有半个影子。实实在在地给“一周后1/4的人会放弃”的统计结论又添加了一个佐证。

当初订好计划后随意从长长的todo list中挑选了一个感兴趣的议题:手工解析AES加密算法的流程。只是从2号起出差至北京以来不少事务等等等等均成了拖延的最好理由。好在当初计划制定的不严谨,作为程序员的本能总能找出其中漏洞,比如“写一篇blog”并不表示一定要写技术相关的,再者即使写技术相关的也不一定要写类似“解析AES算法”这样苦逼的赃又累的技术活。妥协谁不会!?

不过还是好奇探究了一下相关的统计:显示只有约8%的人会坚持到1年,这些坚持下来的牛人之所以在能立于牛A与牛C之间,原因就是他们不妥协。

扎克伯格的新年计划

小扎的一举一动都有轰动效应,每年伊始他所公布的新年计划都是头条中的头条:

2009年挑战每天戴领带上班 2010年挑战学习汉语2011年挑战只吃自己亲手屠宰的动物 2012年挑战每天写代码 2013年挑战每天跟除脸书员工之外的不同的人见面 2014年挑战每天写封感谢信 2015年挑战每个月读两本书 2016年挑战开发一款私人专属人工智能助手以及全年跑步365英里(587KM)

这些计划看起来都非常的“扎克伯格”,有一篇写他的文章说的一针见血,让我兴奋了好一阵子,其标题就解释了扎克伯格为什么能成为“扎克伯格”的原因:扎克伯格:真正决定人生高度的,是你做事的速度决定你人生高度的从来不是做事的完美程度,而是做事的速度 做事的速度 做事的速度。当下就是最好的时机,下一秒、下下一秒、或下下下一秒就已经晚了。

你的动能决定了你所能冲击的高度。动作越快,动能越大,就在你出发的那一刻,你所能冲击的高度便已确定!

用算法来规划行动

妥协者最好的借口莫过于“三思而后行”,然后又用急性子的常犯的错误来反证自己的正确,比如:急急忙忙写了一行代码,结果却引入了若干个新Bug,之后再花几天时间解决掉这些Bug,虽然全是“无用功”,可不也是顿觉成就感爆棚,不也是KPI亮闪闪的程序<折腾>人生?

万维钢老师在《精英日课》第64期中提到过一个有趣的结论:将37%期限的时间专门用来各种纠结与横纵向比较,当37%的时限一过就马上决定,然后依决定采取行动!

这是《Algorithms to Live By: The Computer Science of Human Decisions》一书中所给出的答案!

要成为一个理性的人,要在一个不确定的世界中做到尽量好,就要遵循这样的规则,给自己一个适当的纠结期,纠结期一过马上就做决定。只有行动才能有结果,只有快速行动才能争取到有利的位置和修正错误的机会。

参考链接

  1. Mark Zuckerberg on Facebook截图
  2. 扎克伯格公布2017新年计划
  3. 看看扎克伯格历年来的“新年计划”
  4. 扎克伯格:真正决定人生高度的,是你做事的速度
  5. 万维钢:今天你立志了没
  6. 万维钢:数学家告诉你什么时候结束单身
  7. Marlkdown语法介绍

<第一次用Markdown文法写文章,边写边查语法,再加上查验及组织资料等,这篇短小的blog竟然用了2个多小时的时间!>

Continue reading » · Written on: 01-09-17 · No Comments »

括苍之巅-柴古唐斯越野记

这是最好的比赛,这是最坏的比赛;
这是智慧的决定,这是愚蠢的决定;
这是信仰的时刻,这是怀疑的时刻;
这是光明的一天,这是黑暗的一天;
这是希望之水,这是绝望之山;
人们面前绵延青山接连天际,
人们面前白雾阻隔咫尺难见;
人们正在直登天堂;人们正在直下地狱。

总之,那时印象分明就是眼前,喧嚣着的如潮水的人群,无聊至极的一般疯子,个个脸上洋溢着电光一样的兴奋和一发不可收的癫狂。说它好,越野就是有这般魔力;说它不好,所有的人已经着了它的魔。

---- 新的一天从找不到起点开始!

想当然的就以为出发点就是公园边上的城门(实为崇和门),就是没有提前查看下出发点,就是不愿停下来确认轨迹,就是不愿去取藏在背包深处的手机,就愿意相信和一位交流都不通畅的老外所认准的他老婆在微信上共享的一个小点,就是乐意和着人流狂奔,从崇和门奔到最西边的望江门,然后又沿城墙外奔到最南边的兴善门。就是对此类的偷懒没辙!

一路上边跑边问,结果路人包括出租司机竟没有一个知道兴善门的。等到我跑到起点,离发枪已经5分钟了,大部队早已没了踪影。在我连闯三个临海古城门的时候,乾昌和茂飞大概正在愉快的拍照和把妹吧,叹好机会总是一去不复还!

以最快的速度寄好装备、芯片检录,顺着赛会的旗帜快跑,这时后面传来一声吆喝,原来是另外一位没找对门的跑友,还是台州本地的,我们边笑边跑边聊,一路上没有看到志愿者和其他队员,心存怀疑但没有停下脚步,直到看到了亲爱的志愿者们,心里的石头才算放下。小跑一会,追上了正慢走等我的乾昌和茂飞,兄弟见面格外亲切。真基情才是好基友!

----  这只是一场和关门时间的赛跑!

SP(兴善门)-CP2(兰辽农场) 21KM 海拔:+1200/-400 用时:3:42

从古城墙下来跑没多远,便进入山野小径,连续的上坡,此时刚开始已然有些乏力感,好在人流拥挤,道路湿滑,大部队只能蛇形蜿蜒慢行,我倒是得以缓口气。想着这几个月一直在出差忙工作,没能系统训练,不免有些担心。担心也罢,只得硬着头皮,以自己最适宜的节奏匀速行进,不特意去跟茂飞和乾昌他们,逐渐和他们渐行渐远。后面的路还很长,我跑的还算是比较耐心,因为自己清楚自己不仅仅输在了起跑线上,而是起跑之前的训练,现在最重要的是保持节奏。

然而就在离CP2兰辽农场还有约5公里的地方,后面有人赶上来催促大家快点,说CP2的关门时间马上就到,我看表已是9:10,离关门时间9:50还只有40分钟,还不知后面这5公里是怎样的路况。跑了这么多次比赛还是头一遭碰到马上被关的情形,目前的速度其实并不慢,但还是不够快。之后又听到解释说主办方特意收紧前几个检查点的关门时间就是为了最大化的刷掉能力弱的队员,因为后面的爬升和夜跑更多更难更险。难不成这么快就被刷下去了!?

此时已管不得节奏,只专注于地面路况和前面人的脚跟,翻过一个石头又一个石头,越过一个人又一个人,整队伍的人都在拼,开始基本全是平路或缓坡,然后就是一路下降,但下坡路上全是杂乱的大石头和在石头上龟行的拥堵的人群,我择机从右侧的石头堆上飞过,走到人群的空档,然后一跑飞奔直降CP2兰辽农场,看时间正好9:50。至打卡处得知关门时间是10点。见到了乾昌和茂飞,三人嘴不停手不停边吃边拿,回望慌乱的人群不断的向检查点涌来,有点幸灾乐祸,心想这一关总算过了。

20160416-柴古-31199814120270419120160416-柴古-22718329911458752420160416-柴古-cp3

CP2(兰辽农场)-CP3(上白岩村) 8KM 海拔:+490/-500 用时:1:54

CP2过得不容易,CP2-CP3这段算是此行最容易的一站,像是暴风骤雨前的片刻平静,因为后面的路只会越来越虐。CP2出发后,一路上紧跟乾昌和茂飞,路上下了阵急雨,鞋上全是泥,越走越重,比较辛苦。约11:45左右到达CP3,此时到关门时间也仅仅提前了15分钟。

此站是30KM的终点,人声鼎沸,全是欢乐的声音,好幸福!只是对我们跑82KM的来说行程刚刚过了1/3。

CP3(上白岩村)-CP4(盆化寮) 6KM 海拔:+530/-180 用时:1:40

30KM的人撤离之后路上的拥堵状况马上就好转了,只是中午是我传统的最差状态时间段,特别是吃了一肚子香蕉和一碗稠粥之后,上坡路段更是抬不动腿了,右大腿肌肉感觉明显乏力。和茂飞及乾昌的距离越走越远,我索性不着急了,不紧不慢按节奏走,边走边调整状态。60KM收队的老伯则健步如飞地从我后面赶超,边走边聊,拿着对讲乱呼一通,让我好不气恼,自叹不如。没想到的是,此老伯竟一路跟到了CP6,直到CP6出发不久才终于将他老人家给甩开。

因为道路塌方,CP4调整了位置,补给较少,只有冷食、凉开水,加上天气又转恶劣,开始刮风下雨,冷风吹身上不禁要打寒颤。简单补给后和好兄弟茂飞乾昌又开始下了下一站的征程。

CP4(盆化寮)-CP5(黄家寮) 12KM 海拔:+500/-1000 用时:3:15

20160416-柴古-spyuq5at8453tyb9j0rhtj1ysp33ow2920160416-柴古-nrgjofds0o8t1emi40ynh9ew4yvz33di

出发后就是缓慢上升,好在上升路段主要集中在前面,后面和60KM的线路分道后则是一路下降,一路上没就见其他人,我跑的倒也相当惬意,状态逐渐回升中,不过茂飞和乾昌状态更好,茂飞竟然说跑到现在还没有感觉,而我感觉已经残废了一半,太打击人了,遂劝他们先走,我在后面正好可以悠哉悠哉。最后1/3的路段基本沿溪流走,一会左一会右,要不断穿过溪流。在第一个过溪点看到了绳子,应该是主办方所说的要溯溪的地方,我索性脱了鞋子在冷水中泡了一会腿,感觉相当棒。晾脚的时候后来终于跟上来三人小团队,聊谈得知他们从徐州来,想到同是徐州人的老渔民正在跑江南60KM,不知怎样了。和徐州小团队共走了一段路,直到快CP5时才分开,我先行一步到达CP5,茂飞乾昌也刚到没多久。

天马上要黑了,CP5点开始检查装备,将所有的东西都掏了出来,检查完毕后又塞回去,费了不少时间。CP5有热面条,吃的相当惬意,味口相当好,吃完面又喝了一碗热汤,刚刚好,正准备出发,没想到此时丹丹到了,正赶在关门时间之前,乾昌正开吃,大家遂决定等等一起出发。等了一会身体有些发冷,又吃了一碗热面条,绝对吃撑了。

CP5停留了30多分钟,以至后来的时间相当紧张,差点被关门。

CP5(黄家寮)-CP6(跑马坪) 10KM 海拔:+1200/-600 用时:4:15

这段路可谓是最绝望的一段,出发后就是艰难的上升,我们三人陪丹丹走了一段,然后便快步先行,走了一段根本不是路的路,先是在圆木堆上走平衡,然后又在横七竖八的树阵里走梅花桩,叹主办方这样为虐而虐的路线设计,又遐想闫龙飞跑到这里时皱起眉头的样子(到终点后才行知闫大神因为伤病没来跑柴古)。梅花桩虽然难走但并不费力,后面却是耗尽体力的艰难爬升,我在心里数着自己的呼吸,从0到100不断循环往复,终于达成这段不间断的海拔上升,可等到我们终于爬到山顶才发现前面还有座更高更黑更恐怖的山头在等我们,上面零星有头灯的灯光闪烁着光环,像梦境,像幻觉,但冰冷的现实又将我们拉了回来,饥饿感与疲倦感阵阵袭来,我和茂飞坐着休息了会,吃了个能量胶,这是此行我第一次吃自己带的补给,也是仅有一次。休息的时候,乾昌上来后没有停留继续上山,看起来体能还相当好;收队的老伯吵着他的对讲也走了过去,后面紧跟着还有一队的人马。我和茂飞休息一会后继续赶路,然后听到前方有人喊“前面是平路了”,终于不用下降了,我俩像打了鸡血,一阵加速跑,就好像前面有金子要抢似的。

走得已经麻木了,关门时间马上就到,我觉得时间已经不够了,茂飞问我要不要跑一跑,但我实在跑不起来,特别像这种漫长上坡,快步走都觉得腿部力量有些不支。被关门倒也是个最好的解脱,真的不想再走了,也走不动了。思想的扰动开始跳跃,但脚步并没有停,还是艰难地一步步迈向前方,还在不断地赶超,只是越走越累,越走越绝望。对面有志愿者走过来,说还有1公里,但远处闪烁的头灯让我觉得他说只有1公里真是荒唐的可笑,分别还有“10公里”的距离。

走着走着,前面的一个人给我让路让我先行,我对他说了句“加油,马上就到”之后,忽然觉得脚步一阵轻松,又开始健步如飞,状态回来了?!一阵急步,看到了高处的影子原是风力发电机的高塔,隐约听到了远处传来的嘈杂的人声,很快望见了CP6的灯光,我又飞起来了!

21:30:我手表上显示的时间,工作人员正给我打卡,正好是关门时间,赶上了,TNND,终于赶上了!

CP6(跑马坪)-CP7(米筛浪) 4KM 海拔:+270/-150 用时:0:55

喝了一碗热面条后,帮茂飞整理水袋,忙中出错,搞了好一会子才搞定,此时丹丹也上来了,但因为晚了5分钟多被关了,但她还是决定继续走完全程。出发时已是21:38,到CP7的时间已经相当紧张,但越是时间紧张却越是出各种岔子。天空非常黑,伸手辨不出五指,头灯发出的昏昏的光只能勉强照亮脚前的方圆之地,根本看不到路边红色的路标布条,只能凭着感觉走,来回了几趟以确认路线,耽误了不少时间,后来前面又传来路线不对的喊声,我跑过去又跑回来找路。此时收队的老伯又上来了,肯定的确认路线是对的,原来是风将挡住岔路的信标吹开了,正好挡住了正路,让我们不知可否了好一阵子。

我径直冲到了最前面,钻入丛林,上窜下窜,左转右绕,进入无人之境,心无旁骛,眼中只有脚下的路,远处移动的光点和主办方放置的闪烁的青蛙灯就是我的方向,向前,向前,再向前;快,快,更快!

远远的听到喊加油的声音,还看到有照向天空的光柱,CP7应该快到了,希望就在前方。

22:27分终于到达CP7,志愿者一边给我打卡一边说我这提前的3分钟太值了!82KM组为安全调整了后面的路线,不走原计划的20公里,直接走完60KM组的10公里到终点即可完赛。

CP7(米筛浪)-EP(南岙村) 10KM 海拔:+50/-1400 用时:2:08

得知后面的路线基本全是下降,并且只有10公里,基本放下心来,确定顺利完赛不是问题,并且状态正酣。在休息点喝了点热水,未做过长停留,和一行人一起出发。没多久,乾昌等三人说没有看到路标折返了,大家一同确认路线无误后继续下山。部分路段路标间隔较大,好在岔路不多并且主要是横切公路下山。4公里后开始看到青蛙灯,确认路线没有问题,和后面的队友逐渐拉开距离。台阶路相当湿滑,不小心曾屁降一次,路况基本可控,下坡和认路都是我的强项,一路飞奔,没想到前面还有不少82KM的队员,零零闪闪,有人脚伤走的比较慢,有的队伍边聊边走,大家看到我都不约而同的让路,让我好生感激,简单寒暄后便分道扬镳。

下山的8公里路感觉特长,一路下降,总也走不到头。等下到公路后一阵喜悦,心中想马上就到了,但2公里的公路跑起来并不短,虽然临近村子有路灯,但路标难辨,据后面的志愿者说路标被人给拆了,我一边嘀咕着一边慢跑,直接看到志愿者,志愿者,真亲人呀!还记得我沿马路拐过弯跑到快到终点的马路上时,在前方很远的一位志愿者就开始大喊加油,并挥舞着手中的闪光棒,好似比我还要激动的样子!感谢你们,真心感谢你们,是你们让这场比赛更精彩,是你们让这场超马更圆满!

00:43,冲线!比赛结束!感觉真好!

感谢茂飞和乾昌的一路陪伴和鼓励,感谢辛勤的志愿者们,感谢主办方搞了一场让人难忘而又觉得遗憾的越野赛事。

装备小结

随身穿戴:

1,空顶跑步帽 (的卡侬)
2,快干T恤 (NIKE DRI-FIT)
3,快干7分裤 (NIKE)
4,小腿压缩护套 (ZAMST)
5, 五指加厚运动袜 (injinji)
6,越野跑鞋 (LASPORTIVA MUTANT)
7,越野包 (ULTIMATE DIRECTION AK 2.0 Race Vest)
8,登山杖(BD Z-POLES 112177)
9,全指手套
10,头灯(BD Spot, Fenix HL60R)
11,轻量冲锋衣(TNF)
12,Sunnto AMBIT(心率带+FootPod)
13,头巾(扎手腕上,擦鼻涕专用,哈哈)

食品:

1,能量胶8个(吃2个)
2,盐丸10个(约每7公里一个,共吃了7个,晚上没吃)
3,MoveFree 2片(赛前吃)
4,水2瓶

备用物品:

1,SKINS S400保暖衣一身
2,简易雨衣
3,口哨、现金、纸巾
4,创可贴,红霉素药膏,纱布,包扎带
5,全指手套(备份)
6,急救毯
7, 手机及密封袋

经验检讨

1,对比赛线路基本没研究,关门时间、路况等一点概念都没有
2,未提前探明起点,以致第二天误点,并且多跑了4公里的路,白耗体力
3,头灯电池电量不足,新买的Fenix HL60R未充电(好在撑过了最难走的一段),
     BD头灯放包里被按压误开以致晚上使用时亮度不够
4,检查点的休息时间过长,以致后面时间过于紧张
5,赛后才发现错过了检查点的好多好吃的 :)

20160416-柴古-68758342399766806720160416-柴古证书20160416-柴古成绩

 

The best way out is always through !
     ---- by Robert Frost

Continue reading » · Written on: 04-20-16 · 2 Comments »

南京山地马拉松

去年跑过一次,今天再次参加,本次成绩为458,比去年的520快了20多分钟。从2月到3月一直没有系统训练,工作出差等严重打乱了训练计划,体力储备不够以致最后3公里两腿肌肉抽筋,只得以走走、停停、跑跑的节奏完赛。

certs_owycfpkcswrbpgb920160325-南京山地

和美女冠军东丽合影等待发枪国学队合影

Continue reading » · Written on: 03-27-16 · 1 Comment »

ERESOURCE加锁函数

最常用的加锁函数只有两个:

  • ExAcquireResourceExclusiveLite:试图获取排它锁
  • ExAcquireResourceSharedLite:试图获取共享锁

除此之外,针对共享锁的获取,还有另外两个函数:

  • ExAcquireSharedStarveExclusive:可以早于等待中的排它请求者
  • ExAcquireSharedWaitForExclusive:不能早于排它的请求者

二者都是试图获取共享锁,和ExAcquireResourceSharedLite只是有些微的小差别。但这两个函数使用的并不多,只限于少见的特殊情况:

ERESOURCE本身是可以重入的,如果当前线程已经获得此锁的话,若再次试图获取,ExAcquireResourceSharedLite将会直接准予此请求,但ExAcquireSharedWaitForExclusive则不会,一定要等到此锁等待列表中所有的排它锁的请求者完成之后才会准予当前调用者。当然如果当前线程之前所获得的ERESOURCE锁是排它锁的话,将会直接准予通行,不然会导致死锁发生。

ExAcquireSharedStarveExclusiveExAcquireResourceSharedLite的差别只在一点:若已是共享锁状态,ExAcquireSharedStarveExclusive将忽略排它锁等待列表中的所有请求者,直接准予当前线程,以尽可能的减少当前线程的等待时间。

Continue reading » · Written on: 02-25-16 · No Comments »

KEVENT,ERESOURCE及Thread Boost

在唤醒KEVENT时,函数KeSetEvent的第二个参数(KPRIORITY Increment)是用来临时提高被唤醒线程的调试优先级的,此举可以让睡眠在此KEVENT上的线程尽快得到处理以提高系统整体性能。

同样ERESOURCE也有类似的机制,在放锁时也会调高等待列表中处于饥饿状态的线程的优先级。

不过除此之外,ERESOURCE还有一种反向的Boost机制,即让等待者在试图获取锁时调高此锁当前拥有者线程的调度优先级,以加快属主线程的处理并尽可能早的释放锁资源。

反向操作却有可能遭遇这样一个问题:作为锁拥有者的线程未必是同步的,很有可能在获取ERESOURCE锁之后就因为异步处理事件(如Workitem,异步I/O请求)在不释放锁的情况下就退出(锁的释放将由异步事件来做),在此情况下ERESOURCE的属主线程指针就变成非法的了。为此Windows内核提供了一种机制来阻止问题的发生:线程等结构体一般都是至少8字节对齐的(最后3位均为0),通过将最后两位设为1的方式(|0x03)来甄别此指针数据是用户自己所指定的还是默认的系统线程,以此来避免访问已经释放的内存。

从Win7之后,FastFat及Ntfs都有对ERESOURCE的OwnerThread的处理,主要是异步的Noncached i/o事件的处理,其目的就是处理线程在获取ERESOURCE之后退出的情况。

Continue reading » · Written on: 02-25-16 · No Comments »

FastMutex的陷阱

相对ERESOURCE来说,FastMutex的使用比较方便,不用考虑禁APC问题,也不用考虑FastMutex结构体的释放,用完即可以三不管。对于竞争不激烈且读写不明显的情况下,用FastMutex还是不错的。

不过使用过程中要注意其隐藏的陷阱:

1,ExAcquireFastMutex 会提升IRQL至APC_LEVEL,且保存原来的IRQL用以在ExReleaseFastMutex时恢复。所以在嵌套获取FastMutex时要特别注意放锁一定要依加锁顺序反向操作,不然会导致IRQL紊乱。为此系统特别提供了Unsafe操作函数(ExAcquireFastMutexUnsafe及ExReleaseFastMutexUnsafe),这两个函数不会操作IRQL,但使用上却有前提条件。

2,FastMutex的实现是通过原子锁与Gate对象来实现的,在没有竞争的情况下,通过原子锁可以速实现加锁及解锁,此外Gate对象是不可重入的,不像Event等(Dispatch Object)及ERESOURCE等可重入的锁(同一个线程可以同时加锁多次不会死锁)。

至于FastMutex为什么要提升IRQL至APC_LEVEL的原因,和文件系统调用FsRtlEnterFileSystem禁APC的原因是一样的,直接目的是防止当前线程被挂起(Suspend)。设想在没有禁止APC的情况下调用ExAcquireFastMutexUnsafe加锁之后线程随时可能被挂起,一旦被挂起的话系统中试图获取该锁的其它线程则只能等待,不管此线程是否高优先级或关键的系统任务。同理可以理解Event,ERESOURCE等为什么也需要禁止APC的原因。

除了FastMutex之外,Windows内核还实现了另外两种Mutex: Regular Mutex及Guarded Mutex。不过从Windows 8开始,GuardedMutext和FastMutex的实现是一样的,二者并无差别。Regular Mutex通过KeInitializeMutex初始化,加锁及放锁是通过KeWaitForXXXObject及KeReleaseMutex来操作的。我们知道 Event也是通过KeWaitForXXXObject来加锁的,但是Regular Mutex的加锁操作却会禁止当前线程的Kernel APC,Event却不会,所以在操作Event之前要显示地进入临界区或禁止APC操作以防止可能的死锁发生。

需要注意的是禁止Kernel APC并不会影响i/o操作,但是FastMutex及GauardedMutex不止是禁止Kernel APC,还会禁止Special APC,这样的话i/o操作是不允许的,因为i/o完成例程是在Special APC中做的。这些细微差别在使用中必须考虑到。

Continue reading » · Written on: 02-17-16 · No Comments »