其实读高中时就知道人生大概只有3万多天，那个时候还算了下1万天的时候大概是多少岁，当时算出来是27岁多，就想着还真的有蛮远的哈哈哈，没想到这一天已经在今天抵达。两年前公司入职培训的时候，认识了一个生日只差一天的朋友，当时想的真的是很巧啊。于是后面每年就变成了我先祝她生日快乐，然后她祝我生日快乐。昨天大年初一的时候，在清一色的拜年祝福朋友圈里，看到了她也来地球1万天了，心想这个日子还是挺吉利的，那么我就是明天了[偷笑]。关于今天的话，其实也就是待在春节假期中待在奶奶家的普通一天。中午来了我爸的两个初中同学来拜年，听着他们聊公司业务聊了半天就悄悄跑去睡觉了。晚上的话在家给爸妈测了血压，爸爸的血压控制的还可以，妈妈则是正常水平，我的话高压只有110哈哈哈，看来休息时压力还是小很多啊，之前体检经常测出120和130的。要说最近几年做的最正确的一个决定，就是没有待在学校里读博了。之前一个端午节在奶奶家的时候，奶奶问我：怎么不跟着你们导师读个博士，和舅舅一样在大学里当教授呢？我说：现在读博士的时间很长，说不定要4-5年，出来后也要和别人在学校里竞聘岗位，说不定到30多了连个编制也没有。奶奶惊叹：读了博士也没有编制啊，那还是算了。（说完后我们全家都笑了哈哈哈哈）其实之前有段时间还有读博这个想法的，但是跟着同学一起去实习之后彻底打消了这个念头，因为企业里面工作的反馈真的很适合我，能明显感受到自己的成长。不像做研究一样，费很久时间还不能确定一个结果。其实那个时候我们导师拿到优青跳槽到了清华，那边的团队其实很好，他也问了我们同门有没有想去读的。其实对于想读的同学来说，要拒绝这样一个机会是很难的，毕竟那里的光环很大，要是和高中生说这个事情，估计做梦都要笑醒。没想到我们4个同学都委婉含蓄地拒绝了他哈哈哈。毕竟我们知道去了之后也是得自学成才，读研真的读累了。而且当时也在实验室里看到了不少负面案例，比如我们大师兄读了8年才毕业，身体还积累了不少病[允悲]，好在最后毕业了换了个好点的学校当老师。到企业里上班虽然也有比较蛋疼的时候，但是休息时间是完全属于自己的，基本不用想着上班的事。不像在学校里，总是待在一个环境氛围里。还记得那个时候发的微博，吐槽的占比占了很多，一些小的事情都容易让人自闭。现在想想这些坏情绪也许是当时疫情，和老朋友的交往受限，各方面负面因素叠加导致的。好在，现在是生活得越来越开心了[偷笑]又写了不少了哈哈哈，那就祝自己活出真我，在未来的两万天不设边界地探索世界和人生
自从2018年第一次来到校本部绿树成荫的民主楼前时，我的生活便与中南紧紧交织在了一起。要说到与中南的缘分，我想最早可以追溯到读高中的时候。当时的我们还在讨论着以后要去哪所城市读哪所大学。我当时心想，一定要读一个离家不远而且还不错的大学，正好省会长沙就有很多所，可是国防科大分数太高，湖南大学就在岳麓山下太过熟悉，还有个中南大学听上去名声比较响亮，要不就选它吧。于是，中南便成为了我高中时期埋藏于心底的奋斗目标。尽管由于种种原因，我在高考时与中南失之交臂。幸运的是，我凭借着保研的机会再次来到了中南的怀抱，开始了短暂而又漫长的读研时光。2018年的时候，计算机学院还叫信息学院，我也还在读大四。未来的导师建议我提前过来熟悉环境，于是每周都要到赶到中南的实验室过来学习。那个时候的地铁还没有3/4号线，从长沙另一端奔波而来的我尝试过了各种交通路线，最后发现还是换乘立珊专线比较快，无论是多么复杂的交通情况，司机们总是能飞速驶过，直达终点站。尽管很早以前就知道，中南不仅校区很多而且校园面积也很大，但是我不知道的是每一个校区都有这么大。每次从校本部门口的中南大学站经过清水路和升华大道走到升华楼前，都需要耗费二十分钟左右。在经历了漫长的奔波之后，抵达实验室的我只能勉强打起精神开始一天的科研探索。熟悉了情况之后我才发现，几乎每个人都有电动车，而且在路上经常能看见电动车上坐着一对情侣，然后从我身边呼啸而过，也许这就是中南最常见的秀恩爱方式。所幸实验室的同学告诉我，校门口旁边有学校运营的观光车，只用1块钱便能从校门口坐到学校里面来。这样，我就可以一边欣赏校园风光，一边慢悠悠地抵达实验室。还记得研一的时候，一切都是那么新鲜，新认识的老师、同学、室友和师兄师姐，慢慢地加入了我们的生活，在平凡的日子中增添了许多趣味。读研的生活和本科还是区别很大，本科中最看重的课程成绩在现在无足轻重。下课铃响之后，也不能和同学想去哪就去哪玩，而是得回到实验室开始一天的实验。当时的我们虽然说科研水平不算高，但是每个人都有着冲击顶级会议的梦想。除了学术研究以外，老师们还与很多公司开展了项目合作。于是我们每天都得在许多并行的任务中快速切换，恨不得分出三个身来各自负责一部分。实验室的楼道里，有着一个出水速度很快的饮水机，只需要接上电线和自来水管，它就能够以过滤的方式源源不断的生产纯净水。饮水机的旁边便是一个圆形的玻璃桌，其周围还环绕着几个塑料靠椅。每天过去打水的时候，简单的和同学聊一下日常生活，便是我们一天当中来之不易的休闲时间。在饮水机旁边的房间里还有着一个乒乓球桌，每当晚上吃完饭后，小小的空间里总是人声鼎沸，挤满了过来切磋球技的同学们。当时有两个师兄水平很高，我们每次和他们打几个球就被虐杀了，只剩下他们两个在球桌上高手过招。快乐的时光总是过得很快，很快就到了放寒假的时候。还记得当时已经快到了小年，学校里的同学已经寥寥无几，食堂也只剩下最后一个五食堂还在营业。依稀记得当时已经传出来了一些疫情的消息，但是大家都没有太过重视。直到实验室的同学坐高铁回家路过武汉的时候，发现从武汉上车的人全部都戴着口罩。后知后觉的我们听到了这个消息之后，终于意识到这次疫情很有可能改变我们未来一段时间的生活。在家里度过的漫长时间里，开学的时间一再被推迟，直到最后才确定了只有毕业生这个学期才返校，其他的年级全部改为线上课程。那时我终于才发现，原来我们在中南度过的每个平凡的日常，都是一连串发生的奇迹。平时吃腻了的三五食堂，车水马龙的升华大道，还有和蔼可亲的宿管阿姨，都这样悄然无息的远离了我们的生活。经过了整整一个学期的线上教学之后，我们终于回到了朝思暮想的中南，看见许久不见的老师和同学们，大家地脸上都情不自禁地露出了灿烂的笑容。到了研二之后，所有的课程都已经结束，我们每天再也不用在校园中来回奔跑，而是开始重复略为乏味的实验室生活。研二除了完成最为重要的开题报告以外，我还担任了我们老师C++课程的助教。助教的任务其实也还算简单，主要就是在实验课的时候帮大二的同学答疑解惑，其次就是收集作业，以及检查课程设计。以前读本科时，一直都不知道为什么老师会这么厉害，一下就能看出我们作业中的问题。直到当了助教之后，我才知道这一切都是经验的积累。两个班的同学虽然都在一起学习，但是大家的编程水平还是参差不齐。看到一些投机取巧的同学解释不清楚实验报告时的样子，我总会回想到我们本科时也是这样试图蒙混过关的。这个时候除了在心中偷笑一下，我也会告诉他们下不为例，除了上课的时间之外，课后也要花些时间学习。转眼间，就来到了研三，许多同学暑假都去公司参加了实习，以便为这个学期开始的秋招做好准备。实习和秋招的过程，便是我们与社会接触最为广泛的一段时间。尽管疫情还没有离我们远去，但是2021年的经济发展还算顺利，大部分同学都找到了自己喜欢的工作，也有些同学决定继续读博深造，无论大家的选择如何，我都希望他们能够前程似锦。回过神来，一下就到了待在中南的最后一个学期，我们三年的研究最后都要汇聚在一篇学位论文中。撰写论文的时候我才发现，校本部最为热闹的时候是晚上10点。这个时候，不仅许多同学骑着电动车从实验室返回宿舍，操场上也满是正在慢跑的同学。正是这些起早贪黑的身影，不断鞭策着我要抓紧时间完成论文。写论文的过程尽管十分困难，但是完成之后的成就感却是无与伦比的。老师也告诉我们，如果以后不读博士的话，硕士论文大概是我们人生中最为重要的一篇著作了。为此，我们不得不精益求精地完成论文的每一个段落。在初中的某一节英语课上，英语老师问及到大家未来的梦想是什么，轮到我时我不假思索地站起来就说到：“I want to be a computer scientist”，当时可能也只是随口一说，但是没想到我未来却与计算机专业结下了这么深厚的缘分。在科学前沿漫步了三年之后，尽管离我当初成为计算机科学家的理想还挺遥远，但是我有幸在各种项目中受到了系统的科研训练，并且深入体会到了做一流研究的不易，可以说在中南的这三年便是离我理想最近的时刻。无论未来离中南有多远，我想我与中南的缘分一定会永远的延续下去。2022/05/31
参考文献这个东西说重要也重要，说不重要也不重要，但它却是每个评审老师都会看的地方。简简单单一看，就能知道这篇论文的作者有没有读文献，读的文献质量如何，以及有没有认真整理文献。如果说参考文献的档次可以因人而异，但是参考文献的格式却每个人都是一样的，一般情况下都以GB/T 7714-2015为准，但是也有少数地方不一样。三年前还在读本科的我，被博士师兄安排得明明白白，每周都在给他的大论文整理参考文献。当时不知道为什么他对每个细枝末节都关注得那么细，现在到了自己论文快盲审的时候才知道，评审老师可以很容易发现参考文献里面的细节问题。只是当初的技术手段过于落后，拿着Endnote一个个导入文献的元数据，每次修改之后都得手动把文献发给其他同学。样式文件也没有找到最完整的，最后还得自己去编辑样式文件[允悲]。要是用现在的Mendeley/JabRef管理Bibtex，然后再配上Github同步，那真的不知道有多方便，只不过这套方法就不太适合用Word的同学了。由于当时的历练，导致我比较熟悉参考文献这方面，每次很快就能发现别人的格式问题。之前给师兄的课题组讲过几次报告，还帮他给学生培训了几次。最近也是，帮很多同学都检查了一下。最搞笑的是有个同学的参考文献居然不是按国标来的，我当时就说你这个论文送出去肯定得被老师挂掉[笑cry]，吓得他赶紧认真修改了一天。因为下周就要送审，我下午就去实验室重新画了几个图。刚准备回去的时候，隔壁课题组的同学就拿着论文走了过来问我参考文献对不对，然后我就拿着他的论文给他找出来了一堆错误[允悲]。他们组的大师兄也是的，让他们引用100篇左右的文献，实际上对于硕士生而言，根本不可能读过那么多文献，到最后只能是按关键词瞎引用，而且引用的越多越容易出错。到最后我让他回去删一点文献，到时候师兄问起来就说学院要求不引用自己没看过的文献（事实上也应该如此）。在修改的过程中，另外一个同学看到了这一景象，笑着喊了我一声Q老师哈哈哈。这让我回想起来了研一的时候，坐在我现在这个位置的柳师兄，也是经常旁边坐着个同学，然后师兄就在那指导他的实验。虽然说我既谈不上指导，关注的也不是实验部分，但是这还是有一种似曾相识的感觉哈哈哈哈。也许另一个世界线的我，确实可能已经在当老师的路上了[二哈]。不知不觉就写了那么多，如果有朋友最近也要论文送审了，那么也可以把参考文献发给我帮你看看，说不定就找出来了一堆错误哈哈哈哈。
本来想等着公司的秋招礼盒送到后再写这个总结的，但是快放假了还没有等到，就只好先写写了。今年秋招我没有像一些同学一样海投，一共只投了5个公司，面了4个，最后拿到了2个公司的offer，此外还收到2个创业公司的邀请没有去。下面就分别写一下我投这几个公司的经历吧。英特尔：最开始实习的时候其实比较想去英特尔，因为英特尔的工作环境和福利待遇都比较好（每天下午5点准时下班），其技术实力更不用说，而且我们实验室有个博士师兄之前在那实习过1年。4月份的时候面其他公司一直没面过，于是就想请他帮忙内推一下。当时他说给英特尔那边推荐没问题，但是还是建议我去互联网公司实习，因为英特尔的节奏比较慢，学到的东西可能比较少。于是我就按照他的建议暂时没有投英特尔，接着面试互联网公司。后面到了9月份的时候，英特尔的秋招正式启动了，我当时是想着等英文简历准备好再投，没想到一下就快截止了。最后是我同学问我投了没，我才火速找了内推投过去。实习的时候公司有很多大佬都是从英特尔出来的，在英特尔实习过的同事也说那边工作起来很舒服，这就更增加了我对英特尔的好感。笔试前听说英特尔的笔试偏难而且只有一次机会，我想着凭借着我长期的积累应该没多大问题。没想到运气不太好，笔试系统和我的Win7不是很兼容，题目中许多字都显示不出来。没有办法，面对着6个选项的单选题我也只能瞎猜了。到最后没有悬念，应该是笔试成绩不太好，一直没有收到面试邀请。微软：微软也一直属于我很想去的公司名单里面，微软的实力不仅在工业界数一数二，而且在学术界也有着微软研究院这样的顶级科研机构，特别是做我们系统方向的，如果说上海交大排第一，那么后面一定是微软亚洲研究院了。微软的招聘系统比较神奇，一般内推过去的简历都会被自动识别，但是他们全英文的系统识别得不是很好，很多内容都需要自己补进去。刚开始填的时候没什么问题，没想到把本科学校填进去后找不到对应的匹配项，然后看到下面一个复选框“我的学校不在列表中”，当时我就心想这下凉了，估计我们学校以前都没有人投过微软。在最顺利的一次笔试之后，我一直没等到微软的面试通知，果然凉了哈哈哈。因为当时想着投对口一点的岗位，就选的是微软上海做云计算的部门，后来了解到他们的招聘需求比较少，所以招聘要求会高一些。后来到了10月底的时候，微软开始补招，打开一看果然是微软苏州那边做桌面软件的部门，没有办法也只好试一下了。不过总体看下来，微软的面试体验是所有公司里面最好的，面试官说话都很温文尔雅，面试的时候也不会给太大压力，都是循序渐进地引导面试者回答。前面三面都还算顺利，到最后一面的时候，大部分公司都是HR出来面试，和面试者聊聊天了解一下基本情况。结果微软的最后一面是经理面，不仅要聊HR要聊的，还问了些技术。因为面试官问的技术我平时用的比较少，答得不太好，不到30分钟就结束了面试。我当时其实就有点意识到可能过不了了，过了几天登上招聘系统一看，果然流程就挂掉了。虽然说微软苏州我不是很想去，只是想体验一下外企面试的感觉，不过没面过还是有点遗憾的。所以说，微软毕竟还是顶级软件公司，想进去还是不那么容易的啊。华为：其实最开始没打算投华为，只不过架不住华为HR的电话轰炸，只好投了他们的那个部门。后来想着反正投的投了，还不如投对口的部门，没想到后面的经历却是一波三折。可能是投的部门招人比较少，这次华为的面试难度估计是秋招里面最高的了，前两面上来就是做题，第一面题勉强做出来了，第二面题虽然不难但是不太熟悉，几乎没做出来。二面结束后HR说面试官们的意见不统一，后面又加了一面。这一面就不得了了，HR找了个大佬过来面试，我把我读研期间所有的积累都快讲完了才停下来。最后还是没有通过，可能面试官们觉得我编程能力偏弱了一点。不过也没事，华为的工作强度也不是一般人能承受的了的，还是身体健康第一。腾讯：腾讯其实是我面试的最多的公司了，之前在找实习时就面试了3个部门，这次秋招我还没投就又面了2个部门。第一个部门大概是7月底面的，面试时自己感觉回答的还可以，但是可能还是有所不足吧，就没有过。第二个是我同学实习的部门，面试前稍微多准备了一下，就顺利通过了第一面。第二面时虽然没有所有问题都答得很好，但总归是大部分都答出来了，勉强通过。HR面就不用说了，简单的走一下流程，表达自己想来的心态就顺利通过了。后面也是顺利收到录用意向书和正式offer。阿里：暑假的时候一直在阿里实习，所以就只需要走转正流程就可以了。转正的话相对于秋招还是容易一些，不过也需要看所在部门的名额是否充足，不然有可能会转正失败。转正流程主要就是答辩，主要介绍一下自己实习期间的工作和感悟。答辩的时候有4个人在场，分别是师兄、主管、二级主管和HRG，起主要决定作用的是二级主管和HRG。一般情况下实习只要认真做，主管还是会想留下你的。答辩时我自己讲了20分钟左右，然后就是提问环节。主管问了几个简单的问题，二级主管则问得比较深，HRG则偏向于考察性格和职业规划等偏软的部分。因为在学校里开组会讲报告也讲得比较多，这种答辩对我来说并不难。答辩完第二天主管开会时就告诉我应该没什么问题，过了一个月左右差不多就收到了录用意向书，转正成功。正式offer来得稍晚，大概和腾讯差不多都是在10月底左右收到的。创业公司：在秋招快结束的时候，邮箱里意外的收到了Pony.AI和Covariant.AI两家创业公司的面试邀请邮件，都是看到我Github上面两百多个star的Dota2 AI项目过来的。不过仔细看了一下这两个公司提供的都是社招岗，而且创业公司的发展前景不确定，对于应届生来说并不是一个很好的选择，于是就婉拒了他们。不过也可能就此错过了公司上市一夜暴富的机会哈哈哈哈。最后两家公司开的薪资其实都差不多，还是选了自己比较熟悉的阿里云。这个部门的同事和领导都算不错，而且因为这个部门主要是对内业务，工作压力相对来说是比较轻的，希望以后不要享受太多福报了哈哈哈。总的来说，这次秋招的结果还是可以的，虽然说没能成功进入外企躺平，但是也算找到了一个比较对口的工作。现在的打算就是先去那发展几年再看看吧，我实在是不擅长规划很远的事情。现代社会的信息流通速度实在是太快了，一份纽约时报所的信息量比17世纪一个普通英国人一辈子的信息量还要多。无穷无尽的信息导致我们总是生活在与他人的比较之中，不仅我们的眼光不断变高，而且对自己的认知也发生了偏差。我的父母其实都很尊重和支持我的选择，他们并不会给我什么压力，但是我有时还是会在不经意间通过各种渠道看到特别优秀的人，这带来的同辈压力其实还是存在的。不过在经历这次秋招找到工作之后，我再也不用担心这种压力了，因为自己确实已经在就业市场中证明了自己。以至于在学校里一段时间内遇到什么不开心的事情，我都会想着反正自己有好工作啦，其他事情运气差一点也没关系，总不可能什么好处都被我自己占了哈哈哈哈。在秋招的过程中，其实要谢谢帮我内推的各位大佬以及互联网上无私分享面试经验的博主，没有他们的帮助我可能很难找到这么好的工作，如果大家有什么想问的话也欢迎提问哈哈哈。最后很感谢朋友们能耐心地看到这里，就祝大家未来的发展能够顺风顺水蒸蒸日上吧！
我们学院每年都要办一个学术年会，要求我们在读期间必须投稿一次。前两年我都没来得及投，想着以后肯定有机会好好准备，结果今年实习刚回来也是没什么时间准备，最后只好把本科写的一篇论文交上去凑数。因为这个会议会选出一些不错的论文上去作报告，然后被评为优秀论文的可以直接满足毕业条件。我们老师估计就是看到这个，所以把我们没发论文的都推荐过去作报告了。其实我本科做的那玩意不怎么样，但是为了今天能混过去，昨天还是花了一点时间认真做了ppt，此外还顺便恶补了一下该领域的最新进展，方便到时候能讲得好一点。今天下午到了会场之后，一般作报告都不会紧张的我还是有点慌，毕竟好久没做这方面的工作了。好在前面几个同学的报告水平也就一般般，我又逐渐恢复了信心。上去讲的时候我就发挥了这么多年来积累的演讲能力，把一堆新技术包装在了我过去普通的工作上，没想到还把下面的同学讲愣了。最后老师提问题的时候，我也是见招拆招，把他们忽悠过去了。而且最搞笑的是，下面有个老师和我本科时的毕设老师长得很像，特别是他那稀疏的头发哈哈哈。下来之后我仔细思考了一下，其实不是我做得怎么样，而是他们的技术实在是太落后了，讲的好多东西都是本科做毕设的时候就知道了的。但是当时觉得人工智能方向还是竞争太激烈了，后来读研的时候就没有继续做，而是进到了一个更大的坑里面。不知道如果接着做那个方向会怎样，可能也会有一些不一样的坑没被我发现吧。难得的是下午这个活动结束的比较早，而且正好现场也有几个同学在那听，于是活动弄完之后就和隔壁课题组的同学去吃饭了。虽然说很多新同学都不认识，但是感觉吃饭的时候还是有很多聊的，他们也愿意听我们讲一些实验室的八卦。自己课题组的同学天天坐一起，能聊的东西其实不多，而且距离太近总是会有一些矛盾，很难往好朋友的方向发展。隔壁课题组有个老哥最开始其实和我是坐在一起的，后来即使他搬到另一个屋子去了，我们的关系也还是很好。他最开始说大家其实都是同事关系，我最开始还不理解，但是到现在我才终于弄明白了。读研时的同学和本科时确实不一样，平时一起在实验室工作，距离虽然更近，会涉及到一些合作，但是更多的是会有利益冲突。如果最开始就想着能当朋友，其实会有些失落。如果都当做同事来相处的话，那么很多事情就都无所谓了。这点在我实习完之后其实体会得更加深厚了。总之我想说的就是，现在这个阶段确实不容易结交新朋友，老朋友们又很少相聚，没有朋友一起玩的时候还是要发展一点爱好啊哈哈。
(ATC'19) Unification of Temporary Storage in the NodeKernel Architecture
在任务之间有效地交换临时数据对于许多数据处理框架和应用程序的端到端性能至关重要。不幸的是，临时数据的多样性造成的存储需求往往落在传统存储平台(如文件系统或键值存储)之间。本文提出了一种新的分布式存储架构NodeKernel，它通过将文件系统和键值语义融合到通用存储内核中，同时利用现代网络和存储硬件来实现高性能和低成本，在存储系统设计空间中提供了一个新的落脚点。NodeKernel提供了分层命名，高可伸缩性和接近裸机的性能，可提供临时数据特有的各种数据大小和访问模式。Crail是我们的NodeKernel架构的具体实现，该架构使用RDMA网络和分层DRAM / NVMe-Flash存储。我们证明了将临时数据存储在Crail中可将NoSQL工作负载性能提高多达4.8倍，将Spark应用程序性能提高了3.4倍。此外，通过在NVMe Flash和DRAM存储层之间存储数据，与仅DRAM的存储系统相比，Crail可以将存储成本降低多达8倍。1.简介有效地管理临时数据是提高集群计算工作负载性能的关键。例如，应用程序框架经常缓存输入数据或共享中间数据，既在作业内（例如，在map-reduce作业中shuffle数据），又在作业之间（例如，机器学习训练工作流中的预处理图像）。在无服务器计算中，为了在任务的不同阶段之间交换数据，临时数据存储也越来越重要[17]。有效存储临时数据具有挑战性，因为其特征通常位于现有存储平台（例如分布式文件系统和键值存储）的设计点之间。例如，map-reduce作业中的随机数据可能由大量文件组成，这些文件按层次结构组织，大小变化很大，被随机写入，然后顺序读取。文件系统（例如HDFS）提供了方便的分层命名空间并有效地存储了大数据集以进行顺序访问，而分布式键值存储则针对可伸缩访问大量小对象进行了优化。类似地，基于DRAM的键值存储（例如Redis）提供了所需的低延迟，但是持久性存储平台（例如S3）更适合以低成本实现高容量。总体而言，我们发现现有存储平台无法满足分布式数据处理工作负载中临时数据存储和共享的所有不同要求。在本文中，我们介绍NodeKernel，这是一种从头开始设计的新分布式存储体系结构，可支持快速有效地存储临时数据。作为其最显着的特性，NodeKernel体系结构融合了文件系统和键值语义，同时利用现代的网络和存储硬件来实现高性能。NodeKernel基于两个关键的观察。首先，长期存储平台提供的许多功能（例如耐用性和容错性）在存储临时数据时并不重要。我们观察到在这种情况下，文件系统和键值存储的软件体系结构开始看起来惊人地相似。基本区别在于，文件系统需要额外的间接级别才能将文件流中的偏移量映射到分布式存储资源，而键值存储将整个键值对映射到存储资源。第二个观察结果是，低延迟网络硬件和多CPU多核服务器通过在几ms的延迟中启用可扩展的RPC通信，从而在分布式环境中显着降低了这种间接成本。基于这些见解，我们通过将文件系统和键值语义实现为通用存储内核之上的薄层，来开发NodeKernel架构。存储内核对统一名称空间中称为“Nodes”的不透明数据对象进行操作。应用程序可以在节点中存储任意大小的数据，在分层名称空间中排列节点，并在需要时通过专用节点类型获得文件系统或键值语义。例如，键值节点和表节点允许并发创建具有相同名称的节点，并提供最后提交为准的语义。另一方面，文件和目录节点允许在存储层次结构中的给定级别上高效枚举数据集。通过将通用存储内核和自定义节点类型中的功能分开，NodeKernel使应用程序可以使用单个平台来存储可能需要不同语义的数据，同时通常为各种数据大小和访问模式提供良好的性能。NodeKernel在设计时明确考虑了现代硬件。经过严格考虑后的分离，存储内核由为低延迟网络硬件量身定制的轻量级和可伸缩的元数据平面以及可访问多层网络连接的存储资源的高效数据平面组成。精简的元数据平面能够在低开销下提供最关键的功能。数据平面运行一个轻量级的软件堆栈，并利用现代的网络和存储硬件来实现对任意大小数据集的快速访问，同时还提高了成本效率。例如，取决于性能和成本要求，附加到“Nodes”的数据可以固定到特定的存储技术层，也可以从一个存储层溢出到另一个存储层。Crail是我们对NodeKernel体系结构的具体实现，它使用RDMA网络和分别基于DRAM和NVMe SSD的两个存储层。我们使用原始存储微基准以及NoSQL YCSB基准测试和不同的Spark工作负载，在配备Intel Optane NVMe SSD的100Gb/s RoCE集群上评估了Crail。我们的结果表明，Crail在最佳位置运行时，可以与当前最新文件系统和键值存储的性能相匹配，并且在文件系统和最佳位置之外进行数据访问时，其性能要比现有系统高出3.4倍。键值存储。此外，Crail通过在DRAM之外使用NVMe Flash，创造了降低成本和获得灵活性的新机会，并且几乎没有性能损失。例如，我们在Spark中使用Crail存储shuffle数据时调整DRAM和Flash之间的比率，而作业的运行时间增加很小。总而言之，本文做出了以下贡献：•我们提出了NodeKernel，这是一种融合了文件系统和键值语义的新存储架构，可以最好地满足数据处理工作负载中临时数据存储的需求。 •我们介绍了Crail，它是使用RDMA，DRAM和NVMe Flash的NodeKernel架构的具体实现。•我们证明了将临时数据存储在Crail中可以减少运行时间并减少数据处理工作负载的成本。例如，Crail将NoSQL工作负载的性能提高了4.8倍。集成到Spark的shuffle和broadcast服务中后，Crail可以将应用程序性能提高3.4倍，并将成本降低8倍。Crail是一个开源Apache项目[2，3]，其代码可从项目网站下载，也可直接从GitHub的https://github.com/apache/incubator-crail下载。此外，本论文中使用的所有基准都是开源的。2.背景和动机临时数据代表了分析框架中一大类重要的处理中数据。例如，Zhang等人的报告指出，在Facebook执行的超过50％的Spark作业包含至少一项shuffle操作，从而产生了大量的临时数据[37]。我们将临时数据定义为在处理过程中创建，处理或使用的所有所有应用程序数据，不包括原始输入和最终输出数据。具体来说，我们确定了三种不同的临时数据类别：作业内，作业间和缓存的输入/输出数据集。当执行诸如页面排名或SQL查询之类的单个作业时，将在框架内生成作业内临时数据。常见的示例是在Spark，Hadoop或Flink等框架中的shuffle或broadcast操作期间生成的数据集。通常，此类数据是由同一作业生成和使用的，这限制了数据的生存期。作业间临时数据是多作业流水线中的中间结果。例如，在典型的机器学习流水线中[35]有许多预处理和后处理作业，其中一个作业的输出成为另一作业的输入。最后，缓存的输入/输出数据的示例大部分是只读数据集，这些数据集被拉到缓存中以进行快速重复处理。例如，用户可能会在短时间内在同一个表（或视图）上运行许多SQL查询。在这种情况下，输入表的副本可能会缓存在快速存储介质上。为不同类型的临时数据构建有效的存储平台需要仔细考虑应用程序需求，数据特征和硬件机会。在以下部分中，我们将讨论对临时存储平台的若干要求，并提供当前最新解决方案的概述。2.1需求与挑战大小，API和抽象多样性：数据处理工作负载中的临时数据可能会因数据大小而有很大差异。在图1中，我们显示了在执行以下任务过程中生成的临时数据大小分布（CDF）：（a）在Twitter graph上执行PageRank；（b）在TPC-DS数据集上进行SQL查询；（c）在稀疏矩阵数据集上执行Cocoa机器学习[24]。如图所示，每个任务的数据大小范围从几个字节（用于机器学习）到GB（用于TPC-DS）。由于历史原因，通常使用不同的存储系统来处理此频谱的两端。分布式键值存储区（例如，RAMCloud，memcached等）具有对象API，并进行了优化，可有效存储较小的值以进行快速随机查找[20，33]。相反，诸如HDFS或Ceph之类的文件系统可以通过对数据集进行分区并维护查找索引来有效地存储大型数据集（GB）。此外文件系统的抽象，可附加文件，可枚举的层次名称空间以及用于I/O的流字节接口为将临时数据集（如all-to-all-shuffle）轻松映射到底层存储提供了额外的支持。临时存储平台应该能够有效地存储较小和较大的值，并在单个系统中具有文件和键值抽象的统一优势。性能：临时数据通常位于数据处理的关键路径中，因此必须快速访问临时数据。与大小一样，访问模式也相差很大。例如，由于没有全局顺序，所以shuffle数据经常是随机写入的[11]，而SQL表则是在大型顺序扫描中读取的[32]。因此，用于临时数据的存储平台必须满足的一个要求是，对于任何访问模式，它都应该能够在整个数据大小范围内表现良好。幸运的是，在过去的十年中，I/O设备发展迅速，可支持具有高带宽（100 Gbps），超低延迟（小于10 usc）和数百万IOPS。为了满足数据处理需求，这些设备现在部署在云（AWS，Azure）中，并在数据处理框架内部使用。因此，理想的临时存储系统应该能够在现代网络和存储硬件上高效运行，同时提供接近裸机的性能。超越内存存储：数据处理工作负载所生成或消耗的临时数据总量可能很大。例如，在图1中显示了临时数据对象大小CDF的工作负载之间，数据的总容量相差100 GB（输入数据集大小的10-100％，未在图中显示）。在提供良好的数据访问性能的同时，很难有效地存储大量数据。例如，从性能的角度来看，最好将所有数据存储在DRAM中，但是这样做通常会太昂贵。值得庆幸的是，在过去的几年中，出现了不同的媒体类型，例如NAND闪存和PCM存储，以不同的成本，性能和能耗价格来存储数据。因此，一个有效的临时数据存储平台应集成多种存储技术，这些技术可提供不同的性能成本权衡，并允许应用程序在权衡空间的不同点之间进行选择。表1给出了不同存储技术在价格和性能方面的比较。没有必要的需求：我们观察到在临时数据存储的特定情况下，许多传统存储功能（例如持久性和容错性）不是优先选项。例如，由于临时数据的生存期短，因此持久的重要性较低。虽然容错通常对于短期数据很有用，但是对于临时数据存储，容错仍然不是一个高优先级。如今，容错通常是在计算框架级别以粗粒度方式实现的。例如，在重新启动任务导致数据丢失的情况下，Spark [36]和Ray [25]使用沿袭跟踪来重新计算数据。2.2现有方法的局限性关于上一节中列出的设计目标，我们将回顾当前的最新存储系统。我们将讨论的系统分为以下三类。键值存储：Memcached [4]和Redis [5]是设计用于将数据存储在DRAM中的两种最流行的键值存储。经过网络优化的KV，例如MICA [21]，Hedd [14]，FaRM [12]，KVDirect [19]和RAMCloud [26]使用RDMA操作来提供高性能的数据访问，但是无法轻松地将数据存储集成到除DRAM之外的其他层上 。Redis进行了扩展以将数据溢出到Flash，但是键索引仍存储在DRAM中，因此受到DRAM容量的限制。针对存储优化的KV（例如Aerospike [30]或BlueCache [34]）使用NAND闪存进行存储。因此，它们的性能受限于Flash的性能，并且它们并未针对下一代NVM存储设备（如Optane）进行优化（请参阅第5.1节）。其他系统，例如HiKV [33]，具有混合DRAM-Flash索引，但仅针对单个节点部署，因此将它们的应用程序限制在更广泛的操作范围内，例如改组。此外，这些KV存储的设计是针对数百字节至最大MB的非常小的数据集量身定制的，因此将它们的操作窗口限制为这些对象大小。分布式数据存储：Ceph-over-Accelio [8]和Octopus [23]等存储系统是用于快速网络和NVM设备的高性能分布式文件系统。但是，由于专注于提供容错的，持久的存储，它们在小对象上的性能很差（请参见第5节）。最近提出的Regions系统提供了对远程内存的文件抽象[6]。但是，与其他内存存储系统一样，Regions不是存储大型数据集的经济有效的解决方案。诸如Alluxio [1]和Pocket [17]之类的系统提供对多种存储技术类型的支持。但是，Alluxio无法提供高端硬件的性能，而是旨在构建本地缓存。Pocket拥有我们的目标，即专用于存储临时数据的存储系统，其设计与NodeKernel架构相似。但是，Pocket的重点是在云中的商品硬件上提供高效且灵活的临时存储，而NodeKernel是为低延迟高带宽网络和存储硬件而设计的。此外，Pocket仅具有基于对象的I/O接口，非常适合在无服务器工作负载中进行数据共享。相比之下，NodeKernel的统一API提供了诸如“append”和“bag”之类的语义，以支持在不同的工作负载中存储各种临时数据。临时数据特定操作：许多工作可加速数据处理工作负载中的特定存储操作。例如，Riffle [37]是一种优化的shuffle服务器，旨在减少与大型扇出相关的开销。Sailfish [27]是一个引入I-files的框架，这些I-files是经过随机优化的数据容器。ThemisMR [28]还旨在优化shuffle并针对小型机架规模的部署。通常，这些系统的目标是针对map-reduce型工作负载优化基于磁盘的，面向文件的shuffle数据管理。尚不清楚它们的设计如何支持其他通信模式，例如broadcast和multicast，或如何集成不同的存储类型以针对不同的访问模式进行优化。并行数据库[7,22]对数据库操作符使用RDMA优化的Shuffle操作。但是，这些工作是高度特定于数据库，不能自然地扩展到其他数据处理工作负载或其他形式的临时数据。3.NodeKernel体系结构我们介绍了NodeKernel，这是一种新的存储体系结构，旨在满足数据处理工作负载中临时数据存储的各种复杂需求。NodeKernel通过融合存储语义来解决这一挑战，这些语义在文件系统和键值存储中是可以单独使用的，例如分层命名，可伸缩性，多个存储层，数据集的快速枚举以及对小数据和大数据大小的支持（图2）。NodeKernel体系结构遵循以下三个设计原则：1.将高级存储语义提取到通用存储内核之上的薄层中。2.将数据管理问题分为轻量级的元数据平面和为现代网络和存储硬件优化的“哑”数据平面。3.利用多种存储技术来高效存储大型数据集。在第4节中描述Crail（NodeKernel架构的具体实现）之前，我们将在下面更详细地讨论每种设计原则。3.1 存储内核和节点类型在NodeKernel体系结构中，更高级别的存储语义在共享存储内核之上实现为薄层（或更确切地说，作为专用数据类型），并导出不透明数据“节点”的分层命名空间。节点是抽象类型Node的对象，如以下代码片段所示。内核负责代表节点分配存储资源，操纵分层名称空间以及实现诸如read，append和update之类的基本数据访问操作。应用程序与存储内核交互，以在层次结构中的给定位置创建数据节点，将任意大小的数据附加到节点，查找节点，并从节点获取关联的数据集。节点使用编码存储层次结构中位置的路径名来标识，类似于文件系统中的文件和目录。应用程序不会直接创建原始Node对象，而是会创建提供特殊功能的派生类型的对象。这些所谓的自定义类型通过两种方式扩展Node来实现更高级别的存储语义。首先，自定义类型为抽象操作addChild和removeChild提供实现。每当在存储层次结构中插入新节点或从中删除新节点时，内核就会调用这些操作。其次，自定义数据类型提供了特殊的数据访问操作，这些操作使用Node中可用的read和append实现。NodeKernel定义了五种自定义节点类型，每种类型都提供了稍微不同的语义和操作：（1）File和KeyValue：这两种节点类型都通过在Node中公开相应的操作来提供read和append接口。但是，这两种类型在创建和插入新节点的过程中提供了不同的语义，这些语义是通过addChild和removeChild的实现来控制的。对于文件节点，针对给定路径名的第一个创建操作成功，而对相同路径名的后续创建操作失败。对于KeyValue节点，将在表示现有节点的路径名上进行后续的创建操作，从而替换现有节点。如第5节所述，KeyValue节点对于在NoSQL工作负载中缓存输入数据集非常有用，允许并发更新数据，而File节点更适合在Spark工作负载中缓存只读输入数据。（2）Directory和Table：这些节点类型分别是File和KeyValue的容器。Directory和Table节点将其所有子项的名称成分存储为数据的一部分（使用Node中可用的append和update操作来实现）。例如，路径名称为“/a/b”的目录的数据段存储了两个路径名称为“/a/b/c”和“/a/b/c2”的文件，其中包括两个名称成分“c1” 和“c2”。 Directory和Table节点均提供操作以枚举其所有子节点的名称（使用Node中可用的read来实现）。可以选择将表配置为“不可枚举”，在这种情况下，不存储名称组件，枚举返回空集。在不可枚举的表中创建KeyValue节点通常更快，因为它省去了更新名称组件的步骤（如第4.1节所述）。 （3）Bag：Bag节点类型旨在支持有效地顺序读取分布在许多数据节点上的数据。 Bag的行为类似于目录，因此它充当File节点的容器。应用程序在Bag中创建和写入文件的方式与在Directory中创建和写入文件的方式相同。但是，在读取Bag时，Bag像单个文件一样出现在应用程序中。使用Bag的读取操作，应用程序可以依次读取Bag中的全部文件。通常，由于在文件边界处更有效的元数据访问，因此Bag的读取操作比单独读取每个File节点提供更好的性能。正如我们将在第5节中看到的那样，Spark应用程序可以使用Bags存储转换数据，从而允许简化任务有效地获取由map任务编写的数据。 NodeKernel中的Bag类型在精神上与Hurricane中的bag类似，这是最近在抑制数据处理工作负载中的偏斜上的一项工作[9]。NodeKernel限制了可以堆叠节点类型的方式。例如，KeyValue节点只能附加到Table节点，而File节点只能附加到Bag和Directory节点。此外，Directory可以任意嵌套，而bag和table实现平面名称空间。允许的节点类型组合与临时数据存储的特定用例匹配。同时，防止节点类型的任意组合可确保体系结构不会过度设计且易于实现。例如，Bag要用于存储按单位存储桶组织的随机数据，因此，启用任意嵌套的Bag似乎是不必要的。当时，对扁平Bag的读取操作比对任意嵌套的Bag的读取操作更容易实现。为什么要提供一个统一的存储名称空间？ 通过在通用存储内核和一组自定义数据类型中拆分功能，NodeKernel实现了两件事。首先，它允许由单个存储平台管理需要不同语义的不同类型的临时数据。例如，稍后我们将看到，Spark应用程序可以使用Crail来存储broadcast和shuffle数据，以及缓存RDD。其次，将核心数据访问与存储语义脱钩，使应用程序可以根据所需的语义（键/值与文件）而不是根据数据的大小或访问模式来选择特定的节点类型。如第2.1节所述，即使在单个工作负载内，临时数据通常也会在数据大小和访问模式方面有所不同，从而难以将数据有效地存储在文件系统或键值存储之类的存储平台中。相比之下，NodeKernel中的节点类型没有大小限制，并且可以为不同的访问模式提供有效的数据访问，我们将在后面的第5节中看到。3.2 系统架构图2说明了NodeKernel系统架构。在数据管理级别，NodeKernel的体系结构类似于HDFS或GFS之类的分布式文件系统的体系结构，该体系结构由跨集群部署的一组元数据和存储服务器组成。附加到存储层次结构中“Node”的数据在客户端以流的形式出现，但内部数据是由一系列块组成的。块是指存储在其中一台存储服务器中的固定字节序列。元数据服务器维护分层存储名称空间以及块元数据，即存储块和存储服务器之间的映射。存储服务器在启动时会分配大量存储块，并向其中一个元数据服务器注册。元数据服务器维护一个空闲列表，其中包含未分配给特定节点的块，并在数据写入和追加期间将块从空闲列表移至每个节点列表。在访问数据时，客户端首先联系元数据服务器之一，并请求相应块的元数据。然后，基于此信息，客户端将与给定的存储服务器联系以读取或写入数据。Node抽象数据类型导出两个抽象操作，addChild和removeChild，将由第3.1节中描述的派生类型实现。每当创建或删除新节点时，这些操作就会在元数据服务器上执行。节点进一步导出功能来操纵数据，例如read，append和update。这些功能被实现为客户端库的一部分，并且需要与元数据和存储服务器进行交互。最后，基本的元数据操作（如getPath或size）也由客户端库（如果可能）返回缓存的值来实现。部署目标：NodeKernel以临时数据为目标，这些数据是短期的并且易于重新生成。此外，NodeKernel的目标是由少量计算机架组成的中小型部署。考虑到目标部署和要存储的数据的性质，NodeKernel优先考虑性能而不是容错能力。但是，如果认为有必要，可以添加其他的容错机制，例如复制，擦除编码等。缺少这些功能不会在根本上影响设计。性能挑战：NodeKernel的主要挑战是提出一种能够满足第2.1节中讨论的全部需求的系统体系结构。特别是，尽管提供了方便的分层名称空间，该体系结构仍应该像键值存储一样可伸缩。此外，该体系结构应支持低延迟键值样式访问以及高带宽文件系统（如数据访问）。接下来，我们讨论如何在NodeKernel体系结构中满足这些要求。3.2.1低延迟元数据操作将文件系统和键值语义融合到单个存储内核中，首先需要快速的元数据访问。在第2.1节中，我们观察到分布式文件系统的软件体系结构与键值存储的根本区别仅在于将文件流中的偏移量映射到存储资源（例如存储服务器上的块）所需的额外元数据操作。因此，将元数据操作的开销保持在较低水平将使NodeKernel的体系结构适合小型数据集上的键值形式的操作，同时还可以提高大型数据访问的效率。如今，现代的低延迟网络硬件能够以几ms的延迟实现RPC通信[13，16]。NodeKernel具有轻量级的元数据平面，可与低延迟网络硬件很好地匹配。首先，将元数据平面缩减为仅提供由六个关键RPC操作组成的最关键功能：create以创建新节点，lookup以检索节点的元数据，remove以删除现有节点，move将节点移动到存储层次结构中的其他位置，map以将节点数据流中的逻辑偏移量映射到存储资源，register以供存储服务器在元数据服务器中注册存储资源。所有这些操作都具有较低的计算和I/O强度，并且可以在高性能网络结构上以几ms的延迟来实现。我们特意将诸如enumeration之类的数据密集型元数据操作移至数据平面，以避免产生干扰（请参阅第3.1和4节）。3.2.2元数据分区NodeKernel的可伸缩性在很大程度上取决于其元数据RPC子系统的吞吐量和可伸缩性。最近的工作表明，一方面可以使用高性能网络硬件将RPC系统的规模扩展至每秒上百万次操作[15]；另一方面，还可以在商品硬件上使用高效的软件堆栈[13]。NodeKernel中的轻量级RPC接口旨在实现高吞吐量，并且使用单个元数据服务器每秒可驱动多达1000万个元数据操作，如第5节中稍后所述。到目前为止，在我们所有的部署中，我们从未有过单个元数据服务器将达到其极限的情况。实际上，在我们最大的128个节点部署中，元数据每秒可达到450万次操作，仅大约达到单个元数据服务器可支持的一半。但是，对于仅一个元数据服务器不足的情况，NodeKernel允许在多个服务器上划分元数据空间。从而，顶级根名称空间在元数据服务器的有序列表中进行了哈希分区。使用元数据分区，可以假设足够大的顶级扇出水平地水平缩放元数据平面。基于顶级名称空间进行静态分区的一个缺点是，取决于子树的大小和子树内的活动，负载可能会在元数据服务器之间不均匀地分布。一种替代方法是在更细粒度的级别进行动态分区。例如，过去的工作提出了一种针对文件系统的分区方案，其中在目录级别实施元数据分区，并且可以选择在大型目录过大时按需拆分大型目录，并将拆分内容分布在多个元数据服务器上[29]。尽管这种方法创建了更均匀的负载分配，但由于在路径查找和遍历期间需要多次RPC调用，因此付出了可观的性能代价。给定NodeKernel中5-10 µs的性能目标，我们最终决定采用更简单的分区方案，其中节点路径始终位于元数据服务器本地。3.2.3硬件加速的存储NodeKernel的数据平面旨在与现代网络和存储硬件完美配合。目的是使存储接口保持简单，以避免过多的软件开销，并允许在硬件中实现尽可能多的数据访问功能。NodeKernel中的客户端通过两个接口与本地和远程存储服务器进行交互：read(blockid, offset, length, buffer)以从块中获取一定数量的字节，以及write(blockid, offset, buffer, length)以进行写入存储在块中的缓冲区中的数据。在第4节的后面，我们将展示Crail中的read和write操作几乎可以完全转移到DRAM和Flash的网络和存储硬件上。还要注意，存储接口通过在字节级别（而不是块级别）定义访问粒度，显式支持字节可调整的存储硬件。3.2.4分层存储NodeKernel采用简单的分层存储设计来容纳无法以经济高效的方式存储在DRAM中的大型数据集。存储服务器分为不同的类别（请参见图2），通常是每种存储技术（DRAM，NVMe SSD，HDD等）的类别。存储服务器是一个逻辑实体，即一台物理或虚拟机可以托管多个不同类型的存储服务器。例如，一种常见的部署是每个主机运行两台存储服务器，一台导出一些本地DRAM，一台导出本地NVMe SSD上的存储空间。原则上，存储类是用户定义的存储服务器集。一台存储服务器始终完全属于一个存储类。在我们的评估中，我们配置了两种存储类别，一种用于DRAM服务器，另一种用于NVMe SSD服务器。传统的存储分层方法是随着更快的存储类别填满，将数据迁移到更具成本效益的存储类别。由于数据的生命周期短，我们发现该策略对临时数据无效。相反，我们选择了一种更简单的方法，即根据用户定义的顺序填充存储类（通常先是DRAM，然后是闪存和硬盘），而无需在层之间迁移数据。特别是在数据写入操作期间，元数据服务器首先尝试分配DRAM块，只有在整个集群中没有更高优先级的存储块可用时，才转向较低优先级的存储层。4. CrailCrail是NodeKernel体系结构的具体实现。我们用大约1万行Java和C ++代码实现了Crail。表2显示了Crail的应用程序界面。Crail中的顶级数据类型是CrailStore。应用程序使用CrailStore来create，lookup和delete数据节点，或将数据节点move到存储层次结构中的其他位置。使用类似于文件系统的路径名来标识节点。使用create创建新节点时，应用程序可以为要存储的数据选择首选的存储类（表2中的参数“ sc”/storage class）。我们也将存储类首选项称为存储亲和力，因为它允许用户为特定的一组数据指定对一组特定的存储服务器或存储介质的亲和力。Crail实现了第3.1节中讨论的完整节点类型集。请注意，Crail中的所有操作都是非阻塞且异步的（返回future对象）。Crail的异步API与用于现代网络和存储硬件的异步软件接口非常匹配。实际上，几乎所有Crail的高级操作都可以直接映射到一组非阻塞的异步网络和存储操作。通过无效的futures或异常（表2中未显示）来传达Crail API调用的失败。例如，尝试lookup不存在的节点将导致无效的future (nullpointer)，而尝试从超出节点容量的节点read数据将导致异常。Crail既可以作为共享存储服务使用，也可以按用户或按应用程序部署的形式进行操作。但是，Crail的当前实现没有提供任何工具来虚拟化，保护和隔离多个租户。4.1 元数据平面Crail元数据服务器在内存中表示以下内容：（a）存储层次结构，（b）空闲块集，以及（c）块对“节点”的分配。具体而言，每个元数据服务器维护每个存储类的可用块列表。存储类根据用户定义的优先级进行排序。如第3.2节所述，如果在写操作期间当前写位置尚未指向已分配的块，则客户端将通过调用元数据map RPC操作来请求一个新的新块。元数据服务器根据所选的存储关联性（表2中的“ sc”）选择一个空闲块。如果所选存储类别中没有空闲块，则元数据服务器将尝试从优先级列表中的下一个存储类别分配一个块。在存储类中选择块时，元数据服务器在给定存储类中的所有存储服务器上使用循环，以确保在集群中均匀地分发数据。如果任何存储类中没有可用块，则客户端的写操作将失败。在3.2.1节中讨论的Crail跨元数据服务器阵列对元数据进行分区，这意味着，每个元数据服务器负责存储层次结构的分区。每个服务器都使用DaRPC [31]实现为轻量级RPC服务，该服务是基于RDMA发送/接收的异步低延迟RPC库。为了实现高吞吐量，客户端连接在不同的CPU内核之间进行了分区。每个内核在单个流程上下文中就地管理客户端连接的子集，以避免上下文切换开销。RPC缓冲区的所有内存均分配给与负责特定连接的给定CPU内核关联的NUMA节点本地。图3说明了Crail中元数据处理的不同方面。Enumeration：在第3.1节中，我们讨论了容器节点(Table, Directory, Bag）如何维护所有子节点的名称列表作为其数据的一部分。该设计背后的理由是，它允许我们在数据平面中有效地实现容器枚举。我们已经看到一些用例，其中在Spark中存储Spark shuffle数据会在Bag中生成近十万个File节点。在元数据服务器上实现枚举将导致客户端和元数据服务器之间的大量数据传输，并且在许多情况下将需要进行多轮RPC枚举所有节点。Crail用于容器节点的文件格式由固定大小的记录组成，这些记录由子项的名称组成部分和有效标志组成。创建新节点后，元数据服务器会在数组内分配一个唯一的偏移量，客户端将根据该偏移量写入相应的记录。在删除操作期间，在元数据服务器删除了节点条目之后，客户端将清除相应记录的有效标志（通过将记录中的有效位清零）。请注意，容器数据中的节点记录仅被视为补充信息。元数据服务器始终充当验证节点是否存在的权限。因此，与删除操作同时运行的枚举操作可能会导致以下情况：目录文件中的节点记录仍然有效，但是该节点在元数据服务器上的元数据状态已被删除。在这种情况下，该节点被视为已删除，并且不允许进行任何读或写操作。4.2 数据平面Crail实现了两种存储类别，一种用于DRAM，另一种用于基于NVMe的SSD。存储类的实现包括一个服务器部分，该服务器部分导出一个存储资源（请参阅第3.2.3节），以及一个客户端部分，用于实现有效的数据访问。RDMA存储类：RDMA存储类中的存储服务器将RDMA注册内存的较大区域导出到元数据服务器。基于RDMA的存储块的元数据包含必要的RDMA凭证，例如地址，长度和标记，并允许客户端使用RDMA单边读/写直接读取或写入存储块。NVMe-over-Fabrics存储类：NVMe-over-Fabrics（NVMf）是NVMe标准的最新扩展，该标准允许通过支持RDMA的网络访问远程NVMe设备。它消除了沿I/O路径到远程设备的不必要的协议转换，从而将NVMe的多个成对队列设计直接暴露给客户端。与RDMA一样，队列对可以直接映射到应用程序上下文中，以避免内核开销。Crail NVMf存储服务器通过连接到控制器并将其凭据（如NVMe合格名称，大小等）报告到元数据服务器，充当NVMf控制器的控制平面。借助元数据服务器提供的凭据，客户端可以直接连接到NVMf控制器并执行块读取和写入操作。4.3故障语义和持久性Crail当前未实现容错机制（请参见第3.2节），因此无法防止机器或硬件故障。在存储服务器崩溃时，相应的数据块会丢失。在元数据服务器崩溃时，相应的元数据分区会丢失。元数据服务器根据保持活动消息从活动服务器列表中删除不可访问的存储服务器，并确保在块分配期间仅考虑活动服务器。Crail提供了可选的机制来持久存储DRAM中存储的数据，关闭Crail部署并从先前的持久状态开始Crail部署。持久性是通过元数据服务器上的操作日志记录以及在存储服务器上使用内存映射的持久性存储来实现的。4.4数据访问剖析图4说明了Crail客户端如何代表应用程序从File或KeyValue节点读取数据的情况下与存储服务器和元数据服务器进行交互。应用程序首先调用lookup来检索节点句柄，从而使Crail通过RPC从元数据服务器中获取必要的元数据。元数据包含有关节点的信息，例如数据大小和第一个块的位置。成功执行lookup调用后，应用程序发出read操作以从节点读取一定数量的字节。请求的字节数可能少于一个块。在那种情况下，单个RDMA或NVMf操作将足以完成请求。如果所请求的字节数产生了多个块（如本例所示），则Crail立即为第一个块发出数据传输，同时并行请求下一个块的元数据。在正常情况下-由于客户端和元数据服务器之间的基于RDMA的低延迟协议-元数据请求将在当前块传输之前完成，并确保继续进行数据传输，而客户端不必等待丢失的元数据信息。5. 评估在我们的评估中，我们评估Crail是否满足第2.1节中讨论的临时存储平台的要求。具体来说，我们回答以下问题：1.Crail及其额外的间接层的统一抽象对于高性能设备上的各种数据大小是否性能良好？ （第5.1节）2.将更高级别的工作负载（及其临时数据访问）映射到Crail有多简单？ （第5.2节）3.用于数据处理框架的混合介质存储系统的性能和成本收益有多大？ （第5.3节）集群配置：我们使用八个x64节点的集群，以及两个Intel®Xeon®CPU E5-2690 v1 @ 2.90GHz CPU，96GB DDR3 DRAM和100 Gbit/s Mellanox ConnectX-5 RoCE RDMA 网卡。对于客户端服务器微基准测试，服务器配置了4个Intel Optanane 900P SSD，但IOPS实验除外，在IOPS实验中，每个服务器仅使用2个Optane驱动器。对于较大的集群实验，所有8个节点均配备4个Samsung 960 Pro SSD。这些节点运行Linux内核版本为4.10.0-33-generic的Ubuntu 16.04.3 LTS（Xenial Xerus）和Java 8。5.1 微基准测试小型和中型数据：我们首先要评估Crail存储小型和中型值的数据，这种情况通常是键值存储很好地满足的用例。因此，我们将Crail的性能（延迟和IOPS）与两个最先进的开源键值存储（RAMCloud（用于DRAM存储）和Aerospike（用于NVM Optane））进行了比较。图5显示了不同数据大小的get和put操作的性能。在Crail中，通过使用create API调用（请参见表2）创建KeyValue节点，然后执行append操作来实现put操作。get操作是使用lookup调用实现的，然后在KeyValue节点上执行read，与图4中所示的情况类似。对于小型数据（4字节），Crail在DRAM存储方面的性能比RAMCloud稍差（12 µs vs 6 µs），但在Optane NVM上的表现优于Aerospike，幅度为2-4x（Crail为23-40 µs，Aerospike为100 µs）。Aerospike和Crail之间的差异来自其I/O执行方面的差异。Aerospike使用同步I/O和多个I/O线程，这会导致占用时间并在同步功能中花费大量执行时间[18]。Crail使用异步I/O并在一个上下文中执行I/O请求，从而完全避免了上下文切换和同步。考虑到RAMCloud是为小型数据而优化的系统，Crail和RAMCloud之间的延迟差异是可以接受的。对于中等大小的数据（64KB-1MB），Crail优于RAM-Cloud和Aerospike，幅度为2-6.8倍。例如，一个1MB的put耗时约为590 µs，而Aerospike则为4 ms。这些性能提升来自有效使用RDMA单边操作（用于DRAM和NVM），它消除了客户端和服务器端的数据副本，并通常减少了在put/get操作期间执行的代码路径。尽管Crail本机支持任意大小的数据集（通过将块分布在多个存储服务器上），但是在RAMCloud或Aerospike这样的系统中存储如此大的值是困难的或被禁止的。例如，Aerospike将单个键/值对限制为1MB。RAMCloud没有严格的大小限制，但是无法存储大于4MB的值。为了完整起见，图5还显示了超大数据16MB和128MB的put/get延迟。如我们所见，在Crail的DRAM层中存储128MB值大约需要12ms，而在Crail的Optane层中存储相同的数据集大约需要20ms。在Crail中存储如此大的数据值完全取决于吞吐量。因此，远程DRAM延迟受100 Gb/s网络带宽的限制，而NVM延迟则由存储设备的带宽确定。4个Optane驱动器的总带宽约为10-12 GB/s。因此，存储在Crail的NVM层中的大型数据集的数据访问带宽为80-87 Gb/s。IOPS缩放：到目前为止，我们已经讨论了卸载延迟。图6显示了加载的Crail系统针对不同介质类型的256字节值的延迟性能测试结果。在此设置中，我们将客户端的数量从1个增加到64个。客户端在16台物理计算机上运行，并在紧密的循环中发出put/获取操作。在此设置中，我们仅使用一台存储服务器和一台元数据服务器，它们被配置为服务于DRAM，Optane NVM或闪存。图6的第一行显示了队列深度为1的情况，这意味着每个客户端在运行中始终只有一个操作。如图所示，Crail可以提供稳定的延迟，并达到合理的高吞吐量。对于DRAM，高达4M IOPS的获取等待时间（图6右上方）保持在12-15 µs，这时元数据服务器成为瓶颈。我们对多个元数据服务器进行了相同的实验，并验证了系统吞吐量是线性扩展的（如上图7所示）。对于Optane NVM配置，等待时间一直保持20 µs，直到接近1M IOPS，这非常接近设备限制。闪存延迟较高，但三星驱动器也具有较高的吞吐量限制。实际上，队列深度为1的64个客户端无法使Samsung设备饱和。为了产生更高的负载，我们测量了每个客户端始终进行四个操作的情况下的吞吐量和延迟（队列深度4，图6中的底行）。如图所示，队列深度4通常达到较高的吞吐量，直到达到硬件极限，设备队列过载（例如，对于NVM Optane）和等待时间长。例如，在延迟呈指数增长之前，Crail在4.2M IOPS（DRAM）上获得30.1 µs的延迟（图6右下），对于110万IOPS（Optane）而言为60.7 µs，对于640.3K IOPS（闪存）的延迟为99.86 µs。放置情况类似，尽管通常性能较低。元数据性能：在图7（顶部）中，我们对用于在Crail中检索节点元数据的简单查找元数据操作的性能进行了基准测试，并将其与在Octopus中类似的元数据操作getattr的性能进行了比较[23]（ 在DRAM中运行的经过RDMA优化的NVM文件系统）。这里有两个主要的观察。首先，对于单个名称节点，Crail的性能比Octopus高1.7-5.9倍。Crail中的单个namenode峰值约为9.3M lookup/s。其次，Crail可以非常有效地将单个名称节点的性能扩展到多个名称节点的设置。系统可以为2个和4个名称节点配置提供每秒高达16.7M和27.4M的查询速度。访问大型数据集：与在Octopus和Alluxio中进行文件读取操作相比，图7（底部）显示了在Crail中读取File节点的大型数据集时测得的带宽（y轴）。图7中的x轴表示客户端在读取操作期间正在使用的应用程序缓冲区的大小。Crail具有高效的数据和元数据平面，并且查找RPC和数据获取的重叠也很快达到了网络带宽限制，即使是相对较小的缓冲区大小（刚好超过1kB）。由于数据复制和网络堆栈实施效率低下，Alluxio的性能受到CPU的限制。Octopus的性能优于Alluxio，对于大型缓冲区（接近1MB），其线速度逐渐达到98 Gb/s。请注意，图7中的Crail峰值带宽（98 Gb/s）优于图5中的峰值带宽（87 Gb/s），因为对于KV实验，每个KeyValue节点都是打开，读取和关闭的，而对于文件 实验将这些访问权摊销。总结：在本节中，我们证明了Crail可以有效地存储大型数据值，同时提供比其他针对特定数据范围进行了优化的最新系统更可比或更高的性能。5.2 系统级基准测试5.2.1 NoSQL工作负载Yahoo! 云服务基准（YCSB）是一个开放标准，旨在比较NoSQL数据库的性能[10]。它带有五种强调不同属性的工作负载，例如 工作负载A的更新繁重，而工作负载C的读取繁重。我们选择工作负载B，将Crail与RAMCloud和Aerospike进行比较。工作负载B具有95％的读取和5％的更新操作，并且使用Zipfian分布选择记录。所有系统都在单个命名节点/数据节点配置中运行。本实验的目的是评估Crail的延迟配置文件，以了解超出上一节中介绍的微基准的实际工作负载。图8（顶部）显示了使用单个客户端默认设置10条字段（每条记录100字节，每KV对1K）的工作负载B的读取和更新延迟分布。图的左侧显示读取性能，右侧显示更新性能。如该默认设置所示，最大数量的读取操作观察到的延迟分别为14 µs（95％和99％的百分数分别为37µs和84 µs）和26 µs（95％和99％的百分数分别为47µs和81µs） 分别用于DRAM和Optane。Optane上的Crail的平均延迟为38 µs，因此仅比DRAM上的Crail慢15 µs。另一方面，带有Optane的Aerospike的平均延迟为108.7 µs，比Crail平均延迟（38.03 µs）差了2.84倍。将Crail的DRAM性能与RAMCloud进行比较，可以看出RAM-Cloud的速度比Crail快。但是，随着我们在图8（底部）中移到更大的10个字段（每个10KB，每个KV对100KB）的较大值，Crail分别比Aerospike和RAMCloud高出2.6-4.8倍。总结：我们使用YCSB基准进行的实验表明，（a）Crail可以成功地将原始DRAM / NVMe的性能优势转化为工作负载级别的收益，并且（b）Crail可以有效地处理小型和大型数据，而RAMCloud和Aerospike可以在特定的操作范围内发挥最佳性能 。5.2.2 Spark集成我们介绍了Spark（最流行的数据处理引擎之一）对Crail的评估。Spark通过一系列map-reduce的步骤来执行工作负载，同时在每个步骤中共享性能关键数据。Spark数据处理流水线中有多个点可以生成临时数据集。在本节中，我们将显示专门针对以下两个方面的性能指标：shuffle和broadcast。这两个子系统都可以轻松地实现为Spark的插件模块。broadcast：通过将broadcast数据存储为不可枚举的Table中的KeyValue节点，我们使用Crail实现了broadcast。broadcast写入器创建一个新的KeyValue节点，将broadcast数据附加到该节点，然后将节点“名称”传递给读取器。分布在Spark执行程序内部多台机器上的读取器对“名称”进行查找，并从Crail读取数据。图10a显示了结果。x轴显示在Spark作业中不同broadcast读取器观察到的延迟，而y轴显示读取器的百分比。垂直实线表示基线时延为12 µs，这在我们的微基准测试中得到了证明。如图所示，大多数Crail broadcast读取器观察到的延迟非常接近最小可能的延迟。少数读取器观察到低于12 µs的等待时间，因为其中一些读取器位于存储值的同一台物理机器上。对于这些节点，即使它们仍然使用本地网络接口读取数据，也没有发生实际的网络传输，因此，它们的读取性能不受网络的限制。总而言之，Crail broadcast性能比默认的Spark实施好1-2个数量级。shuffle：在Spark中，shuffle写入器在映射阶段会不断生成shuffle数据，因为它会处理输入数据集并将数据分类到不同的存储桶中，这些存储桶随后将由reducer读取。由于大型的扇入和扇出访问模式，我们使用Crail Bag节点实现了shuffle。每个reducer有一个Bag节点，每个shuffle写入器将数据追加到一组私有File节点的数组中，每个bag每个写入器一个File节点。映射阶段之后，每个读取使用Bag节点类型中可用的优化读取接口读取其关联的bag（请参阅第3.1节）。我们生成了大量数据（512 GB），并使用Spark源代码中提供的GroupBy基准触发了shuffle操作。图10b和10c显示了各种配置的性能（x轴上的运行时）和观察到的网络吞吐量（y轴）。值1、4或8表示分配给每个Spark执行器的内核数。对这两个图进行快速比较可以看出，Crail加速的Spark观察到更高的网络吞吐量（对于相应的内核数），因此，运行时间更好（1个内核5倍，4个内核2.5倍和8个内核2倍）。总结：在本节中，我们证明了Crail能够通过利用不同的节点类型（KeyValue和Bag）成功地针对较小的值（例如broadcast）和较大的值（例如shuffle）加速Spark中的临时数据访问。5.3 混合DRAM / NVM配置的效率在评估的最后一部分，我们将量化Crail的分层数据平面如何帮助实现性能和成本目标。我们考虑Terasort工作负载，它是Spark上最I/O密集型应用程序之一。我们分两个阶段将Terasort实现为外部范围-分区排序算法。第一阶段将传入的键值对（10个字节的键和90个字节的值）映射到外部存储桶中。然后，将这些存储桶按单独的reduce任务进行shuffle和分类。为了进行评估，我们使用了先前开发的加速shuffle和broadcast插件。在图9中，我们探索了使用NVM而不是DRAM在200 GB Spark排序工作负载中存储随机数据的性能/成本折衷。为此，我们为Crail配置了DRAM和Flash存储层不同的存储限制。x轴表示在DRAM与Flash中存储的总shuffle数据中的哪一部分。请注意，在本实验中，我们使用的是基于Samsung Flash的SSD，而不是Optane设备。10/90的配置意味着10％的数据保存在DRAM中，而90％的数据保存在闪存中。该图还显示了完全在DRAM（使用tmpfs作为存储后端）中完全在其默认shuffle引擎上运行的原始版本Spark（该图的第一条）的性能。这里有两个主要观察结果。首先，与原始版本Spark相比，将Crail用于shuffle后端已经将运行时间减少了3.4倍。这种性能提升可归因于Crail中高效使用高性能网络和存储硬件。例如，在reduce阶段，我们测得了70 Gb/s/台机器的所有网络吞吐量。其次，随着我们减少Crail中DRAM的比例，转而使用Flash，Spark会优雅地自动将随机数据泄漏到Flash层中。在所有随机数据都存储在Flash中的极端配置中，性能下降到46.49秒（提高了48％），而总存储成本则从1,000美元减少到126美元（存储200 GB数据）减少了8倍。根据表1中的数字）。数据从DRAM到闪存的逐渐溢出是透明发生的。即使在全闪存配置中，Crail集成的Spark Terasort的性能也只有完全内置DRAM的Vanilla Spark性能的一半。这些结果验证了我们在Crail中所做的设计选择，这些选择允许以交易性能换取存储成本。总结：在本节中，我们证明了在Spark中使用Crail（i）会由于其高效的I/O路径而带来更好的性能；（ii）由于采用了DRAM-NVMe混合架构，因此降低了存储成本，并提高了性能。6. 结论在数据处理工作负载中有效地存储和访问临时数据对于性能至关重要，但由于复杂的存储需求介于文件系统或键值存储之类的现有存储系统之间，因此仍然具有挑战性。我们介绍了NodeKernel，这是一种新颖的存储体系结构，它通过将分层命名与可伸缩性和出色的性能相结合，为各种临时数据所特有的各种数据大小和访问模式提供了新的存储设计空间。NodeKernel体系结构受现代网络和存储硬件机会的推动，这使我们能够减少开销，而这种开销过去使这种设计变得不切实际。我们表明，将临时数据存储在Crail中，这是我们利用RDMA网络和NVMe存储对NodeKernel架构进行的具体实现，可以将NoSQL工作负载提高4.8倍，将Spark应用程序性能提高3.4倍。与仅使用DRAM的存储系统相比，Crail使用NVMe Flash可以进一步将存储成本降低多达8倍。Reference：[1]Patrick Stuedi, Animesh Trivedi, Jonas Pfefferle, Ana Klimovic, Adrian Schuepbach, and Bernard Metzler. 2019. Unification of Temporary Storage in the NodeKernel Architecture. In Proceedings of the 2019 USENIX Annual Technical Conference, 767–781.
才摸到了一点科研的门路就要去找实习啦，突然感觉到人生是如此的匆忙。论文也没有做出来，简历也没有准备好，真不知道应该怎么办[允悲]。虽然刚来的时候我就提醒自己，很快就又要毕业了，但是没有想到时间过得这么快。粗略一算，相比成熟的实验室，我们好像少读了三个学期。大四时课题组都没成立，自己拿着几本书瞎看，自然是没有学会什么东西。研一下又因为历史事件发生只能待在家里，一跃变成了wow高手[笑cry]。徐教授人确实很好，大四时让我学会了文献检索与管理，专利写作，LaTeX，Visio等重要的科研工具，但是我实在是没有什么可写[允悲]。这几天捣鼓了一下LaTeX的一个会议模板，把之前开题报告里面的一些东西翻译了之后填了上去。看到生成后仅有两页的论文，内心也是十分开心，毕竟上面清晰地署着自己的名字。不过这学期总体说来还是挺开心，这大致要归功于老友记，以前一直有人推荐这部美剧给我，但是从来就没有把它完整下好过。这次寒假整了个迅雷会员一下把10季都下好后，我就开始了另一种消磨时光的方式。不得不说，即使是上世纪末拍摄的美剧，直到今天还能对我们产生许多影响，我也更加深刻地认识到了友谊的珍贵，从此不再为实验室的一些人际关系上的破事而烦恼。心情好了之后，很多事情也顺利多了，对一些事情不敏感的话反而能够更好地处理。还有一件值得一提的是我在语雀上面整了一个课题组的网站，等到以后我们组发达了之后再告诉大家吧，虽然可能也发达不起来了，因为我们老师就要慢慢走了。不过对我也没太大影响了，毕竟在他彻底离开前我已经毕业了[doge]。但是有几个小伙子要炸了，他们选的是本博连读计划，大四即博一，这大四还没读完导师就没了，唉好惨。不得不说，年轻人还是浮躁，沉不住心下来做研究。如果我们老师一直坚持待在这的话，我们组说不定会把他培养成杰青哈哈。至于为啥要弄个网站呢，因为我看很多牛逼的实验室都有主页，我们啥都没有总感觉太落后了，做做基础设施建设应该有益于长远的发展。今天看见组里同学发的周报，我突然意识到我好像影响到了许多人的科研方向，这都源于上学期我做的的几个大忽悠报告，把他们都忽悠了。要是以后发不出论文可别怪我这个方向不好啊哈哈，那不然我真的觉得自己有罪了。上学期老师安排了我们带几个本科生做毕设，然后有两个是保送到我们实验室的，老师希望他们大四时就能开始做研究，以后就能成果多多。我想如果老师你不准备离开的话，那他们这一届的培养环境一定会很好，毕竟已经有我们在前面铺路牺牲了。虽然说我带的那个同学很菜，实验也不怎么会做，写个调研报告大都是从我的开题报告里面复制的，唯一强的一点就是灵感挺多。不过我也不能过度批评她什么，毕竟我也不是老师嘛，更何况才大四，以后可以慢慢发展。至于实习怎么搞，还是明天做份简历出来，问问徐教授能不能帮我推荐去哪个公司看看了[doge]
在我还没开学的时候我弟就说他要来长沙玩，原因是他们还有很久才开学，而且开学了之后很难出学校，于是昨天他就坐火车到我们这来了。上午我们去爬了岳麓山，这次选了条爱晚亭左边的路上山，竟然比以前轻松很多。以前每次都是走的右边，那个路不仅陡而且很长[允悲]。这次从左边一会就上到了麓山寺，在里面又看见了这些晒着太阳一动不动的乌龟。岳麓山其实我上去过很多次，这次特别选了一条不一样的路，从东方红广场上去然后从我们学校下来。还记得上个学期我们几个同学吃饱了没事干，从我们学校后面直接上山，那真的爬得累死了。今天从这条路下来倒是很快。下午吃饭的时候和我几个老哥会合后大家一起去了烈士公园，因为现在3号线直接可以到公园东门，于是我们就直接从学校边上坐了过去。但是下了车后没人知道东门怎么进，只好先查了下地图才找到路。进公园后发现小朋友特别多，大多都是和父母一起出来玩的，即使是在什么都没有的普通草坪上，他们也能互相追赶着玩得特别开心。除了出来陪孩子的爸爸妈妈，也有很多结伴出行的年轻人。在天气晴朗的下午，最惬意的事情大概就是几个人坐在草地上玩桌游了。可惜我们不仅人不够更没有带桌游。公园里还有很多人在拍照，我们一般称这种人为带艺术家，无论是拍风景还是拍人像，其实都是艺术创作的过程。路边有很多盛开的梅花，在宣告着春天的到来。如果带艺术家萌萌姐来了的话，她肯定会对着这些花展开一系列艺术创作。说到艺术创作，我又想到了我尘封已久的微单，以前拿着它到处拍都很有意思，现在既没有时间又没有场景能够让它发挥自己的作用。这次开学都没带来，干脆把它放在家里了。绕着湖走了很远，看见右边有一座桥很好看便走过去参观一下。刚刚整理照片的时候才发现这张图拍得特别好，我其实也不知道这个角度为啥好，只看见有几个人都挤在那个地方拍桥，我也就过去拍了一张[喵喵]。看完桥之后呢沿着湖走了很久，发现在湖里划船确实是一件很有意思的事，但是感觉排队的人太多，于是决定等会人少了点再玩。其实这个公园我们小时候都经常来，只有和爸妈一起来长沙，必定少不了来这儿玩各种好玩的游乐设施。上次来的时候没有找到这些东西在哪个位置，这次终于找到了。但是突然发现很多游乐设施要么太幼稚，要么太无趣。几个稍微刺激一点的项目，比如说过山车和摩天轮居然都没有开放，也不知道是为啥。走了一圈发现真的没有什么好玩的，可是我们都记得小时候这里可全都是好玩的啊，也许是我们过了那个年纪了吧[允悲]，童年真的是一去不复返啊。到了最后，还是排队去买了票划船。船有很多种，最大的区别就是脚踏和电动。我们一天走了很远，心想还是电动舒服一点，只需要控制方向就可以了，可是到我买票的时候只剩下脚踏船了。大家觉得脚踏也还行，于是直接订了一艘。刚上船没多久，师傅就喊着我们靠岸，说旁边另外一艘船靠岸了让我们玩。原来是我们几个老哥块头都比较大，选一艘稳一点的船安全一些，走之前师傅还强调中途不要换座位，不然可能船会不平衡。其实这个船踩起来并没有那么累，反而挺好玩的，我们两个坐在后面的就开始了愉快的开船之旅。湖面上最舒服的就是迎面吹来的春风，让人好不自在。不过踩久了还是有点累，我们便在尽力保持平衡的情况下，交换了一下座位，大家轮流着踩。开始其实订了一个小时的船，但是感觉湖上的时间过得很快，没过多久就快到时间了，我们就只好停下和岸边游客互相注视的行为，把船还了回去。划船真的很好玩，而且心情也非常放松，下次一定还来。
前几周回了母校，大概已经一年没来了。12月份还是迟了一点，图书馆前的枫叶大多已经落下，人流也比往年稀少很多。学校里发生了很多变化，最让我羡慕的是图书馆下面新开的书店。以前想买书的话要么在网上买，要么只能去市里的书店。书店里面不光有很多陈列整齐的书，还有很多古典风格的座位。里面的同学很多，但却丝毫感受不到吵闹。看着这样美好的环境，我也忍不住买了两本小说，支持一下这家新开的书店。要是这家书店早一点开，我几位喜欢看书的朋友们估计会一直泡在这。学校里好吃的店子也有很多，当时身处这么好的环境反而没有珍惜，天天就在各个食堂吃来吃去，不过我们的食堂也是很好吃，丰泽三楼的孜然牛肉可香啦。这次我们先去东湖那边我以前经常和老哥吃饭的家常菜馆，我都不认识老板长啥样了，老哥居然还记得清清楚楚。吃完饭后又走到了红旗，吃了份豆花和一些小吃。晚上则在滨湖那条路上解决了晚餐。一般要重游故地的话，要么是有什么景色值得怀念，要么是有什么朋友值得牵挂。去年刚毕业的时候，没有回家就被老师喊到了这边的实验室。一时半会不能适应，经常跑回母校看看。那个时候不仅有留下来读研的朋友，尚未毕业的朋友，还有许多二战的同学，每次回来玩都是满载而归。如果他们都毕业了的话，估计就只只能拜访本科的老师了哈哈哈。大一的时候图书馆前面的枫树刚种下，稀稀拉拉的没有什么好看的。但是我的同学们还是乐意在这玩耍和拍风景。枫树慢慢地成长，到了大三的时候枫树已经长得枝繁叶茂，两排枫树包围的小道上落满了枫叶。不知道是被长沙哪个媒体报道之后，我们学校突然就变成了长沙的著名景点。每到周末学校就停满了车，很多家长带着孩子就坐在草坪上玩耍。只要碰见人问路，想都不要想就可以朝图书馆前面指。游客们好像还给那条路起了个名字，但是叫啥我实在忘了[允悲]。随着游客挤满了学校，我们就给学校起了个名字：马坡岭人民公园[二哈]。后来为了避免学校内的车太多，以前完全开放的学校在几个路口都设置了闸门，收点停车费。不过只花10块钱的停车费就能欣赏这么多美景，那当然是很值的。如果愿意坐公交车过来，那甚至不用花一分门票钱。以前每次想去枫树那拍照的日子，总是错过没什么游客的最佳拍摄时间。现在手机里最好的一张，还是大四的时候随手拍的。明年的话，一定要提前过去欣赏11月的红枫[doge]，以及3月的樱花。
圣诞节没什么活动，给大家讲点好笑的吧哈哈哈。上周刚刚开题完，但是还有一堆报告要写，而且实验也没怎么做。我在实验室实在是待着无聊，于是想着去徐教授那蹭饭吃。为什么我觉得有饭蹭呢，因为今天周五他们组开组会，如果会开得够晚，徐教授偶尔会请客。光看这一点概率确实不高，但是今天还请了别的学校老师过来作报告，而且今天是圣诞，这么多因素叠加在一起，怎么说应该能蹭到饭吃了。于是我就跟着他们组的老哥前往了湖大。到了湖大，看见了许久没见到的唐教授，虽然她可能不记得我是谁了哈哈。去年暑假的时候，她还没入职，就一直坐在我后面，当时还不清楚她是谁，后来才知道她博士都毕业了。第一个报告是一个师妹讲的，师妹的报告讲得还行，就是感觉区块链的文章都是大同小异，没有场景需求强行创造一个场景，然后针对虚假的场景设计了一个协议，没什么意思。问了下师兄，他说工业界里面没有什么人用区块链保障安全，因为这个效率实在是太低了，一般用用公私钥就够了。下面一个报告可就精彩了，报告人郭老师，一个普普通通的17届本科生，居然是他们学校的研究员[笑cry]还是产业化公司的架构师，太强了。反正一个小时的报告把数据安全和隐私保护的各个方面都讲到了。报告讲完后，几位老师又聊了快一个小时，眼看着就六点了，怎么说都应该大家一起共度圣诞佳节了吧。没想到徐教授首先拍了下郭老师的肩膀，说道：“哎呀，今天晚上还有点事，下次一定请你吃饭啊”。郭老师回道：“没事，正好我今天也有事，下次再聊”。唐教授默默地拿着本子瞬间也告辞了。最后只剩下我们一群同学在那呆若木鸡，原地愣住。怎么办？干饭人饭还是要干的，只好几个人一起到他们学院对面的鸡公煲小吃了一顿。席间谈到郭老师并不是普通本科生，而是博士中途退学了。好家伙，怪不得他说他们公司要像苹果公司学习，这不是乔布斯吗哈哈哈哈。回来的时候几个人都说，没想到徐教授今天不请客，太稀奇了。本人虽然有所遗憾，但觉得这还是比食堂好吃多了，十分满意。老哥还给我说，徐教授请客还好，唐教授就更有意思了。上次在电梯里碰见她，她就说正好大家一起吃个饭。老哥们心想这下又可以大快朵颐一餐了，没想到唐教授带着他们两个沿着学校主干道走了几百米，拐角进入了一个快餐店，给他们说：“这个饭店13块钱的盒饭超好吃的，请你们尝尝鲜”[二哈]。普普通通的唐教授，虽然博士毕业一年多，但还是不改学生本色啊，生活方式一直都是那么年轻哈哈哈哈。
东京大学最震撼入学致词：等待你们的是不公的社会
在今年的日本最高学府东京大学入学典礼上，上野千鹤子名誉教授的致词就好像一颗深水炸弹，在日本引起了极大反响。抛开关于女性主义的议论，很多字句，都切中要害，直抵人心。完整译文如下，送给所有在漫漫求学路上努力着的学生们，特别是女生们。女学生们面对的现实 对于这个选拔考试的公正性，你们想必是深信不疑的。若是出现了不公正，一定会气愤不已吧。但是去年，东京医科大学被查出考试不公，他们对女学生和复读生的差别对待已经确认无疑。文科省对全国81所医科大学医学部展开了全面调查，结果是这样的，女性学生的入学难度更高，换句话说男性学生的合格率相比女性学生合格率的比值，平均为1.2倍。被查出问题的东医大的该数值为1.29，最高的顺天堂大学为1.67，处于前列的还有昭和大学、日本大学、庆应义塾大学等私立大学。比1.0低的，也就是女生更容易考入的大学有鸟取大学、岛根大学、德岛大学、弘前大学等地方国立大学的医学部。顺带一提，东京大学理科3类的该数值为1.03，虽然比平均值要低，但是也高于了1.0，这个数字应当如何解读呢？统计很重要，因为基于统计的考察才能成立。 女学生比男学生更难合格，是不是就意味着男性考生的成绩比较好呢？公布全国医学部调查结果的文科省负责人作出了这样的评论：「男生处于优势地位的学部，除了医学部没有其他的了，无论是理工科还是文科基本都是女生更有优势。」也就是说，除了医学部以外的其他学部，女生的合格难度都低于1，唯独医学部的数值在1以上，这似乎意味着需要做出点解释吧。 事实上，有各种数据可以证明女性考生的偏差值比男性更高（即成绩更好）。首先，女学生们为了避免落榜，会倾向于选择更有把握的目标学校。其次，东京大学入学者中的女生比例长期无法跨越「2成之壁」，今年甚至比去年更低，仅为18.1%；统计上的偏差值正态分布并没有男女之差，因此会来参加东大考试的女生原本就比男生更加优秀。第三，原本4年制大学入学率上就出现了性别差。根据2016年的学校基本调查，4年制大学入学率男生为55.6%，女生却为48.2%，有7个百分点的差距。这个差距并非成绩的差距，而是信奉「儿子上大学，女儿上短期大学」的父母的性别歧视的结果。 最近获得诺贝尔奖的马拉拉·优素福扎伊在来访日本时强调了「女性教育」的重要性。但那不过是巴基斯坦的事，跟日本没什么关系吧？「反正是女孩」、「因为不过是女孩」像这样浇冷水的事情，我们管它叫意欲冷却效果。马拉拉的父亲在被问到「您是如何培养您女儿的」的时候，他回答说「不折断她的翅膀」。正如所言，很多的女孩子们，都早已被折断了那双所有小孩子都曾拥有的翅膀。 等待着拼命努力进到东大来的男生女生们的，又是怎样的环境呢？在和其他大学举办的联谊活动中，东大的男生会很受欢迎，但从东大女生口中，却听到了这样的声音——在被问到「你是哪个大学的？」的时候，会回答「东京……的……大学……」。究其原因，说是不知为何若是听到「东大」对方就会退缩。为什么男生在自称东大生的时候就可以挺胸抬头视为荣耀，女生却要踌躇不决呢？说到底，男性的价值所在与成绩的优秀一致，女性的价值所在却与优秀的成绩之间存在着扭曲。女生自小就被期待着“可爱”，然而可爱又有什么价值呢？被爱、被选择、被保护，这样的价值中包含着绝对不要威胁到对方的保证，所以对于女生们而言不管是成绩优秀也好上了东大也罢，居然都是需要隐瞒的事情。 （2016年）发生了东大工学部和大学院的5个男生对私立大学女生进行集团性猥亵的事件，加害者中3人被退学，2人受到停学处分。作家姫野KAORUKO以这个事件为原型写了一本名为《因为她脑子笨》（彼女は头が悪いから）的小说，去年还以此为题在学校里开了论坛。「因为她脑子笨」是在调查过程中加害的男生实实在在说出来的话。若是读过这本作品，便可知道社会是用怎样的眼光来看待东大男生的了。 据说，东大至今都还有本校女生实质上不被允许参加、只有校外女生才能参加的男生社团。半世纪前我的学生时代有同样的社团存在，没想到半世纪后的如今还依然健在，我深感震惊。这个三月，东京大学男女共同参与计划担当理事和副校长已经对于这种违反《东大宪章》所倡导的平等理念、排除女学生的行为予以了警告。 如今你们所经历过的学校，还算是表面平等的社会，在偏差值竞争上男女无别。但是，在你们进入大学的瞬间，隐性的性别歧视就已经开始了。等你们出了社会，还会有更多明目张当的性别歧视肆意横行。东京大学，很遗憾，也不过是其中之一。 学部里的女生比例约为20%，大学院里修士课程的女生比例为25%，博士课程则为30.7%。再之后，进入研究职位以后，助教的女性比例为18.2，准教授11.6%，教授则只有7.8%。这甚至比国会议员的女性比例都还要低。学部长、研究科长15人中只有一位女性，历代校长则从未有过女性的身影。作为女性学的先驱 研究这种问题的学问诞生于40年前，即女性学，之后被逐渐称为性别研究（gender studies）。在我还是学生的时候，还不存在女性学这一门学科。正因为不存在，所以才被创造了出来。女性学诞生于大学之外，又进入到大学之内。25年前，我赴任东大之时，成为了文学部的第三名女性教员，之后担任在讲坛上传授女性学知识的工作。开始研究女性学之后，世间变得充满了未解之谜。为什么要规定男性在职场工作，女性在家里做家务？主妇到底是什么样的存在，做什么事的人？餐巾纸、卫生巾还未发明出来的年代，月经用品都用的是什么？日本历史中出现过同性恋吗？这些内容因为谁也没调查过，所以也就不存在所谓的先行研究，因此无论做什么都会成为这个领域的先锋、第一人。在现在的东京大学，做主妇研究、少女漫画研究、性少数研究能够获得学位，正是因我们曾埋头于全新的领域、战斗而来的成果。而曾刺激我奋起的，正是永无休止的好奇心和对不公正社会的愤怒。 学术之中也有冒险。有如日落西山般的学科，也有如初生朝阳般的学问。女性学就是这样的冒险。不仅限于女性学、环境学、情报学（信息科学）、残障学等很多新兴领域相继诞生，因为时代的变化在渴求它们。由变化与多样性开拓出的大学 在我看来，东京大学正是由变化与多样性开拓出的大学。聘用我，让我站在这里便是证明。在东大内，有国立大学首位在日韩裔教授姜尚中老师，有国立大学首位持有高中学历的教授安藤忠雄老师，也有身患盲聋哑三重残疾的教授福岛智老师。 你们在经受选拔之后来到这里。据说培养每一位东大生所需要的政府费用一年为500万日元（约合新台币138万）。从今往后的4年间，等待你们的将是极其优越的教育环境。这份优越，在这里有过执教经验的我可以作担保。 你们应该是抱着「努力就能获得回报」的这份信念而来。但是，正如开头所提到的违规入试一样，即使努力也无法获得公正回报的社会一样在等着你们。并且请不要忘记，你们所想的「努力就能获得回报」的这份信念，不是因为你们努力的成果，而是受环境的恩惠使然。你们能够在今天想到「努力就能获得回报」，正是一直以来你们周围的环境在激励、在背后一直扶持着你们，表扬你们成绩的结果。在这世界上，有即使努力也无法获得回报的人、想努力也无法努力的人、太过努力以至于身心受到摧残的人，也有「就凭你」、「反正我这种人就是不行」等在开始努力之前积极性就遭到打击的人。 请不要把你们的这份努力，仅用在自己获得最终胜利的这件事情上。这份受惠的环境与能力，请不要用来贬低没有受惠的人们，而应该用来帮助他们。不要逞强，承认自己弱小的一面，互相扶持着生活下去。虽然是女权主义这项女性运动孕育出的女性学，但女权主义绝不是让女性的言行举止像男性一样，也不是让弱者变身为强者这样的思想。女权主义是追求让弱者能够以弱者的身份受到尊重的思想。在东京大学学习的价值 等待你们的，是以往的理论无法验证，也无法预测的未知世界。一直以来，你们所追求的是有正确答案的智慧。而今后等待你们的，将是充满没有正确答案的疑问满载的世界。若要问学校内为何需要多样性，那是因为全新的价值诞生在系统与系统之间，诞生在异文化产生摩擦之处。不必将它限制在学校范围内。东大有国外留学和国际交流、支持解决日本国内地区课题的相关组织。请你们追求未知，探索周围的世界吧，不必害怕异文化。人只要是还活着，无论在哪里都能够活下去。无论是在东大这块招牌完全不通用的世界、或是任何环境、任何世界、哪怕是成为难民，也请你们努力学习生存下去的智慧。我坚信，在大学中获得的价值，并不是掌握既有知识，而是掌握住令此前谁也未曾接触过的知识诞生的知识。孕育知识的知识，我们称之为元知识。而让学生掌握元知识，正是大学的使命。 东京大学，欢迎你们的到来。原文地址：https://www.u-tokyo.ac.jp/ja/about/president/b_message31_03.html译者：morykudo
我国缺少针对大众的古典音乐教育吗?
仔细想了一下，缺乏基本的音乐素养在我国其实是一件很普遍的事。从小学到初中其实就没上过多少音乐课，只有小学五年级和初中二年级的课对我有些影响。五年级的时候音乐老师是隔壁班的数学老师，他姓卜，我还记得。小学只有六节课，每天下午放学后我们就跑到隔壁班教室参加他的奥数培训班，其实也就是同学凑在一起好玩，家长们也很支持，毕竟那么早放学了回家也没人，不如就去学学奥数吧。说是培训，其实大班授课一个月也就收20块钱，真的是良心啊。在他的教导下，我六年级还拿了一次市里的数学竞赛二等奖，不过证书因为被班主任拿去评职称就不在了，至今也没还给我。我们住的那个小区里面有个教音乐的张老师，很多同学都在他那里学过各种乐器，他那里发生的故事至今还是我们的笑谈。我与乐器缘分最近的一次，就是一天放学回家，在小区门口碰见了张老师。他一见我就打了个招呼，然后端起了我的手，说道：“孩子啊，我看你还蛮有音乐天赋的诶，你以后就到我这里来学笛子吧，我已经和你妈妈说好了”，当时我心里就紧张得不行，和他寒暄几句后就跑回了家。等我妈下班回来我就问我妈，我妈说没有这回事啊，我心中的紧张一下就平复了下来，那个老师原来只是假借父母名义打广告推销的啊。我们那个小学也没有多么先进的设备，他就靠着普通的脚踩风琴和手风琴给大家教授了许多音乐常识。那时我学会了认识简谱，区分音调，区分节拍，知道怎么跟着指挥唱歌[笑cry]。初二的音乐老师叫啥我忘了，不过她倒是一个音乐专业毕业的正规老师，钢琴也弹得好。印象最深的一次就是老师弹完钢琴问有没有同学学过钢琴的，我们班的夏同学就上去弹了一首，没想到比老师弹的还要好，那时真的是掌声雷动，经久不息。所以说他大学毕业后出道成为大明星也早已在我们的意料之中[笑cry]。大学期间想选点音乐鉴赏的课提升一下自己的知识水平，可惜的是这个课实在是太热门了，从来就没有抢到过，只能作罢。有的时候看见邻国学生的交响乐队表演，就不由得感叹，这才是教育的真正意义啊。在音乐教育方面，我确实是一个标准的国内理工科教育受害者，这也不能怪我是吧[允悲]。
以前小的时候想着以后可以做个文艺青年，结果到现在美术音乐啥的还是一窍不通，书读得少，音乐不怎么听，电影也就偶尔看看。唯一比较擅长的就是写文章了[笑cry]，但其实从小学开始我就喜欢偷懒，每次老师布置作文我都是从优秀作文选集上抄的。倒是高中的时候很擅长写批判社会的作文，有一次老师还让我上台念一篇反思教育的作文，回想起来这还真是我高中语文的高光时刻呢。真的挺感谢这么多年来语文老师对我的照顾，可惜大学没有开设这种写作课，不然的话我肯定第一个选哈哈哈。这么看来文理学院的教育模式倒是挺适合我的，年轻人就应该多涉猎点文史哲。还记得12年的时候网上流行普通青年、文艺青年和2B青年的对比，那时候就喜欢笑同学是2B青年[二哈]。至于我呢，应该是普通青年吧，不喜欢站在台上吸引大家的注意力，只喜欢自己默默地思索。唉，其实我本来应该可以更外向的啊[允悲]，就像小学的时候那样多好。以前总想着找对象，却忘记去发现身边经过的小姐姐，掐指一算大四算是接触妹子最多的一年了，感谢认识的妹子教会了我如何与异性相处。此前总觉得妹子都是高高在上，不食人间烟火。现在发现除了性别不同，两性差异倒不是很大，一样可以像小学时那样建立纯粹的友谊关系，所谓的两性来自不同的星球说法完全就是扯淡。今天实验室年会，开开心心玩耍了一天，突然发现实验室怎么突然出现了这么多没见过的妹子。我们排练好的小品一上台就状况百出，好在混着混着也演完了[允悲]。其他同学的节目也挺有意思，虽然大家的准备时间都不长，不过心意到了就挺好。看节目的时候和师兄谈到大师姐找对象的事情，尽管大家都在用心给她物色，但每次遇见条件合适的博士却个个英年早婚。其实她博一的时候是有对象的，就在我们学院，可惜后来分了就一直单身至今。不过话说回来，29岁的师姐一毕业就成了副教授，即使没有对象又能怎样呢。人生有着无穷无尽的可能性。总有一天我会遇见那个同样闪烁着光芒的你。
每天生活在互联网当中，看着这光彩夺目的资本世界，成天就是消费娱乐炫富，总以为我们早就步入小康社会了。那边却还有朋友家中拿不出读大学的6000元学费准备辍学今天一个网友跑过来给我说家里条件太困难了，自己又错过了七八月份的生源地贷款，怕是没机会读书了，准备去小姨介绍的菲律宾工厂打工。我觉得他要是不读的话实在太可惜了，赶紧去教育部的公众号上找到了资助政策发给他。让他走绿色通道先入学，然后去食堂勤工俭学，这样家里就不用出什么钱了。经过一番艰苦的工作，家里终于同意他去读书了，我也算是放心了。他也实在是不容易，初中毕业后没读高中而是出去打了一年工，后来想读书呢又被坑去读了一个成教中专...学校估计也没怎么认真教，他们呢也不用天天去学校，反正读了几年出来什么工作都找不到，只能打打临时工维持生活这样子。以前真的只听说过高等教育有成教自考这类的，没想到中专也有。一路读着普通教育上来的我们，确实很难知晓其中的苦难啊。好在这几年政府准备大力发展职业教育，今年大专扩招一百万，而且要着重从已经不在接受教育的社会人士中招录。他也是看到了这个政策就赶紧去参加单招考试报名，考试也很简单，大概就初中难度，录取通知书很快也就寄到了家里。也许他之前受学历歧视多了，和我说着他想先读大专，再升本科，最后考研的规划。有着这样远大的理想当然好，不过我还是和他说基础要一步一步打牢，万丈高楼也不能平地而起，先把专科读完吧，况且他现在也20多岁了，时间和家庭都不允许他读那么久了。尽管学的不是他很想学的软件/电气专业，不过财务会计专业也算挺不错的，就业算是没有任何问题。他怕自己像以前那样划水不读书，但我还是鼓励他好好学习，多考几个会计资格证，以后找个好工作回馈家庭。不让一个学生因家庭经济困难而失学，是党和政府对每一个家庭的郑重承诺。只有在这个时候我才会想起那逝去的社会主义荣光忘记我们的基尼指数已经接近零点五的现实后记前几天在空间动态里得知他过生日，评论下方一长列的朋友祝福，看上去和过去很是不一样。他告诉我他以前吃了太多学历的亏了，想专升本再考研，想去附近的本科学校自习。我说不必好高骛远，在大学里好好学习，不要攀比，把老师上课的知识学会就很不错了。在考研的前一天，希望教育能改变他的命运。
又到了四六级考试的日子，还记得两年前第一次在老师那看见研究生学姐的桌子上赫然摆着一套六级真题，始终都不能接受这个事实。都读研了六级还没过吗，考研英语应该比六级难多了吧。结果今天，学院群里的同学提醒着明天考试的注意事项，实验室群里的同学也还不知道准考证在哪打印，我稍微查了一下，果然是换了网站了，便将地址发了过去。我的英语其实学得一般，但是应付考试还是可以的。前几天听了场留学资助申请的讲座，说着如果要出去的话最好还是要有托福雅思成绩。于是我便打开了久违的百词斩，测了下自己的词汇量，结果从上次的六千个跌落到了四千[允悲]，是好久没学英语了啊，上次认真学大概是三年前了吧。去年也想着没事学学新概念3和4提升一下英语水平，结果一共学了不到五课...我不喜欢做计划，确实也很难坚持这种事情，还问自己以后再也不需要英语考试了吧，我还学它干嘛。事实上还是用得着的，看论文查资料，都是英语优先。依赖翻译软件确实不是件好事，但是我就喜欢看母语啊哈哈哈哈，打开CopyTranslator和google翻译，一天不知道能看多少篇论文。可惜我的母语不是英语，不然搞学术的水平那得大大提升啊。我不喜欢竞争，前进的道路也不仅仅只有一条。当所有人都涌向一个方向的时候，就应该让他们去吧，避免内卷就得换条道走。人工智能领域的会议热度持续升高，投稿甚至破万，真正有价值的工作却不过几篇。也许只有泡沫破碎的那一天，沉醉于炼丹的人们才会醒悟过来。经常有别的专业的同学过来和我说他们现在在做计算机方面的东西，写了很多代码，感觉编程并不简单。实际上我已经很多天没写代码了呢哈哈哈哈，纯粹就是一个理论选手。做系统方向工作量大，还难发论文，但是好处就是整篇论文可以没有一个数学公式，学的东西也算是真正的计算机科学。那么多的黑皮书堆在我的桌子上，可谓是无尽的知识宝藏啊。csapp一书更是被誉为价值超过等质量的黄金，书的前言更是讲述了他们在上交主导激进课程改革的事情。可惜啊，我本科的时候走了许多弯路，没有早日学习到这么优秀的教材，天天用着学校自己编的垃圾教材，这一切都要靠以后慢慢弥补了。看着组里的本科生，想想他是多么的幸运，我也希望过去的我能认识几个本专业的正经研究生博士生，那样一定会学习到更多吧哈哈。
今天中午去考场参加科目三模拟考试，因为师傅带着去迟了，就错过了12点半的那一批。坐在那没什么事就观察同样在等待着的人们，发现几个小姐姐很好看，故仔细端详以表敬意。终于等到了1点半，警官过来叫了我们两个的名字，又叫了另外的两个名字，结果刚刚看到的一个小姐姐过来了[二哈]，再就是一位大叔，然后我们四个就上了模拟考试的车。坐在后座等待时收到科研助理老师发来的通知，说根据指导老师的情况重新安排了实验室的座位，我从一个房间调到了另一个房间。上面是整个实验室同学的名单，后面附着我们的学号、导师、指导老师和房间号。一部分同学的两个老师名字是一样的，但是更多的同学却不一样，我仔细看了一下，我的名字后面有两个不同的名字，而且没有出现那位博士的名字，故仰天长笑[喵喵]，事实上他没有出现在任何属于老师的位置上。然后轮到我跑的时候，就想着应该坐在新房间的哪个座位，怎么喊同学挪一下我的书，结果还没起步就在灯光操作那被扣了一百分，直接挂了，然后在这一轮里我又连续扣了几次分。事实证明，开车的时候不能想别的，不然很危险[允悲]。回家，因为没睡醒头有点晕，下车后跑到我同学@秋裤汉子 家聊天。他说我们找个电影看看吧，遂打开某部电影，指了指放在一起的两个音箱，只有单声道诶。我：什么？单身？（愣了一会）原来你说音箱哦。他：哈哈哈，A神最近情感状况怎么样？我：爱情没有，友情挺多[doge]。继续看了一会电影，虽然我没怎么认真看。屋外大雨滂沱，正想着怎么回去，他的母亲这时便进来递了一把伞给我。于是我打着伞来到路口卖公安锅盔的摊子上买了一个锅盔，虽然价格从3元涨到了4元，但挡不住它的好吃。
一、初见清华一位老哥听闻我比赛获奖了要去北京，正好他也想去玩，于是我们俩便组队前往。那天我们下了高铁便前往清华东门附近的一个酒店里，把行李放好后便骑着车试图混入校园。虽然他们说清华的保安可能会在门口检查证件，但是除了西门以外，其他的门都比较松，只要装作平常的学生样子就能很容易进去。于是我们就骑着自行车装着一副若无其事的样子前往东边最近的一个门。在马路对面暗中观察了一会后发现，骑着车的学生都能直接进去，我们便跟着他们进去了。保安一定不知道表面上镇静的两个人实际上慌得不行。初来我国的顶尖大学，想看看有什么特别的感觉。结果我们便带着强烈的柠檬气息围着学校转了一圈[酸]。无论是教学楼还是路上前行的学生，都给我一种不一样的感觉。有朋友说要我关注一下清华普通学生的颜值水平，经过我的不完全抽样调查，结果用一句话来形容的话就是“工科气息显著”。无论男生女生，大多梳着平常的发型，衣着也极为朴实，由于学校比较大，他们都喜欢骑着自行车往返，林荫大道下面便是他们成群结队的身影。二、不知名参赛选手的一天周日则是他们计算机系的学生科创开放日，上午是一系列的讲座，除了业内的特邀嘉宾，还有许多博士和本硕学生做学术报告。嘉宾的报告我还能勉强听懂，到了学生来讲，本来时间就短到只有8分钟，他们还喜欢中英文夹杂在一起说，听得就不是很懂。和刚刚认识的一位来自上海科技大学的选手老哥吐槽，他说他们好多都是英文授课的，听这个问题不大[二哈]。清华的学生还是厉害，好多同学大四就发表了国际顶级会议的文章，这在别的学校博士都是不容易做到的。听完这些报告后呢，便找到了清华节奏学博士花鼠前辈@花鼠前辈hraaat ，带着我们去食堂混饭吃，吃了整整一锅麻辣香锅都只要45元，还好好吃。吃完后便在清华校园内闲逛闲逛，看到了传说中的清华学堂等知名建筑。下午回到FIT楼观看比赛，不过去迟了几分钟，错过了开场的短视频。我们这个比赛是游戏AI之间的对抗，尽管编写起来有点难度，但一直看这些已经被我看过无数遍的游戏过程，实在是有点无聊。好在举办方的几位大佬解说得绘声绘色，倒还有点意思。现场来的人不多，也就二三十个。花鼠前辈hraaat 中间有几个抽奖的环节，按道理说中奖率挺高的了，可是几次抽奖都抽到了后面的那位同学和他父亲，最大的奖kindle还抽给了第一名那位选手，我什么都没有，哭了[允悲]。不知道为啥，现场前八的选手里面居然有两个女装大佬，其中一个还长得挺好看的[doge]，不过这不重要，略过。前八名的决赛很快打完了，大家便上去合了个影，紧接着就前往下一个活动地点清华主楼去参加颁奖仪式。周日的活动是几个活动合在一起的，先是几个赞助商的广告环节，一家讲了下量化基金啥的，另一家则是做无人驾驶的公司。讲完后就是算法竞赛的讲题环节，我这个停留于校级水平的同学完全听不懂他们的讲解，只能默默围观。比赛的题目都是同学出的，出题者自己需要上去讲，结果我又看见之前那个女装大佬上去了讲了A题，好强啊。讲题环节结束后，我注意到了传说中的C语言大师（雾）谭浩强教授，原来他创立了一个教育基金用来激励计算机基础教学领域的老师和学生，接下来便是这个基金的启动仪式。我国第一本C语言教材便是他编写的，一共印刷了一千多万本，据说是世界上第三大销量的书。站在台上的他叙述了清华大学计算机系建系从无到有的过程，他44岁才第一次接触计算机，一边学习一边向大众传授编程语言知识。简而言之就是很厉害，真是百闻不如一见啊。基金的启动仪式结束后是智能体大赛的颁奖环节，本以为我这个14名的不知名选手能有机会上台拿个优秀奖的奖状，没想到工作人员好像出了一点失误，所有的奖都降了一级，特等奖变成了一等奖，优秀奖就只发到了第8名，只能看着旁边老哥的奖状羡慕一下，不过奖金还是有的[偷笑]。算法比赛的颁奖随之开始，看上去这个比赛的参加选手大多是高中生，我还看见了熟悉的雅礼中学，他们这个队伍则是三个妹子。最后活动结束了，似乎是谭浩强教授招呼着现场没走的同学都上去合影，我们也就跟着上去了，毕竟这种机会不多嘛[doge]。离开清华主楼后，送上海的老哥出校门，没走几步就看见谭浩强教授和另一位老师走了出来，走到了非机动车的停靠点，骑着电动车就回去了。果然这就是大师级的教授啊，都有这么大的成就了，生活作风还如此简朴，值得敬佩。后记：本来应该昨晚发的，无奈信号不好一直发不出来。
亲爱的朋友们，大家好！鉴于目前股市行情逐渐变好，为实现让大家一起共同富裕的梦想，现在给大家介绍一下如何通过长期定投降低风险，获得不错的收益率。理财基本常识简介：https://content.qieman.com/items/193为什么选择指数基金定投？早在上世纪九十年代，巴菲特就开始在公开场合表示对于指数基金的推崇，他曾经近十次公开推荐指数基金。他认为低成本的指数基金是最明智的投资方式，对于大多数机构或个人投资者而言，指数型基金是投资股票的捷径。——通过定投指数基金，一个什么都不懂的业余投资者往往能够战胜大部分专业投资者。——大部分投资者，包括机构投资者和个人投资者，迟早会发现，最好的投资股票的方法是购买管理费用很低的指数基金。——个人投资者的最佳选择就是买入一只成本低廉的指数基金，并在一段时间里持续定期买入，如果你坚持长期定期买入，你可能不会买在最低点，但同样不会买在最高点。什么是定投呢？https://qian.tenpay.com/resources/pages/mb/6498e018a.shtmlhttps://www.sohu.com/a/139235080_433537如何实践？我们已经知道，定投需要选择波动大的基金，目前来说，中证500是一个很好的投资指数，购买中证500就相当于一次性购买了中国股市市值排名第301到第800家的中小型上市公司的股票。对于中证500指数来说，除了普通的被动指数基金，还有力争于超越指数表现的增强型基金，简单来说就是基金经理会根据其团队分析的结果，侧重性地额外购买其中的部分股票。从历史数据来看，增强型基金在中国股市中的确能够战胜市场，取得超额收益。具体到基金产品来说，可以选择富国中证500指数增强(LOF)161017这款基金产品，或者是建信中证500指数增强A(000478)。你可以简单的在支付宝蚂蚁财富平台进行购买，或者选择其他常见的互联网基金平台，例如天天基金，蛋卷基金，微信理财通等。以支付宝蚂蚁财富平台为例：1.打开支付宝手机客户端2.选择下方财富菜单栏3.点金基金栏目4.打开上方的搜索栏目，搜索对应的基金产品（查看定投专区可以了解相关的知识）5.点击下方的定投6.选择右上角的慧定投7.设置你想要每次投资的金额与定投周期，建议两周或一个月为一个周期，每个月投资额为你月可支配收入的20%。定投日可以选择为星期四和星期一。8.随后进行确认，此后每经过两周或一个月就会自动进行扣款，而无需你的操心。以后就只需要慢慢投入积累，收获财富吧！
这次寒假好短好短，真是不想开学啊，但没有办法还是得去读书。去年寒假结束时就想着写篇类似的文章，可是却忘了，暑假也是一样。这次可不能鸽了，毕竟记忆远远没有文字可靠，今天就先写写友情吧。不知道从什么时候开始，高中的班群逐渐没有了声音，以往寒假时我们的副班长总会在群里高呼聚餐，但这次直到开学，我也没能等到他的出现。高中班主任在高考前的几天曾给我们说，这可能是你们几天在一起学习了，要珍惜这份缘分。我不以为然，心想大家关系这么好，以后肯定有许多机会见面的。几年之后才发现，自毕业有些同学后我再也没有见到。我也不算是一个很会交际的人，不喜欢那种灯红酒绿的场合。以我开朗的性格来说，喊我出去玩当然很开心，聊聊过去、现在与未来，不得不说是一种享受。在欢乐之外有时却又彷徨四顾，不知道怎样找到那些丢失联系的老同学。我在家乡的小伙伴们大多是高中同学和在同一个社区里一起长大的发小。至于其他同学呢？小学同学大多因为人生道路不同而早已分道扬镳。至于初中，可能是因为那件事情。我们初二学校合并时，中二的我故意将分班考试的题目改错，以避免重复初一那样的重点班生活，终于如愿以偿进入了一个普通班，第一次来到这个班时，几乎只认识几个初一同班的同学，尽管在最后也熟悉了他们中的绝大多数，可回过头看，除去高中同班，现在还有联系的同学，不到5人。初中班主任是个很严厉的老师，那时把我们班的成绩和纪律都带得很好，在普通班都居前列。远近闻名的他有一个外号“火云邪神”，原因就是因为他年轻时可能喝了假酒，身上留下了难以治愈的红色皮肤。他也是在中考前最后一节数学课给我们说了很多很多话，依稀只记得一点点，大概就是很感谢大家的支持，以前如果有些严厉的话那确实对不住大家了，最后还深深鞠了一躬。常常凶神恶煞的他眼眶甚至都湿润了，有所感动的我跟着大家不停的鼓掌。他也是说初中的友谊最为真挚，以后便很难碰上这么好的朋友了，我深以为然。年后有个高中同学过生日，请了我们几个在餐馆小聚，还见到了几个我几乎丢失联系的同学。印象最深的就是那个高一结束因为和班主任合不来转学去读文科的妹子，在此之前我只知道她高一后就在学校里消失了，没想到再次见面却是这么多年之后。不得不说，学文科的妹子在一众朴素的理工科女生面前，有一种鹤立鸡群的感觉，真是太漂亮了[doge]。聊着聊着，突然发现除我以外的所有人都是初中一个班的，那个妹子还问我是不是初三才去他们班[允悲]，怎么对初中的我没什么印象。哈哈哈哈，其实我只是和其中几位同学是小学和初一的同学关系，大家如此熟悉的原因也许就在于小城这种纵横交错的同学关系吧。也许我当初不应该该那几道题的，那样就会顺其自然进入那几个重点班，能保持联系的同学也许会多一些。真是羡慕有很多玩得好的初中同学的人啊[酸]。也是过年的时候，联系上了初中的班长，那时的她真的可以说是传说级的存在，不仅长得清纯可爱，成绩也位居年级前列，不知为何也来到了普通班[允悲]，班上第二名的经常就望着她的背影感叹，这成绩也太好了吧。可惜缘分不够，我才从奶奶家回来，她就离开爷爷奶奶家回长沙了，另外一个和我们玩得好的男生也因为工作早早离开了家乡。我要是祖上就在这该多好，那就不用过年到处跑了。虽说她和我说可以在长沙碰面小聚一下，但相比两人相见，我更喜欢多人相聚，因为这样的话就不用一直思考聊什么的问题了[允悲]，我是真的不擅长开拓聊天话题啊。不过既然多年未见，还是见一面吧，共叙过往也是极好的。大学毕业在即，许多过去充满理想的朋友们都变得世故了起来，有一种我说不上的成熟感觉，尽管不喜欢但却要接受。时间磨平了他们的棱角，留下的只有那一个个纯粹而普通的个体。
重温了一下我以前写的文章，读起来结构有点像是高中生的议论文，先是抛出观点然后再举例论证...写这篇文章已经过去两年了，我想里面提出的问题自己也能回答了。1.究竟是爱笑的女孩运气不差，还是幸运的女孩更容易笑？当然是幸运的女孩更容易笑，在艰难的生活下她很难笑出来，但是保持乐观的态度也是一种良好的生活方式，蔑视困难才能继续前行。2.同样的作业题，有的同学一点就通，而他们却百思不得其解。他们是不是真的比别人傻呢？不是，人的智商大体呈正态分布，每个人之间的差距并不大。有的同学只是因为没有拥有一个幸运的家庭环境，从而无法充分发挥出自己的潜能。在给定后天条件的帮助下，他一定能不断发展，用主观能动性弥补以前的不足之处。所以我们不能鼓吹阶级决定论，这是不符合事实的。3.素质教育听上去很不错，但各种各样的素质培训岂是普通家庭所能承担得起的？普通家庭确实承担不起纷繁复杂的素质教育，因为生活本来就很艰难了，怎能把钱用在没什么意义的地方上呢。即使是中产阶级家庭，有足够的家庭条件支持素质教育，但这种恶性的竞争对家长、孩子和学校都是伤害，我之前的文章已经记录了这一现象。没有扎实的基础教育作为支撑就谈素质教育则是空中楼阁，应当在不削弱基础教育的情况下，辅以适量的素质教育，以实现人的全面发展。绝对不能学习某些国家的快乐教育法，让公立学校的学生玩着毕业，而将重要的知识放在私立学校和辅导班中教授，这对贫困的学生是极其不公平的。4.那时的我，怎能理解抽象的高考分数中所蕴含的意义呢？现在也不怎么理解，但我知道他只是在有限教育资源的情况下一种相对公平的选拔机制。我国自改革开放以来所取得的教育发展是举世瞩目的，但人民日益增长的美好生活需要和不平衡不充分的发展之间的矛盾仍然存在。每个家庭都希望自己的孩子接受更好的教育，但在更好的制度被发明之前，高考制度仍具有极大的积极作用。5.有时候心想，如果考上清华大学，人生是不是会变得更精彩一些？可能会更精彩一些，不过这需要付出代价，而且这也不是凭借我个人的努力就能实现的，需要家庭和学校的共同支持。我不后悔来到现在的学校，尽管本科的生活不是完美的，但不完美也是一种美丽，我不需要那种各方面全面发展的标准优秀学生生活。要知道现在的生活已经很精彩了呀，每一天都是全新的开始，有着这么多的事情值得去做，还有无数的好朋友等着我去交流。之前就曾听说过某著名高校的同学写实验报告写到快要自杀，要是我真去了清华，可能也毕不了业吧。6.他们好像抛弃了年少的自己，离自己的理想也是渐行渐远。这其中究竟发生了什么？在中国，任何超脱飞扬的思想都会砰然坠地——现实的引力实在是太沉重了。他们也想实现自己的梦想，但很遗憾没有时间和空间允许他们这样做。7.难道所有人都愿意看透自己的未来——从参加工作到退休，一成不变的生活真的不会没有意义吗？有意义。并不是每个人都需要世俗意义上的成功，跑道上的运动员也需要观众才能组成一场完整的运动会。所有的意义都是人类自己赋予的，在平淡的生活中一样可以实现自我价值，让世界变得不一样。8.是怎样的社会前景，居然能让一个对历史兴亡有着透彻理解的人选择永远地离开世界呢？社会固然存在问题，但正需要我们前去改变，选择死亡是对自己与家庭的不负责任。更何况死亡是不可逆的，如出现这种情况，请及时咨询心理医生或拨打24小时援助热线求助。她那时候还太年轻，不知道所有命运赠送的礼物，早已在暗中标好了价格。
以前我们对政府的刻板印象常常是低效和官僚，但今天的实地考察却改变了我的看法。起因是最近各地都在开展退伍军人的信息采集工作，我外公则是一名援越抗美老兵，正好需要去填报信息，现在是说填报后家门口能挂一个光荣家庭的称号，不知道以后会不会有补助啥的。由于外公的户口不在长沙，要回老家郴州办理。本来应该是我舅舅带他去，但由于他事物繁忙，只能让我陪同外公坐火车，然后让那边的亲戚接应。今天清晨我们就开始了一天的行程，舅舅先是把我们送到地铁站，然后我们再坐车去高铁站。大概坐了50分钟的地铁后就到了高铁站，外公年纪大了走得很慢，我也只能放慢了步伐陪他走。第一个接触的基层工作人员就是安检员，原来在此之前应该还有个检票员的，但是现在人脸识别系统直接取代了这部分的工作。没想到这个安检员在检查外公时十分的礼貌，要外公摘下帽子时也是用很温柔的语气说“爷爷，麻烦您摘一下帽子可以吗？” 她在这么繁忙的工作中还带着发自内心的笑容，真是五分好评啊。在一个半小时的高铁后，我们便抵达了郴州西站，坐上亲戚的车后，我们便前往当地的人社局复印档案。在这里，完全见不到以前那种人满为患的场景，有的只是整洁的办事窗口，各种各样的办事指引在屏幕上显示着。来到窗口前，便接触了第二个基层工作人员档案员。向她说明了来意后，递上身份证，她就起身去档案室提取档案了，不到5分钟档案就被拿回来，在复印好了兵役登记表的那一面后，两个公章唰唰地盖在了复印件上。由于没有说清楚要复印两份，亲戚便又和她说明了一下，她说本来应该我们自己去复印这份的，但是现在就顺便帮忙复印了吧。很快，两份复印件就递了出来。看了下旁边的宣传资料栏，里面还有着很多办事指南手册，里面都写清了每一个业务所需要的材料和办理流程，看得出政府在简政放权上还是花了很多工夫。从郴州市人社局出来后，我们便前往镇上的民政办，办理最后一个填表的业务。这个部门便设在小小的镇办公楼里，几个部门都在一起办公。接待我们的第三个工作人员便是一个年轻的小伙子，大概不到30岁吧，不过态度倒是没有市里的工作人员好，稍微多了一点点急躁。大概花了20分钟处理填表，复印证件之类的工作。感谢他后我们便离开了政府办公楼，从外面的公示栏上看去，他的职务好像是民政办主任来着。此时正值中午下班时间，他和几个年轻的同事走出办公楼，在我的缓缓注目下往办公楼后面大概是食堂的地方走过去了。看上去都是受过高等教育的人，走起路来有说有笑的，好不自在。基层政府是最接近人民群众的部分，如此作风的转变不仅能让我们省下许多办事时间，还能感受到许多幸福的感觉。要知道只有基层工作作风好了，人民才能相信政府，政府才能更好地服务于人民。
舅舅家有两个孩子，大的叫欢欢，小的叫熙熙。哥哥已经上小学四年级了，房间里满是各种各样的玩具和书籍，还有一个诡异的拉杆箱书包[费解]。每天在写完繁重作业后他的乐趣便是玩玩这些玩具，看看那些书，听听平板里的故事。尽管除了今日拜访的我，平时可能都没有人能和他共享睡前的这一段时光，但他一个人似乎也乐在其中。听舅妈说他最近在学机器人编程，还给我看了一下他的软件和硬件，问了几个问题都把我问晕了[允悲]，说是不知道怎么用那个软件来着。我打开他的工具箱，发现一张DVD，上面写着LOGO教育几个大字，赶紧放到电脑里面看看到底是个什么玩意。现在小学的教育资源都这么丰富了吗？妹妹现在才两岁，对于很久没见到的我似乎已经忘记了怎么称呼，嘴里只是重复着“不知道”这几个字。吃完饭后她的娱乐活动则是看英文版的小猪佩奇...看完几集后她似乎是困了，但却不愿意离开电视机前，一被抱起来后就开始哭。舅妈只好给她冲了一袋牛奶，把她引到餐桌那边去喝，没想到的是她更感兴趣的却是桌上的奶粉，甚至感觉比起牛奶，她更喜欢一点一点地吃奶粉。舅妈也和我聊了很多，说哥哥前一阵子参加了在深圳举办的英语演讲比赛，还让我看了他的视频，不仅发音标准，还附带表情动作。我去，这比我的拿院级优胜奖的水平不知道高到哪里去了[允悲]，没想到这还只拿了三等奖。我关切地问到他一般几点钟睡觉，结果是11点，这比我小时候整整晚了2个多小时啊，我不禁感到了一种无形的压力，这样的教育对孩子真的有帮助吗？尽管舅妈说她并没有要求她这么晚睡觉，只是作业做着做着，玩着玩着就到了这么晚。家里给他报的辅导班也并不多，只有作文奥数足球书法机器人罢了[喵喵]，比起其他的孩子还差得远呢。这大概率是来自于家长老师间的无形比较，只希望自己的孩子不输在起跑线上。可是，人生哪有这么简单呢，我只希望他们的童年能快乐一些，不要早早误认为学习是一种痛苦的过程。嗯，现在看上去他还蛮快乐的，只是多了一份无名的急躁情绪。哥哥今晚听取了我的建议，早早的做完了作业，9点钟就到床上听故事了，我则是10点给他关的灯。此刻，睡意正浓。
还记得小时候亲戚朋友们都喜欢问孩子们长大了想上什么大学，等待着“我要上清华北大”这几个字从稚嫩的孩子口水出现，也许这代表着一种乐观态度，也许这就是大人逗小孩的游戏，其实只是因为他们只知道这几所大学。从小我就知道，清华北大对于我这种既不是天才又不够勤奋的人来说是不可能的。到了高中，开始真正的需要考虑去哪个大学读书这个问题了。湖大好像就在长沙，我以前去长沙岳麓山玩还去过几次，感觉也不是很遥远啊，还是隔壁的中南大学好，名字都听上去响亮一些。现在回想起来，无非就是距离产生美嘛，无知的我也大概只知道10来所大学的名字，后来了解到大部分还是在教室后面张贴的重点大学名单上看见的。高中后期看到老师们提出像衡水中学学习的口号我就本能地感到反感，那时，每个人都信心满满地说着要考600分、650分，只有我比较真实，默默说出了550分这个数字，可能是理想与现实最接近的一次。也不算很快，就到了高考填志愿的日子了，看着自己飘在一本线边的分数感觉还是有那么一丝遗憾，学校大概是选不了了，之前买的一本课堂内外出的志愿填报指南大概率也是没用了。只好把湖南省去年的院校线拿出来降序排列，看看还有哪个学校收我。专业大概也是随便填的，本来前几个都是电子信息类的专业，但最后我又把第二专业志愿改成了应用心理学，第三志愿改成了环境科学。为什么要这么填呢？不过就是看了几本心理学的书觉得挺好玩的，再就是高三时看了柴静拍的纪录片《穹顶之下》里面的数据旁边都标了一个某某大学环境科学专业提供，瞬间触动了我内心深处，感觉这个专业还是挺高大上的嘛，做着这么多与人类命运息息相关的事情。把这个志愿传到了学校发的那张卡上的志愿测评系统里，显示我有80%的概率被农大的环境科学专业录取，果不其然，我真的被录了。第一天来到农大，满心都是欢喜，开心得像个孩子，尽管宿舍条件实在是让我懵逼了，不过好在其他的一切都还不错。大一时的生活倒也是平淡如水，也就拿了一个校级的程序设计大赛的奖。也许是机缘巧合吧，大二又成功转到了计算机专业。直到大三才知道了有保研这回事，最后也算是顺利拿到资格吧。其实可以选择的学校有三个：湖大、中南和华工，本来还是挺喜欢华工的，但是导师却不尽如人意，反而把我鸽了，我也只能技不如人，甘拜下风，只好跑路会中南。尽管这个学校不是最满意的，不过也算是实现了自己以前的愿望吧，更何况导师的人挺好。最后要感谢我所有的同学和朋友，很幸运能认识你们，希望大家工作考研顺利。中南大学，我来了！
知足是什么？知足应该是一种平和的心态，满足于当下所拥有的一切，懂得适可而止。大学是无数高中生梦寐以求的高等学府，这不仅是进入社会的起点，还是青春的最后一站，这里理应充满着灿烂的阳光，和谐的景色与充满朝气的学子们。看到这样美好的场景，即使用尽世间一切赞美，也不能表达出内心的喜悦之情。既然条件如此优越，这里的人们应该是知足的，可惜事实并不是如此简单。大学里经常有同学成天闷闷不乐，总是在怨天尤人，觉得老师不够博学，同学不够友善，就连食堂阿姨也不够大方，总之就是一句话，这个地方配不上我。这可以说是不知足的典型表现，早知如此，为何高中不再刻苦一些呢？年轻的我们不需要对过去感到遗憾，应该脚踏实地，仰望星空。既然现在环境不尽如人意，那么就应该去改造这个不让人满意的环境。而且要知道，能够进入大学学习就已经是一件很幸运的事啦，那么多因为各种各样原因早早辍学而去打工的年轻人，哪个不羡慕着不用为琐碎的生活而烦恼的时光呢？我们应该感到知足，毕竟我们的家庭条件能让我们在这短暂的大学时光里收获一些纯粹的友情和知识，而不是提早步入残酷的社会竞争中。也许会有人说，知足意味着好吃懒做，放弃对未来的追求。但是我认为知足并不意味着放弃进取，而是对自己现状的肯定。因为知足，所以快乐。伴随着已有的快乐就又可以继续追求更好的生活。知足也不是只有在完美的生活中才能找到，没有人能拥有完美的经历，如果生活被安排得一帆风顺的，那么这个世界未免也太过于平淡。生活中的挫折恰恰是白色画布上的一些点缀，在失败中积累经验才能让我们走得更远。在平凡的生活中克服困难后，这便收获了全新的自我。知足其实意味着自己达到了预期的目标，而不知足则常常意味着要求偏高甚至不切实际。上一个时代的媒体在传递着新闻资讯，而新时代的媒体却善于贩卖焦虑。无穷无尽的虚假焦虑推动着自我预期的膨胀，今天想着自己没有完成的学习目标，明天又想着如何才能拥有丰富多彩的生活。这难道不是很讽刺吗？这样的人会永远的深入到不知足的循环中去，永远也不能被救赎。知足常乐要求我们用平和的心态看待荣辱得失，它并不意味着安于现状，而是要承认自己的不足，感恩自己当下的生活，并用一颗进取的心去开创未来。希望每一个知足者都能快乐，每一个快乐者都能知足！
为什么这么多姑娘都要做“精致的猪猪女孩”
文：宋婉心 / 界面新闻记者来源：界面新闻女孩Stella热爱美甲，曾经在大学期间经营过一间美甲铺子。这间铺子借着宿舍的地盘开张，做的也都是同学的生意，所以定价很低。在接待了一系列让她头疼的顾客之后，她深感价格影响客群的真理，“好像大家觉得做个美甲，自己就可以和精致挂上钩了。”令她印象最深刻的一个姑娘是从她这里第一次接触美甲，“她之前是一个连剪指甲都会剪秃的那种女孩。”Stella觉得这姑娘可能是决心想打扮一下自己，便打算从做指甲开始。然而女孩的审美水平却跌破了Stella的想象，“我按照她的外形打扮给她推荐了几款最百搭的纯色，但是她执意要做镶满水钻的那个，说真的，做出来之后的效果我都不敢看，但你却根本想象不到做成后她自己有多开心。”“现在回想起当时来我这里做美甲的顾客，可能都是‘精致的猪猪女孩’吧。”Stella说道。谁是精致的猪猪女孩在以瘦为美的当下，微博、知乎等社交媒体上正有越来越多的女生开始争先恐后地给自己冠上“猪”的名号，“精致的XX后”这个名头的出场频率也颇高。按照通行的说法，“猪猪女孩”可能不具备高水准审美、外形条件也并不突出，但在打扮自己方面下的功夫却丝毫不比各位博主少，有时哪怕只是下楼去倒个垃圾，她们也会花上两个小时化妆。“猪猪女孩”据说最早产生于一位微博用户@休闲璐发布的内容，她指出猫猫狗狗已经过气，猪将是下一个人们追捧的动物，并且给出了猪猪女孩的定义，指那些又笨又傻，笑点很低，神经比较大条但对朋友十分仗义的姑娘，但并不带有明确的贬义。后来，社交媒体上的用户又为猪猪女孩加上了“精致的”定语，比如她们热爱自拍，不是妆容精致就是面膜加持，通常是生活在都市的白领女生或者在大学中享受校园生活的学生族，口中嚷着“今天也是精致的猪猪女孩”或“即使生活艰难险阻，也要坚持做精致的猪猪女孩”，但其所谓的“艰难生活”顶多也只是加班出差、赶ddl、或是一些“先天不足”的烦恼。随着流行语一起盛行起来的是配套的表情包，英国学前教育电视动画片《小猪佩奇》中主人公小猪佩奇的形象被网友拿来当成了“猪猪女孩”的教科书范本，由于小猪佩奇动画风格极简，表情主题一目了然，再加上文案引导，用成年人娱乐八卦中的流行用语和动画本身低龄化的内容形成反差，则成了网友斗图的海量表情包库。除了佩奇以外，一个带有婴儿肥的女孩照片也被拿来贴上了精致猪猪女孩的标签。乐观和上进是猪猪女孩生活态度里的关键词。有网友发现，美剧《了不起的麦瑟尔女士》高度符合这类型女孩的定义，在豆瓣上的评分高达9.3分，剧中女主角几乎每十分钟就要换一套服装，其中一段经典片段更是在网络上广为流传：视频中，麦瑟尔在和老公互道晚安关灯睡觉后，偷偷趁老公睡着起身去洗手间卸妆、卷头发，又赶在老公醒来之前去洗手间化好裸妆、弄好发型，再回到床上假装睡着。不幸的是，没多久麦瑟尔就经历婚变，但丝毫没有影响她保持独立而精致的生活状态，让一众“猪猪女孩”瞠目结舌，视她为榜样。“浅薄”的精致“精致的猪猪女孩”渐渐在口口相传的过程中演化成了一种人设标签。这种现象级语汇依赖于病毒式的传播，提醒着每个人在网络热点上都不能掉队。语言学中有“模因”一说，即信息在广义上的模仿过程而被复制，是大多数网络流行语背后的传播动因，用户在模仿的过程并不自知，但却不知不觉中复制了信息源，每一个网民个体都构成了模因的一部分。标签背后代表的是一种人生态度和生活方式，也是一种站队。类似标签的应用近年已经从蛇精发展到了猪精，又有了最近的佛系和中年少女，也许每个人都能在时兴的流行语后对号入座。某种意义上，“猪猪女孩”代表着平凡无奇的普通人，在此基础上加上了定语“精致的”，可以看出在当下物质消费水准被推上新高度的环境下，大众对生活标准有了新的要求。这个过程也伴随着商业的发展，如各类型品牌都在利用新的消费需求进行营销，试图创造出一个消费不断在追求升级的氛围和文化。是微博上的美妆大V们最早打出了“精致的猪猪女孩最爱的韩妆限量”等名号，博主和KOL的博文也把“精致的猪猪女孩”作为宣传角色给消费者安利口红眼影等产品，不然就是从护手到护发等局部护理产品的推荐，家居日用品等快消品牌也在教导消费者注意细节，称这样做才是“真正的精致”，而餐饮美食的网红店更是抓住机会吸引本就爱吃爱拍照的猪猪女孩。不过，这些所谓的“精致”更多浮于表面，是外显式的精致、让别人看得到的精致——即使穷到回家啃馒头也要买下博主推荐的眼影盘，每个也许过得不怎么好的猪猪女孩，也都要让自己“看起来过得很好”。这是一种表演，是不带没任何情感倾向的最普遍的日常生活。只是在这个互联网时代，表演在虚拟化空间里拥有了更为独立的舞台。如今，网络和媒体拥有了明显的工具化特征，暗藏套路和技巧，相比于网络还没有普及的年代，现在的人们省去了面对面的尴尬和隔阂，缩短了从相识到相知的时限，大多数情况下，通过屏幕上的文字和图片就可以树立对别人的印象，这使自我展示的过程更加容易且快捷，也变得更加容易被操作。事实上，对于“精致的猪猪女孩”来说，是“精致”在定性该词的价值取向，它体现出了女孩们对生活有所控制的愿望。“猪猪”不过是以退为进，它的存在只是为了让社交网络上的自夸显得更为含蓄。毕竟，姑娘们都是从好几百张自拍中挑上一张再P上俩小时才发到网上，又有谁真的觉得自己是“猪猪”呢？现代女性承担了越来越多的社会压力，她们需要通过一些力所能及的小事情增加对生活的掌握，在加班工作和养育子女之间忙得蓬头垢面时，可能敷个面膜或者涂个口红都可以让自己从其中跳脱出来，这在社会心理学中被称为对生活的“可控性”，生活可控性的提高和生活满意度成正比，也是最基本的生活需求。相较于更早流行的带有贬义的“猪精女孩”，“猪猪女孩”是乐观派的自嘲，它给了女性一个“示弱”的台阶，宣告她们在坚强背后，也可以有更多不依附于人、不取悦于人、不符合主流价值取向的个性和选择。网络游民的归属感不过，这代表着“精致的猪猪女孩”是一种女权主义吗？答案恐怕并没有那么简单。在美国，曾经也出现过一股“猪猪女孩”风潮，它就是诞生于1974年的Miss Piggy。你一定见过她的样子或看过她的故事，在美国电视节目《布偶秀》中，猪猪小姐Miss Piggy在爱荷华州的一个小镇上长大，因为年幼时父亲去世，母亲对她也不好，Piggy从小的成长环境就很糟糕，这催生了她想要离开家乡参加选美比赛的想法。自此之后，Miss Piggy身体力行地展示了如何成为一个后天美女的励志故事，她上进乐观、永不言败，看起来很像是“猪猪版”日本网红渡边直美。越来越有名的猪猪小姐渐渐拥有了属于自己的综艺秀，这也是上个世纪唯一以女性角色为主的电视节目。随着这个角色的走红，Miss Piggy在当时美国的女权运动大潮中悄然成为担当，宣告着受困于家庭环境和自身条件的女性有权力也应当有勇气追逐梦想。而当美国的中上层女性在家庭和事业、自我追求和社会认同中平衡和取舍时，如今生活在中国北上广等一线城市受过良好教育的女性也在面临着同样的课题。曾有一篇名为《为什么斯堪的纳维亚的女人令全世界嫉妒》的文章在社交媒体上被大量转发，文章写到：“2013年的《全球性别差距报告》显示，冰岛的女人基本上拥有一切（指家庭、工作、政治经济参与的广度和深度，以及个人的幸福），在芬兰、挪威以及瑞典的姐妹同样过得相当不错。在这份报告中，这些国家占领了前四名，而美国却排在令人沮丧的第二十三位，比去年还略有下降。”因此，作者指出美国女性因为男女平权不被满足曾在社群中找不到归属感，而在中国的2017年里，从SKII“小梦想VS大无畏”的广告片到电视剧《我的前半生》、《欢乐颂》等，女性话题也在不断地被提出和议论。但事实上，喻物于人并不只发生在女性身上。此前最流行的莫过于将男友划分为犬系男友和猫系男友，犬系男友指代的是那些性格较为主动和外向，喜欢运动玩闹，有些神经大条的男生，而猫系男友则说的是比较内向高冷，经常拒人于千里之外，不善与人打交道但心思却十分细腻的男生。除此以外、还有领导力爆棚的狮子男友、温暖的考拉系男友等说法，这到底是对动物的拟人化，还是对人性的拟物化，其实并不好区分，但本质上说，它们都是一种符号化。符号方便人们自我定义、寻找同类，也促进着商业世界对消费者进行解构。在数字经济上，符号化的群聚效应在女性身上要比在男性身上明显得多。“她经济”决定了女性是移动互联网上最大口碑扩散群体，她们在购买特定物品的时候，如果遇到了购买相同物品的人，会更容易产生共鸣。这些年来，互联网的普及也使得符号化有了急速发展的空间，网络用语和图案都成为符号化的载体。据中国互联网信息中心发布的《第40次中国互联网发展状况统计报告》称，截至2017年6月，中国网民仍以10-39岁群体为主，占整体的72.1%，年轻的网民造成了网络流行语的年轻化，他们对于网络用语和符号的加工更偏向戏谑讽喻的风格，但不管是自黑还是吐槽他人，这都是向身边人发送确认是否是同类的信号。在这一点上，人类和任何哺乳动物无异。这也是如今各大品牌都在培育社群的缘由，这种战略所能带来的最大好处就是提供归属感，就像过去的人们通过身上的纹身来划分部落一样。从“猪猪女孩”“佛系女孩”到“犬系猫系男友”，无不是对身份的识别和辨认，用哲学家维特根斯坦的话说：“凡是能够言说的世界，就是我们能够掌握的世界。如果不能言说出来，也就是不能把它符号化、简化的世界，我们只好保持沉默。”——最后，我们采访了三个行业的从业者，来看看他们如何定义“精致”。奢侈品店店员 雨薇如果说精致能和事儿多画上等号的话，那估计我们的顾客几乎都是精致女孩了吧。曾经有一位中央电视台的歌手来到我们店里，当时我才刚入职没多久，完全还是小朋友，她看出来我完全镇不住她之后更是得寸进尺。在试衣过程中，她会故意挑刺，两件相同的衣服，只试货架上那件，不接受仓库中拿出来的货品。这些人就是拿我们不当人看吧，在他们的概念里，有钱就是有品，所以我们在服务过程中提出的任何搭配建议，她们都会看作是对她们眼光的不尊重，被骂就是家常便饭了。最重要的是，有时来折腾我们一圈，一件不买就走了。虽然这么说不好，有些VIP打扮得像模像样的，但行为举止和菜市场大妈没什么区别。纹眉师 Judy眉毛对于女孩子太重要了。很多姑娘拿着明星的照片过来，让我们给做一个一摸一样的眉形，我们真的不好明说，明星的妆容其实几乎没有任何参考价值，除非你这张脸除了眉毛其他零部件都长得和明星一样。大多数还是想自己卸妆之后也有个好看的眉毛吧，特别是那些和男友一起住的女生，毕竟有眉毛人就精神些。这样的理由我很能理解，但没有人能保证24小时都精致的吧，生活已经很累了。男朋友不能接受自己最差一面，他又凭什么拥有你最好的一面呢。有一个小姑娘要求极度苛刻，挑了我们店最贵最仿真的款式，做的过程中一直在嘱咐我要做得自然，为的是一场两周后的面试，她觉得做个眉毛能让自己自信一些。说真的，这女孩原本就已经很美了。美容师 Jeanne打针已经是家常便饭了。每个人的要求都不一样，有些姑娘来了就是想祛痘，脸上能够干净光滑一些她们就觉得知足了，但是现在医美的发展速度太快了，有些姑娘打水光针、瘦脸针是会上瘾的，不过打一针就能变美的诱惑力谁又能抵抗得了呢？来我们店里的应该都是精致姑娘吧，即使不是，也很想成为精致姑娘。主要还是现在最不缺的就是漂亮姑娘吧，大街上一抓一大把，这样的情况下很难不焦虑，跟顾客聊天时也会发现，很多都是带着心理问题来的。
有时候一直在想，人生的意义是什么？在大学前，我们的生活轨迹一成不变，每天都是伴随着清晨的阳光从家里出发，又在同学们的玩耍中从学校返回，生活无忧无虑，需要思考的也只是学习成绩和同学关系。前途总是光明的，一切事情都不需要额外的选择。高中老师有句名言：“上了大学就轻松了”。似乎大学就是一个可以畅谈人生理想，与同学一起学习奋斗，实现自我价值的地方。可是，当上了大学后，发现一切都没有那么简单。尽管再也不需要没日没夜备战高考，但需要考虑的事情却变得很多很多。来大学前，我总是想着大学里丰富多彩的生活，能在社团里找到一些志同道合的朋友，很可惜，社团里总是一小群人玩得不亦乐乎，而大多数人只能做一个旁观者，然后被遗忘在角落。也许是这些社团活动方式有点问题，也许是我自己没能更加主动参与进去，无论怎么说，这都是我一个小小的遗憾。一个个在高中拼命学习才能考上大学的少年，在来到大学后，却选择了一条最轻松的道路，每天沉迷游戏刷剧，过着得过且过的生活。不在乎学到了什么知识，只关注考试能不能及格。不反思自己上课时没认真听讲，只苛求老师讲课不够生动。其实娱乐并不是一件坏事，适当的娱乐是再生产的一部分，能帮助人恢复精力投入到接下来的生活当中。但沉湎于娱乐之中，遗忘学生的本职工作——学习，便是一件得不偿失的事情了。面对着这些娱乐至死的同学，我想是不是因为高中过于紧张的学习消耗掉了我们自身的学习动力了呢？还是说认为考上大学，就意味着前途一片光明？我不知道答案，但要知道很多人往往没有机会参加高考，他们早已消失在了每一个开学的秋季。而我幸运的能参加高考并考上大学，而不是早早辍学外出打工。除了那些浑浑噩噩的同学，还有一部分同学则看上去非常优秀，他们学习优秀，身兼数职，参加各种各样的竞赛活动；坚持运动，琴棋书画样样精通，还时不时会来一场说走就走的旅行。这似乎是大多数学生的榜样，相信自己总有一天会成为像他们一样，成为自己想成为的人。这种评价标准似乎伴随着我们的整个大学生涯，但我们有没有想过，这究竟是不是我自己内心的真实想法呢？哈佛招生主任，威廉·R·费茨蒙斯中曾说到：就算那些最成功的学生，也会在某个时刻思考一切是否都值得。在他们三四十岁时，他们是社会公认的有成就的医生、律师、学者、商人，但他们往往感到，自己不过是一群在终生竞争的集中营里茫然的生还者。我们的价值观经常被社会绑架着，无处不在的主流价值观让我们随波逐流，有些人在其中遗失了自我，有些人则想方设法逃离，前去寻找真正的自我。孔子曾说，吾日三省吾身，在前进的道路上应该多回头看看自己走过的路，这究竟是不是有价值的，如何才能实现自我。有个同学问我，“为什么你能对所有事情保持一种热情”，我想这正是因为我认识到人需要认清自我，只有积极地探索自我，才能度过有意义的一生。人生本没有意义，只有自己才能赋予人生意义。
击败DotA2顶级人类玩家，并不是AI的一次突破
文：Denny Britz（前谷歌大脑团队成员）来源：量子位 当我昨天看到OpenAI的人工智能，在一项奖金2400万美元的电子竞技赛事上，击败DotA2人类顶级高手时，整个人感觉超兴奋。 这是因为，一方面我是一个电子竞技的粉丝。尽管没玩过DotA 2，但我经常在Twitch上观看其他其他电竞赛事，高中时我还当过一阵半职业选手。 更重要是的，像DotA这类多人在线战术竞技游戏（MOBA），以及星际2这类实时策略游戏（RTS），通常被认为远超目前人工智能的驾驭能力。因为这两类游戏需要长期战略决策、多人合作，比国际象棋、围棋有着更复杂的状态和动作空间。 DeepMind已经在星际2上研究了一段时间，前不久刚刚发布了新的进展，但目前为止，相关研究还没有取得重大突破。大家普遍认为，距离人工智能在星际2上吊打人类顶级玩家，至少还有一两年的时间。 这就是OpenAI这个成果如此令人震惊的原因。这是怎么回事？最有有什么人工智能方面的突破是我没有注意到的么？于是我开始研究这个DotA 2人工智能到底干了什么，它是如何训练的，以及在什么样的游戏环境中运行。 我的结论是：这是一个令人印象深刻的成就。但不是一次AI上的突破。 通过这篇文章，我想提供一个关于此事的清醒解释。实际上，过度炒作人工智能的进步才是真正危险的事情。例如，下面这位在推特上的发言，才是真正的误导。 这是伊隆·马斯克的推特，这位硅谷钢铁侠不单创办了特斯拉，而且创办了OpenAI。上面这篇推特中，马斯克大意是说：OpenAI搞出了史上首个击败电子竞技顶级玩家的人工智能。这比搞国际象棋和围棋什么的复杂多了。 在第二条推特中，马斯克再次发表曾被AI届猛轰的观点：没人喜欢被管制，但对公众构成危险的一切（汽车、飞机、食品、药物等）都应该受到管制。AI也是一样。 当然，马斯克还发了一条，就不翻译了，贴图如下 首先要声明的是，我今天要谈及的炒作或者误导，并不是OpenAI研究人员的错误。OpenAI一直在研究方面都有诸多贡献。目前，OpenAI还没有公布他们解决方案的细节，所以外界很容易就会得出错误的结论。 现在开始切入正题。我们先来看看DotA 2的人工智能程序，到底解决了一个多困难的问题？尤其是与AlphaGo相比。1v1不能与5v5相提并论 在正常的DotA 2游戏中，两个对抗的队伍各由五名玩家组成。游戏过程中需要高级策略、团队沟通和协调，一局比赛通常要45分钟。 而这次人工智能击败人类的比赛，采用了1v1的模式，这种模式有太多限制。例如双方基本上只能沿着单线前进，并尝试击杀对方，游戏过程几分钟就结束了。 在1v1模式中，击败对手主要靠机械技能和短期策略，并不涉及长期规划和协调，而后者才是对当前AI技术来说最具挑战性的部分。 事实上，在这次的人机DotA 2对抗中，可以采用的有效动作数量，少于围棋人机大战；有效的状态空间（目前局面情况），如果以智能的方式表示，应该比围棋要小。AI可以获取更多信息 OpenAI的人工智能程序，极有可能是构建在DotA 2原有的机器人接口之上，可以获取更多人类玩家看不到的信息。即使OpenAI的研究人员限制了这些信息的获取，人工智能仍然能够得到比人类更精准的信息。 例如技能的施放，人类玩家必须紧盯屏幕，并且估算与对手之间的距离。而AI知道确切的距离，并且能立即决定是否施放技能。获得精准的数字信息是一个很大的优势。其实对战过程中你就能看到，AI有几次攻击都是在最大距离上展开。反应时间 AI可以立即作出反应，人类不行。再加上刚才说的信息优势，AI的优势进一步扩大了。比方，一旦对手逃离攻击范围，AI可以立刻取消攻击命令。使用单一英雄 DotA 2中有上百种不同的英雄角色，各具不同的能力和优势。而AI掌握的只是其中一个英雄：Shadow Fiend（影魔）。影魔通常会立刻展开攻击，而不是在一段时间内学习掌握更复杂的攻击技能，这更加有利于发挥AI在信息和反应方面的优势。 所以，鉴于1v1主要比拼机械技能，AI击败人类玩家并不奇怪。鉴于游戏环境被严格限制，造成一些列战术和策略也被限制，而且对战中几乎没有必要进行长期规划或协调。 再次重申我的结论：这次AI击败DotA玩家，比在围棋中击败人类冠军要容易得多。人类没有在AI领域突然取得突破。 这次在DotA对抗中之所以AI获胜，是因为研究人员聪明的设置了问题，使得AI可以绕过目前人工智能的技术限制。 据说这个OpenAI训练这个AI打DotA花了2周。与之相比，AlphaGo在Google的GPU集群上进行了数月的分布式大规模训练。两个程序之间的计算要求有着数量级的区别。 最后夸夸这个会玩DotA的AI，到底有何精彩之处？完全通过自学训练 AI不需要任何训练数据，也不会从人类的比赛中学习。整个学习过程随机开始，并且通过和自己对抗进行学习。虽然这不是什么新技术，但令人惊讶的是，AI学会了人类玩家已经在使用的技术。这很酷。 AI可能还有其他技术，甚至人类都不知道。这与我们在AlphaGo中看到的类似，围棋选手已经开始学习AI的下棋方式。AI+电竞的重要一步 在具有挑战性的环境中（例如DotA 2和星际2）来测试AI技术是非常重要的。AI可以为游戏提供更多的价值，游戏也会助推AI更快发展。不完美信息 在DotA对决中，人类玩家智能看到地图的一小部分，视线受到妨碍。AI可能也一样，虽然还不清楚OpenAI如何处理这个问题的细节。 这意味着与围棋、国际象棋、Atari游戏机等环境不同，AI在DotA中处于一个部分可观察的环境，而无法获知关于游戏当前状态的完整信息。这类问题通常难以解决，话虽如此，但目前还不清楚1v1的DotA 2比赛中，视野的重要性到底几何。 不管怎样，非常期待看到OpenAI关于这次比赛的技术报告。
Dota2 AI 简易开发教程（二）——英雄出装及其相关功能
距离上一篇教程也过去一个多月了，是时候写一篇新教程了。上一篇文章主要介绍了如何选择阵容和技能的使用，在这一篇文章中，我们将介绍如何配置英雄出装和其相关的一些模块。勘误首先先纠正一下上一篇文章中的一些错误，在选择阵容部分，下面的table.remove函数中出现了一个错误，bad argument #2 to 'remove' (number expected, got string)，就是第二个参数应该为数字而不是字符串。这个错误将导致已选择的英雄不能从英雄列表中移除，从而会选择出重复的英雄。function Think() for i,id in pairs(GetTeamPlayers(GetTeam())) do if(IsPlayerBot(id) and (GetSelectedHeroName(id)=="" or GetSelectedHeroName(id)==nil)) then local num=hero_pool_my[RandomInt(1, #hero_pool_my)] --取随机数 SelectHero( id, num ); --在保存英雄名称的表中，随机选择出AI的英雄 table.remove(hero_pool_my,num) --移除这个英雄 end end end所以中间几行应该修改为，这样从表中才能正确移除已经选择的英雄 local i=RandomInt(1, #hero_pool_my) --取随机数 local heroname=hero_pool_my[i] --获取英雄的名称 SelectHero( id, heroname ); --在保存英雄名称的表中，随机选择出AI的英雄 table.remove(hero_pool_my,i) --移除这个英雄出装系统简介在官方开发者维基中有着这样的说明：物品购买如果你只想重写在购买物品时的决策，你可以在文件名为item_purchase_generic.lua的文件中实现如下函数： ItemPurchaseThink() - 每帧被调用。负责物品购买。 你也可以仅重写某个特定英雄的物品购买逻辑，比如火女(Lina),写在文件名为item_purchase_lina.lua的文件中。在dota 2 beta\game\dota\scripts\vscripts\bots_example V社的示例文件中，我们可以找到item_purchase_lina.lua文件，这就是为火女配置出装的文件。打开这个文件，我们可以看到：--这个表用来记录AI出装的顺序 local tableItemsToBuy = { "item_tango", "item_tango", "item_clarity", "item_clarity", "item_branches", "item_branches", "item_magic_stick", "item_circlet", "item_boots", "item_energy_booster", "item_staff_of_wizardry", "item_ring_of_regen", "item_recipe_force_staff", "item_point_booster", "item_staff_of_wizardry", "item_ogre_axe", "item_blade_of_alacrity", "item_mystic_staff", "item_ultimate_orb", "item_void_stone", "item_staff_of_wizardry", "item_wind_lace", "item_void_stone", "item_recipe_cyclone", "item_cyclone", }; ------------------------------------------------------------------------------------------ --用来实现基本的物品购买函数 function ItemPurchaseThink() local npcBot = GetBot(); if ( #tableItemsToBuy == 0 ) then npcBot:SetNextItemPurchaseValue( 0 ); return; end local sNextItem = tableItemsToBuy[1]; npcBot:SetNextItemPurchaseValue( GetItemCost( sNextItem ) ); --用于默认AI的相关函数 if ( npcBot:GetGold() >= GetItemCost( sNextItem ) ) --判断金钱是否足够 then npcBot:Action_PurchaseItem( sNextItem ); --购买物品 table.remove( tableItemsToBuy, 1 ); end end 大家注意到，在上面那个记录出装顺序的表中，物品的名称似乎和平时用的有所区别，其实也可以在这个页面找到。在上面这个函数中，V社为我们提供了购买物品的基本函数，但是这只能实现在泉水的商店中购买物品，如果要去神秘商店和边路商店购买物品怎么办呢？如果要配置多种出装风格应该怎么办？如何控制信使去购买物品？那就需要靠我们自己实现了。而且如果要配置物品出装，那么需要手动填写每一个配方。不过在V社最近的api更新之后，添加了一个函数GetItemComponents(sItemName)，可以直接获取物品的配方。下面，我们开始在V社的基本函数上逐渐添加更多的功能。在神秘商店和边路商店购买装备由于物品购买是一个通用的功能，所以我们可以在item_purchase_generic.lua中编写函数，以便重复调用。在默认AI的框架下，有两个模式用于物品购买secret_shop和side_shop，我们需要通过在主函数中控制前往神秘商店和边路商店购买物品。（尽管将选择前往哪个商店的功能耦合在一个函数中不好。更好的方法是在其它两个模式中重新编写GetDesire()函数。）在游戏中，一个能在神秘商店购买的物品必定不能在基地商店购买，而边路商店的物品则有可能来自于其他商店。所以便能通过IsItemPurchasedFromSideShop(sNextItem)和IsItemPurchasedFromSecretShop(sNextItem )函数来判断一个物品能在哪被购买，进而决定下一个物品的购买位置。 if(npcBot.secretShopMode~=true and npcBot.sideShopMode ~=true) then if (IsItemPurchasedFromSideShop( sNextItem ) and npcBot:DistanceFromSideShop() <= 2000) --只有在离边路商店较近时才前往边路商店 then npcBot.sideShopMode = true; end if (IsItemPurchasedFromSecretShop( sNextItem )) then npcBot.secretShopMode = true; end End然后我们在mode_secret_shop_generic.lua和mode_side_shop_generic.lua函数中分别实现控制英雄前往神秘商店和边路商店购买的操作。在开发者维基中提到了以下内容：模式重写如果你想在已有模式体系下修改某个模式逻辑的需求和行为，例如修改对线模式(laning mode)，你可以在文件名为mode_laning_generic.lua的文件中实现如下函数: GetDesire() - 每帧都被调用，需要返回一个0到1之间的浮点值，该值标志了该模式有多大可能成为当前激活模式 OnStart() - 当该模式成为当前激活模式时调用 OnEnd() - 当该模式让出控制权给其他被激活模式时调用 Think() - 当该模式为当前激活模式时，每帧都被调用。负责发出机器人的行为指令。 你也可以仅重写某个特定英雄的模式逻辑，比如火女(Lina),写在文件名为mode_laning_lina.lua的文件中。如果你想在特定英雄的模式重写时调用泛用的英雄模式代码，请参考附件A的实现细节。所以，我们便需要GetDesire()和Think()以重写该模式。当英雄离边路商店较近，而且下一件物品可以在边路商店购买时，英雄便不需要用信使或自己返回基地购买物品，而是直接前往边路商店。mode_side_shop_generic.lua 边路商店模式function GetDesire() local npcBot = GetBot(); local desire = 0.0; if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() ) --不应打断持续施法 then return 0 end if ( npcBot.sideShopMode == true and npcBot:GetGold() >= npcBot:GetNextItemPurchaseValue()) then local d=npcBot:DistanceFromSideShop() if d<2000 then desire = (2000-d)/d*0.3+0.3; --根据离边路商店的距离返回欲望值 end else npcBot.sideShopMode = false end return desire end function Think() local npcBot = GetBot(); local shopLoc1 = GetShopLocation( GetTeam(), SHOP_SIDE ); local shopLoc2 = GetShopLocation( GetTeam(), SHOP_SIDE2 ); if ( GetUnitToLocationDistance(npcBot, shopLoc1) <= GetUnitToLocationDistance(npcBot, shopLoc2) ) then --选择前往距离自己更近的商店 npcBot:Action_MoveToLocation( shopLoc1 ); else npcBot:Action_MoveToLocation( shopLoc2 ); end endmode_secret_shop_generic.lua 神秘商店模式function GetDesire() local npcBot = GetBot(); local desire = 0.0; if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() ) --不应打断持续施法 then return 0 end if ( npcBot.secretShopMode == true and npcBot:GetGold() >= npcBot:GetNextItemPurchaseValue()) then local d=npcBot:DistanceFromSecretShop() if d<3000 then desire = (3000-d)/d*0.3+0.3; --根据离边路商店的距离返回欲望值 end else npcBot.secretShopMode = false end return desire end function Think() local npcBot = GetBot(); local shopLoc1 = GetShopLocation( GetTeam(), SHOP_SECRET ); local shopLoc2 = GetShopLocation( GetTeam(), SHOP_SECRET2 ); if ( GetUnitToLocationDistance(npcBot, shopLoc1) <= GetUnitToLocationDistance(npcBot, shopLoc2) ) then --选择前往距离自己更近的商店 npcBot:Action_MoveToLocation( shopLoc1 ); else npcBot:Action_MoveToLocation( shopLoc2 ); end end然后需要在主购买函数中检查英雄是否已经到达神秘或野外商店附近，并购买物品。 local PurchaseResult --接收购买结果，后文会介绍 if(npcBot.sideShopMode == true) then if(npcBot:DistanceFromSideShop() <= 200) then PurchaseResult=npcBot:ActionImmediate_PurchaseItem( sNextItem ) end elseif(npcBot.secretShopMode == true) --如果目标是神秘商店，则命令信使购买物品 then if(npcBot:DistanceFromSecretShop() <= 200) then PurchaseResult=npcBot:ActionImmediate_PurchaseItem( sNextItem ) end local courier=GetCourier(0) if(courier==nil) then BuyCourier() --没有信使的话则会购买 else if(courier:DistanceFromSecretShop() <= 200) --信使已到达商店 then PurchaseResult=GetCourier(0):ActionImmediate_PurchaseItem( sNextItem ) end end else PurchaseResult=npcBot:ActionImmediate_PurchaseItem( sNextItem ) end购买信使的函数function BuyCourier() local npcBot=GetBot() local courier=GetCourier(0) if(courier==nil) --购买小鸡 then if(npcBot:GetGold()>=GetItemCost("item_courier")) then local info=npcBot:ActionImmediate_PurchaseItem("item_courier"); if info ==PURCHASE_ITEM_SUCCESS then print(npcBot:GetUnitName()..' buy the courier',info); end end else --购买飞行信使 if DotaTime()>60*3 and npcBot:GetGold()>=GetItemCost("item_flying_courier") and (courier:GetMaxHealth()==75) then local info=npcBot:ActionImmediate_PurchaseItem("item_flying_courier"); if info ==PURCHASE_ITEM_SUCCESS then print(npcBot:GetUnitName()..' has upgraded the courier.',info); end end end end检查购买结果npcBot:Action_PurchaseItem( sNextItem )函数会返回一个购买结果的值，其可能的值为： Item Purchase Results PURCHASE_ITEM_SUCCESS --成功购买 PURCHASE_ITEM_OUT_OF_STOCK --物品栏已满 PURCHASE_ITEM_DISALLOWED_ITEM --不被允许的物品 PURCHASE_ITEM_INSUFFICIENT_GOLD --金钱不足 PURCHASE_ITEM_NOT_AT_HOME_SHOP --不在基地商店 PURCHASE_ITEM_NOT_AT_SIDE_SHOP --不在边路商店 PURCHASE_ITEM_NOT_AT_SECRET_SHOP --不在神秘商店 PURCHASE_ITEM_INVALID_ITEM_NAME --不存在的物品名称在购买物品时，用一个变量记录购买结果，并随后检查，以免出现购买失败的情况。local PurchaseResult=npcBot:ActionImmediate_PurchaseItem( sNextItem ) if(PurchaseResult==PURCHASE_ITEM_SUCCESS) --成功购买便从出装表中移除该物品 then npcBot.secretShopMode = false; npcBot.sideShopMode = false; table.remove( ItemsToBuy, 1 ) end if(PurchaseResult==PURCHASE_ITEM_OUT_OF_STOCK) --物品栏已满，出售多余的物品 then SellExtraItem() end if(PurchaseResult==PURCHASE_ITEM_INVALID_ITEM_NAME or PurchaseResult==PURCHASE_ITEM_DISALLOWED_ITEM) --不存在的物品，移除该物品 then table.remove( ItemsToBuy, 1 ) end if(PurchaseResult==PURCHASE_ITEM_INSUFFICIENT_GOLD ) --金额不足（其实该情况也较少出现，因为我们已经在上面判断了金钱） then npcBot.secretShopMode = false; npcBot.sideShopMode = false; end if(PurchaseResult==PURCHASE_ITEM_NOT_AT_SECRET_SHOP) --不在神秘商店，前往神秘商店 then npcBot.secretShopMode = true npcBot.sideShopMode = false; end if(PurchaseResult==PURCHASE_ITEM_NOT_AT_SIDE_SHOP) --不在边路商店（其实该情况不会出现，因为在边路商店的物品能在其他商店购买） then npcBot.sideShopMode = true npcBot.secretShopMode = false; end if(PurchaseResult==PURCHASE_ITEM_NOT_AT_HOME_SHOP) --不在基地商店（也不会出现的情况，因为如果英雄不在家中，那么物品会购买于贮藏处） then npcBot.secretShopMode = false; npcBot.sideShopMode = false; end两个效用函数，用于判断物品栏是否已满和出售特定物品function SellSpecifiedItem( item_name ) --出售特定物品 local npcBot = GetBot(); local itemCount = 0; local item = nil; for i = 0, 14 do local sCurItem = npcBot:GetItemInSlot(i); if ( sCurItem ~= nil ) then itemCount = itemCount + 1; if ( sCurItem:GetName() == item_name ) then item = sCurItem; end end end if ( item ~= nil and itemCount > 5 and (npcBot:DistanceFromFountain() <= 600 or npcBot:DistanceFromSideShop() <= 200 or npcBot:DistanceFromSecretShop() <= 200) ) then npcBot:ActionImmediate_SellItem( item ); end end function SellExtraItem() --出售已经没有用处的物品 if(GameTime()>15*60) then SellSpecifiedItem("item_faerie_fire") SellSpecifiedItem("item_enchanted_mango") SellSpecifiedItem("item_tango") SellSpecifiedItem("item_clarity") SellSpecifiedItem("item_flask") end if(GameTime()>20*60) then SellSpecifiedItem("item_stout_shield") SellSpecifiedItem("item_orb_of_venom") end if(GameTime()>30*60) then SellSpecifiedItem("item_branches") SellSpecifiedItem("item_bottle") SellSpecifiedItem("item_magic_wand") SellSpecifiedItem("item_magic_stick") SellSpecifiedItem("item_urn_of_shadows") SellSpecifiedItem("item_drums_of_endurance") end end信使控制信使又称为小鸡，一直都是dota中有很大用处的单位，一直以来都是各方神圣追杀的对象。但是因为7.00版本刚出时，默认AI的信使控制机制有些问题，不知道现在修复了没有。而且为了与我们之前所写的神秘商店控制系统配合，所以需要重写信使控制模块。在前文中我们提到过，信使控制的函数位于ability_item_usage_generic.lua的CourierUsageThink()中，所以我们只要在这个文件中重写此函数，便能完全地控制信使。信使有以下几种状态和命令，参见开发者维基。通过ActionImmediate_Courier( hCourier, nAction ) 函数命令信使，int GetCourierState( hCourier )函数则能获取信使的状态。Courier Actions and States COURIER_ACTION_BURST --加速 COURIER_ACTION_ENEMY_SECRET_SHOP --前往敌方的神秘商店 COURIER_ACTION_RETURN --返回基地 COURIER_ACTION_SECRET_SHOP --前往神秘商店 COURIER_ACTION_SIDE_SHOP --前往边路商店 COURIER_ACTION_SIDE_SHOP2 --前往边路商店 COURIER_ACTION_TAKE_STASH_ITEMS --拾起物品 COURIER_ACTION_TAKE_AND_TRANSFER_ITEMS --拾起并运送物品 COURIER_ACTION_TRANSFER_ITEMS --运送物品 COURIER_STATE_IDLE --空闲 COURIER_STATE_AT_BASE --处于基地 COURIER_STATE_MOVING --移动 COURIER_STATE_DELIVERING_ITEMS --运送物品 COURIER_STATE_RETURNING_TO_BASE --返回基地 COURIER_STATE_DEAD --信使已死亡 所以信使控制模块需要先检测信使的状态，然后再根据英雄是否有装备需要运送来决定信使的行为。以下便是信使控制主函数function CourierUsageThink() local npcBot=GetBot() local courier=GetCourier(0) --获取信使句柄 if(npcBot:IsAlive()==false or courier==nil or npcBot:IsHero()==false or npcBot:HasModifier("modifier_arc_warden_tempest_double")) --判断使用者是不是真正的英雄 then return end local state=GetCourierState(courier) --获取信使状态 local burst=courier:GetAbilityByName("courier_burst") local CanCastBurst=burst~=nil and burst:IsFullyCastable() --检查信使加速能否使用 if(state == COURIER_STATE_DEAD) --信使已死亡 then return end if(courier:GetHealth()/courier:GetMaxHealth()<=0.9) --信使受到攻击，立刻回家 then if(CanCastBurst) then npcBot:ActionImmediate_Courier(courier, COURIER_ACTION_BURST) end npcBot:ActionImmediate_Courier(courier, COURIER_ACTION_RETURN) return end if(state == COURIER_STATE_IDLE) --信使处于空闲状态10秒以上则回家 then if(courier.idletime==nil) then courier.idletime=GameTime() else if(GameTime()-courier.idletime>10) then npcBot:ActionImmediate_Courier(courier, COURIER_ACTION_RETURN) courier.idletime=nil return end end end if(state == COURIER_STATE_RETURNING_TO_BASE and npcBot:GetCourierValue()>0 and not utility.IsItemSlotsFull()) --运送物品 then npcBot:ActionImmediate_Courier(courier, COURIER_ACTION_TRANSFER_ITEMS) return end if (state == COURIER_STATE_AT_BASE ) --从基地运送 then if( npcBot:GetStashValue() >= 400) then if(courier.time==nil) then courier.time=DotaTime() end if(courier.time+1<DotaTime()) then npcBot:ActionImmediate_Courier(courier, COURIER_ACTION_TAKE_AND_TRANSFER_ITEMS) courier.time=nil end return end end if(state == COURIER_STATE_AT_BASE or state == COURIER_STATE_RETURNING_TO_BASE) --前往神秘商店 then if(npcBot.secretShopMode == true and npcBot:GetActiveMode() ~= BOT_MODE_SECRET_SHOP) then npcBot:ActionImmediate_Courier(courier, COURIER_ACTION_SECRET_SHOP) return end end if(state == COURIER_STATE_DELIVERING_ITEMS) --当信使正在运送物品时加速 then if(CanCastBurst) then npcBot:ActionImmediate_Courier(courier, COURIER_ACTION_BURST) end end end最后需要每个英雄调用主函数。例如ability_item_usage_zuus.lua。function CourierUsageThink() ability_item_usage_generic.CourierUsageThink() end示例为宙斯配置的出装：ability_item_usage_zuus.luarequire( GetScriptDirectory().."/item_purchase_generic" ) local ItemsToBuy = { "item_tango", "item_clarity", "item_branches", "item_branches", "item_faerie_fire", "item_bottle", "item_boots", "item_energy_booster", --秘法鞋 "item_mantle", "item_circlet", "item_recipe_null_talisman", --无用挂件 "item_mantle", "item_circlet", "item_recipe_null_talisman", --无用挂件 "item_helm_of_iron_will", "item_recipe_veil_of_discord", --纷争 "item_void_stone", "item_energy_booster", "item_recipe_aether_lens", --以太之镜7.06 "item_staff_of_wizardry", "item_void_stone", "item_recipe_cyclone", "item_wind_lace", --风杖 "item_point_booster", "item_staff_of_wizardry", "item_ogre_axe", "item_blade_of_alacrity", --蓝杖 "item_point_booster", "item_vitality_booster", "item_energy_booster", "item_mystic_staff", --玲珑心 } function ItemPurchaseThink() purchase.ItemPurchase(ItemsToBuy) --将出装表传至主函数 end总结看完了这篇文章后，大家应该能够了解AI出装的相关功能了，虽然说这篇文章因为作者太懒拖了很久，不过还是要比V社好一点。V社说好的战役第二章迟迟没有推出，即将重新定义“七月下旬”。下面上张图。附件1.示例代码
原来以为MySql从删库到跑路只是句笑话，没想到是真的。这学期才学数据库原理，以前人们总是说数据要经常备份，不然哪一天就会后悔，果然昨天我就碰到了这么倒霉的情况...昨天晚上没事做，发现typecho后台文章cid的变化有些奇怪，按道理来说主键自增不会出现突变，可是cid有时却从50多跳跃到了90。于是我便在百度上找到了这个坑爹帖子。本来想着是优化一下数据库表的结构，直到运行了这个sql语句后TRUNCATE TABLE typecho_contents，突然发现，咦？为什么查询不到结果了？？？原来数据库的一个表被我删掉了。当时就急了，这个作者什么都没提醒啊，我之前也没用过这个语句，根本就不知道这有什么用途，还以为只是优化一下表呢。百度一查，这个TRUNCATE语句就意味着DROP+CREATE...不仅删掉表，还重建了表。如果只是删掉了表，那么还可以通过闪回操作恢复，但这样之后就没办法恢复了。当时瞬间整个人就懵逼了，我从来没有手动备份过，不知道有没有自动备份。检查了一下，不仅没有自动备份，连事务日志都没有。正常的数据库级恢复方法当然就没有用了，只好跑去腾讯云那里发了个工单，看他们有没有自动备份硬盘。我真佩服腾讯的工程师，凌晨居然都还有值班的，回复我说：需要自己手动快照才能备份。好吧，这下就彻底GG了，之前的博客文章都是直接在typecho里写的，电脑上也没有备份，这么久的心血难道就毁于一旦了吗？还好想起了搜索引擎快照这个东西，百度一下果然没有，谷歌上一搜就找到了，赶紧连夜从谷歌快照上恢复了这么多博客文章。所以说数据库一定要备份啊！不仅需要数据库级的备份，也需要异机、异地备份，以防万一，不然就只能从删库到跑路了...PS：真正的修改方法是：alter table typecho_contents AUTO_INCREMENT=100;
Dota2 AI 简易开发教程（一）——选择阵容及技能使用
在第一篇教程中，我们主要介绍了Dota2 AI的基本情况，在这篇文章中，我们将介绍如何为AI选择阵容和技能使用（以宙斯为例）。选择阵容在官方开发者维基中有着这样的说明：如果你想控制英雄选择和分路，你可以在文件名为hero_selection.lua的文件中实现如下函数：Think() - 每帧被调用。负责机器人选择英雄。 UpdateLaneAssignments() - 在游戏开始前的每一帧被调用。返回玩家ID-分路的值对。 GetBotNames() - 调用一次，返回一个包含玩家名称的表。 在dota 2 beta\game\dota\scripts\vscripts\bots_exampleV社的示例文件中，我们可以找到hero_selection.lua文件，这就是为AI选择阵容的脚本文件。如果我们要开始制作自己的AI，那么首先需要创建dota 2 beta\game\dota\scripts\vscripts\bots文件夹，之后建立hero_selection.lua文件，在其中编写选择阵容的部分，这样的话AI就会选择自定义阵容了。打开这个文件，我们可以看到如下内容 function Think() if ( GetTeam() == TEAM_RADIANT ) --处于天辉方时 then print( "selecting radiant" ); --在控制台输出调试信息 SelectHero( 0, "npc_dota_hero_antimage" ); --为0号玩家选择敌法师 SelectHero( 1, "npc_dota_hero_axe" ); SelectHero( 2, "npc_dota_hero_bane" ); SelectHero( 3, "npc_dota_hero_bloodseeker" ); SelectHero( 4, "npc_dota_hero_crystal_maiden" ); elseif ( GetTeam() == TEAM_DIRE ) then print( "selecting dire" ); SelectHero( 5, "npc_dota_hero_drow_ranger" ); SelectHero( 6, "npc_dota_hero_earthshaker" ); SelectHero( 7, "npc_dota_hero_juggernaut" ); SelectHero( 8, "npc_dota_hero_mirana" ); SelectHero( 9, "npc_dota_hero_nevermore" ); end end其中Think()是主函数，游戏选择阵容时就会调用这个函数，然后判断是天辉方还是夜魇方，之后分别选择各自的阵容。那么我们如何找到英雄对应的名字呢？在这里便可找到英雄的实际名称。例如宙斯的实际名称是"npc_dota_hero_zuus"，那么我们将夜魇方的SelectHero( 5, "npc_dota_hero_drow_ranger" );替换为SelectHero( 5, "npc_dota_hero_zuus" );，那么AI便会选择在5号玩家的位置上选择宙斯。需要注意的是，玩家的ID是会随着人类玩家的加入而发生改变的，将玩家ID硬编码是一种不好的做法，比较好的方法是通过循环遍历出玩家的ID，这样无论人类玩家有多少，AI都能正常选择阵容。下面便是能够自动适应玩家变化选择阵容的代码。function Think() for i,id in pairs(GetTeamPlayers(GetTeam())) --Lua语言自带的迭代器pairs，能够依次读取表中的值。 do if(IsPlayerBot(id)) --判断该玩家是否为电脑 then SelectHero( id, "npc_dota_hero_drow_ranger" ); --为id号玩家选择黑暗游侠 end end end如果我们要AI能够选择随机的阵容，而不是仅仅选择10个黑暗游侠，那该怎么办呢？很简单，通过Lua语言唯一的数据结构表(称作Table，可以用作数组)保存可以选择的英雄列表，然后随机出一个序号，选出表中的英雄。hero_pool_my= { 'npc_dota_hero_zuus', 'npc_dota_hero_skywrath_mage', 'npc_dota_hero_ogre_magi', 'npc_dota_hero_chaos_knight', 'npc_dota_hero_viper', "npc_dota_hero_lina", "npc_dota_hero_kunkka", "npc_dota_hero_lich", "npc_dota_hero_shadow_shaman", "npc_dota_hero_centaur", 'npc_dota_hero_crystal_maiden', } function Think() for i,id in pairs(GetTeamPlayers(GetTeam())) do if(IsPlayerBot(id) and (GetSelectedHeroName(id)=="" or GetSelectedHeroName(id)==nil)) then local num=hero_pool_my[RandomInt(1, #hero_pool_my)] --取随机数 SelectHero( id, num ); --在保存英雄名称的表中，随机选择出AI的英雄 table.remove(hero_pool_my,num) --移除这个英雄 end end end以上代码会为两边的AI依次从hero_pool_my表中随机选出5个英雄。如果要让AI不选择重复的英雄，那么还需要进一步的修改。选择分路为AI分路的函数也是在hero_selection.lua中，如果我们想让AI遵循自定义的分路，那么需要在这个文件里新建一个UpdateLaneAssignments()函数。这个函数是用于游戏底层C++端调用，所以需要返回一个分路情况的表。function UpdateLaneAssignments() local npcBot = GetBot() local lanes= { [1]=LANE_MID, [2]=LANE_BOT, [3]=LANE_TOP, [4]=LANE_BOT, [5]=LANE_TOP, } return lanes; end以上函数根据AI的位置分路，1楼中路，2楼下路，3楼上路，4楼下路，5楼上路。当然，如果要根据英雄的特性分路，那么需要加入更多判断。如果没有自己写好分路系统的话，可以暂时启用默认分路系统，即不编写这个函数。技能加点在官方开发者维基中有着这样的说明：如果你只想重写在技能和物品使用时的决策，你可以在文件名为ability_item_usage_generic.lua的文件中实现如下函数:ItemUsageThink() - 每帧被调用。负责发出物品使用行为。 AbilityUsageThink() - 每帧被调用。负责发出技能使用行为。 CourierUsageThink() - 每帧被调用。负责发出信使的相关命令。 BuybackUsageThink() - 每帧被调用。负责发出买活指令。 AbilityLevelUpThink() - 每帧被调用。负责升级技英雄能。这些函数中未被重写的，会自动采用默认的C++实现。你也可以仅重写某个特定英雄对技能/物品使用的逻辑，比如火女(Lina),写在文件名为ability_item_usage_lina.lua的文件中。如果你想在特定英雄对技能/物品使用的逻辑重写时调用泛用的逻辑代码，请参考附件A的实现细节。我们要实现的第一个英雄为宙斯，那么就可以新建一个ability_item_usage_zuus.lua的文件。首先要实现AI的加点，就要在此文件中编写AbilityLevelUpThink()函数。然后通过 npcBot:ActionImmediate_LevelAbility(abilityname);升级名称为abilityname的技能。那么怎样获取升级技能所需的技能名称呢？比较原始的方法是用一个表记录从1到25级所有的技能名称。其中的数据要在dota 2 beta\game\dota\scripts\npc\npc_heroes.txt中获取。例如宙斯的技能为 --以下为宙斯的技能名称 "zuus_arc_lightning", "zuus_lightning_bolt", "zuus_static_field", "zuus_cloud", "zuus_thundergods_wrath", --以下为某个版本的天赋，请注意天赋名称会随着版本更新而变化，所以以下部分可能在当前版本中无效 "special_bonus_mp_regen_2", "special_bonus_movement_speed_25", "special_bonus_armor_7", "special_bonus_magic_resistance_15", "special_bonus_unique_zeus_2", "special_bonus_unique_zeus_3", "special_bonus_cast_range_200", "special_bonus_unique_zeus",如果通过原始方法记录，则需要排列组合以上的技能天赋。比较好的方法则是用两个表分别保存技能和天赋的名称，然后在一个统一的表中引用技能天赋名称，以存储加点顺序。local Talents = { "special_bonus_mp_regen_2", "special_bonus_movement_speed_25", "special_bonus_armor_7", "special_bonus_magic_resistance_15", "special_bonus_unique_zeus_2", "special_bonus_unique_zeus_3", "special_bonus_cast_range_200", "special_bonus_unique_zeus", } local Abilities = { "zuus_arc_lightning", "zuus_lightning_bolt", "zuus_static_field", "zuus_cloud", "zuus_thundergods_wrath", } --存储技能句柄，方便调用 local npcBot = GetBot() local AbilitiesReal = { npcBot:GetAbilityByName(Abilities[1]), npcBot:GetAbilityByName(Abilities[2]), npcBot:GetAbilityByName(Abilities[3]), npcBot:GetAbilityByName(Abilities[4]), npcBot:GetAbilityByName(Abilities[5]) } --存储加点顺序 local AbilityToLevelUp= { Abilities[1], Abilities[3], Abilities[2], Abilities[2], Abilities[2], Abilities[5], Abilities[2], Abilities[1], Abilities[1], Talents[1], Abilities[1], Abilities[5], Abilities[3], Abilities[3], Talents[3], Abilities[3], Abilities[5], Talents[5], Talents[7], }至此，英雄的技能天赋名称和加点顺序都已完成存储，接下来只需要在函数中引用加点顺序即可完成加点。function AbilityLevelUpThink() local npcBot = GetBot(); if npcBot:GetAbilityPoints()<1 or #AbilityToLevelUp==0--当没有技能点时，或没有技能可升时不继续执行。 then return; end local ability=npcBot:GetAbilityByName(AbilityToLevelUp[1]); --获取技能句柄 if ability~=nil and ability:CanAbilityBeUpgraded() --判断技能可否升级 then npcBot:ActionImmediate_LevelAbility(AbilityToLevelUp[1]); --升级技能 table.remove( AbilityToLevelUp, 1 ); --从表中移除刚刚升级的技能 end end我们之前说过，天赋名称会随着版本更新而不断变化，而且每次手动从npc_heroes.txt中获取技能天赋名称也有点麻烦，那么有什么更简便的方法呢？当然有，比如通过遍历英雄的技能槽来获取每一个技能和天赋的名称。local Talents ={} local Abilities ={} local npcBot = GetBot() for i=0,23,1 do --由于卡尔有24个技能，所以需要从0遍历至23 local ability=npcBot:GetAbilityInSlot(i) if(ability~=nil) then if(ability:IsTalent()==true) then table.insert(Talents,ability:GetName()) else table.insert(Abilities,ability:GetName()) end end end这样的话，我们每次新编写一个英雄，就不用手动去复制技能名称了。使用技能示例代码如果要重新编写一个英雄的技能使用，则需要编写AbilityUsageThink()函数。打开示例文件ability_item_usage_lina.lua，我们可以看到如下代码castLBDesire = 0; castLSADesire = 0; castDSDesire = 0; function AbilityUsageThink() local npcBot = GetBot(); -- Check if we're already using an ability 检查我们是否正在使用技能 if ( npcBot:IsUsingAbility() ) then return end; abilityLSA = npcBot:GetAbilityByName( "lina_light_strike_array" ); abilityDS = npcBot:GetAbilityByName( "lina_dragon_slave" ); abilityLB = npcBot:GetAbilityByName( "lina_laguna_blade" ); -- Consider using each ability 考虑使用每一个技能，得到使用技能的欲望值和技能目标 castLBDesire, castLBTarget = ConsiderLagunaBlade(); castLSADesire, castLSALocation = ConsiderLightStrikeArray(); castDSDesire, castDSLocation = ConsiderDragonSlave(); if ( castLBDesire > castLSADesire and castLBDesire > castDSDesire ) then npcBot:Action_UseAbilityOnEntity( abilityLB, castLBTarget ); return; end if ( castLSADesire > 0 ) then npcBot:Action_UseAbilityOnLocation( abilityLSA, castLSALocation ); return; end if ( castDSDesire > 0 ) then npcBot:Action_UseAbilityOnLocation( abilityDS, castDSLocation ); return; end end ---------------------------------------------------------------------------------------------------- --判断技能能否对目标使用 function CanCastLightStrikeArrayOnTarget( npcTarget ) return npcTarget:CanBeSeen() and not npcTarget:IsMagicImmune() and not npcTarget:IsInvulnerable(); end function CanCastDragonSlaveOnTarget( npcTarget ) return npcTarget:CanBeSeen() and not npcTarget:IsMagicImmune() and not npcTarget:IsInvulnerable(); end function CanCastLagunaBladeOnTarget( npcTarget ) return npcTarget:CanBeSeen() and npcTarget:IsHero() and ( GetBot():HasScepter() or not npcTarget:IsMagicImmune() ) and not npcTarget:IsInvulnerable(); end ---------------------------------------------------------------------------------------------------- --考虑是否使用2技能 function ConsiderLightStrikeArray() local npcBot = GetBot(); -- Make sure it's castable 确认技能能否使用 if ( not abilityLSA:IsFullyCastable() ) then return BOT_ACTION_DESIRE_NONE, 0; end; -- If we want to cast Laguna Blade at all, bail 如果要使用大招，那么先不用这个技能 if ( castLBDesire > 0 ) then return BOT_ACTION_DESIRE_NONE, 0; end -- Get some of its values 获取技能相关的参数 local nRadius = abilityLSA:GetSpecialValueInt( "light_strike_array_aoe" ); local nCastRange = abilityLSA:GetCastRange(); local nDamage = abilityLSA:GetAbilityDamage(); -------------------------------------- -- Global high-priorty usage -------------------------------------- -- Check for a channeling enemy 打断正在吟唱的敌人 local tableNearbyEnemyHeroes = npcBot:GetNearbyHeroes( nCastRange + nRadius + 200, true, BOT_MODE_NONE ); for _,npcEnemy in pairs( tableNearbyEnemyHeroes ) do if ( npcEnemy:IsChanneling() ) then return BOT_ACTION_DESIRE_HIGH, npcEnemy:GetLocation(); end end -------------------------------------- -- Mode based usage -------------------------------------- -- If we're farming and can kill 3+ creeps with LSA 收兵线打钱 if ( npcBot:GetActiveMode() == BOT_MODE_FARM ) then local locationAoE = npcBot:FindAoELocation( true, false, npcBot:GetLocation(), nCastRange, nRadius, 0, nDamage ); if ( locationAoE.count >= 3 ) then return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; end end -- If we're pushing or defending a lane and can hit 4+ creeps, go for it 推进与防守 if ( npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_TOP or npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_MID or npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_BOT or npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_TOP or npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_MID or npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_BOT ) then local locationAoE = npcBot:FindAoELocation( true, false, npcBot:GetLocation(), nCastRange, nRadius, 0, 0 ); if ( locationAoE.count >= 4 ) then return BOT_ACTION_DESIRE_LOW, locationAoE.targetloc; end end -- If we're seriously retreating, see if we can land a stun on someone who's damaged us recently 逃跑时阻止敌人追击 if ( npcBot:GetActiveMode() == BOT_MODE_RETREAT and npcBot:GetActiveModeDesire() >= BOT_MODE_DESIRE_HIGH ) then local tableNearbyEnemyHeroes = npcBot:GetNearbyHeroes( nCastRange + nRadius + 200, true, BOT_MODE_NONE ); for _,npcEnemy in pairs( tableNearbyEnemyHeroes ) do if ( npcBot:WasRecentlyDamagedByHero( npcEnemy, 2.0 ) ) then if ( CanCastLightStrikeArrayOnTarget( npcEnemy ) ) then return BOT_ACTION_DESIRE_MODERATE, npcEnemy:GetLocation(); end end end end -- If we're going after someone 对当前目标使用技能 if ( npcBot:GetActiveMode() == BOT_MODE_ROAM or npcBot:GetActiveMode() == BOT_MODE_TEAM_ROAM or npcBot:GetActiveMode() == BOT_MODE_GANK or npcBot:GetActiveMode() == BOT_MODE_DEFEND_ALLY ) then local npcTarget = npcBot:GetTarget(); if ( npcTarget ~= nil ) then if ( CanCastLightStrikeArrayOnTarget( npcTarget ) ) then return BOT_ACTION_DESIRE_HIGH, npcTarget:GetLocation(); end end end return BOT_ACTION_DESIRE_NONE, 0; --不使用技能 end function ConsiderDragonSlave() --略，考虑是否使用1技能 end function ConsiderLagunaBlade() --略，考虑是否使用4技能 end 以上便是原版AI的火女技能使用源代码，当然这是由C++代码翻译过来的。我们要编写的代码结构也可以参考这一部分，主要分为3个部分：主思考函数判断技能能否对目标使用考虑每一个技能调用关系为：主思考函数->考虑每一个技能->判断技能能否对目标使用实战在看完了示例代码后，我们应该对英雄的技能使用有了一个初步的了解，那么接下来便介绍一下如何从零开始开发一个新的英雄。（以宙斯为例）主思考函数首先先编写主思考函数，每一个英雄的主思考函数都是相似的，只需要处理每个技能不同类型的目标即可。在函数开头用local npcBot = GetBot()记录此英雄的句柄，方便后面的调用。之后需要判断英雄能否使用技能，是正在施法，还是被沉默了。 if ( npcBot:IsUsingAbility() or npcBot:IsChanneling() or npcBot:IsSilenced() ) then return end然后获取一些常用的量 AttackRange=npcBot:GetAttackRange() --获取攻击距离 ManaPercentage=npcBot:GetMana()/npcBot:GetMaxMana() --获取当前魔法百分比 HealthPercentage=npcBot:GetHealth()/npcBot:GetMaxHealth() --获取当前生命百分比然后考虑每一个技能的使用，Lua语言支持多重返回值，所以能够方便地从函数获取结果。 cast1Desire, cast1Target = Consider1(); --1技能为单位目标技能 cast2Desire, cast2Target, cast2TargetType = Consider2(); --2技能为单位目标技能或地点目标技能 cast5Desire = Consider5(); --大招为无目标技能 cast4Desire, cast4Location = Consider4(); --5技能（A杖技能）是地点目标技能最后使用每个技能，从上到下，为技能使用的优先级。当然我们也可以通过比较每个技能的使用欲望，选择欲望值最高的技能使用。 if ( cast4Desire > 0 ) then npcBot:Action_UseAbility( AbilitiesReal[4] ); --使用大招 return end if ( cast5Desire > 0 ) then npcBot:Action_UseAbilityOnLocation( AbilitiesReal[5], cast5Location ); --对目标点使用5技能 return end if ( cast2Desire > 0 ) then if(cast2TargetType=="target") then npcBot:Action_UseAbilityOnEntity( AbilitiesReal[2], cast2Target ); --对单位使用2技能 return elseif(cast2TargetType=="location") then npcBot:Action_UseAbilityOnLocation( AbilitiesReal[2], cast2Target ); --对目标点使用2技能 return end end if ( cast1Desire > 0 ) then npcBot:Action_UseAbilityOnEntity(AbilitiesReal[1], cast1Target ); --对目标单位使用1技能 return end至此，主思考函数编写完毕。考虑使用每一个技能在开始开发一个技能的使用前，我们应该先想想，这个技能有什么用？是一个单体爆发技能，还是一个范围技能？这个技能有没有控制效果？这样的话才好编写接下来的技能。比如说宙斯的1技能，可以用来补兵，清兵，对英雄造成范围伤害等等。首先我们也需要获取英雄和技能的句柄。在函数开头用local npcBot = GetBot()记录此英雄的句柄，用local ability=AbilitiesReal[1];记录此技能的句柄。然后需要判断这个技能能否使用，即魔法够不够，冷却有没有好。 if not ability:IsFullyCastable() then return BOT_ACTION_DESIRE_NONE, 0; end之后也是记录一些常用的量，以免重复获取降低效率。 local CastRange = ability:GetCastRange(); --获取施法距离 local Damage = ability:GetAbilityDamage(); --获取技能伤害，注意这个函数不一定有效...有些特殊的技能无法获取 local HeroHealth=10000 local CreepHealth=10000 local allys = npcBot:GetNearbyHeroes( 1200, false, BOT_MODE_NONE ); --获取周围友方英雄 local enemys = npcBot:GetNearbyHeroes(CastRange+300,true,BOT_MODE_NONE) --获取周围敌方英雄 local WeakestEnemy,HeroHealth=utility.GetWeakestUnit(enemys) --获取血量最低的敌方英雄 local creeps = npcBot:GetNearbyCreeps(CastRange+300,true) --获取周围的敌方小兵 local WeakestCreep,CreepHealth=utility.GetWeakestUnit(creeps) --获取血量最低的敌方小兵注意，在这个地方我调用了utility函数库中的函数，调用函数库模块，需要在脚本开头加入require(GetScriptDirectory() .. "/utility")。当然这个utility名字是可以变化的。该函数的实际代码放在文末。1.之后，便是宙斯1技能的实际用途，我分为了5个部分：团战使用线上正补发育打钱推进防守通用function Consider1()(1) 团战使用当英雄模式处于攻击时，判断蓝量是否足够，敌方单位数量是否足够，然后找到最脆弱的敌方单位或者英雄，判断它们能不能被技能作用，最后将这个单位的句柄返回给上层主思考函数。--teamfightUsing if(npcBot:GetActiveMode() == BOT_MODE_ATTACK ) then if(ManaPercentage>0.4 and #enemys+#creeps>2) --蓝量大于40%，敌方单位数>2 then if(WeakestCreep~=nil and CanCast1( WeakestCreep )) --CanCast1是一个自定义函数，用于判断技能能不能对目标使用，请参考下一部分。 then return BOT_ACTION_DESIRE_HIGH,WeakestCreep; end if(WeakestEnemy~=nil and CanCast1( WeakestEnemy )) then return BOT_ACTION_DESIRE_HIGH,WeakestEnemy; end end end(2) 线上正补 --Last hit if ( npcBot:GetActiveMode() == BOT_MODE_LANING ) then if(WeakestCreep~=nil) then if(ManaPercentage>0.4 and GetUnitToUnitDistance(npcBot,WeakestCreep)>=AttackRange-ManaPercentage) --蓝量大于40%，而且该单位远离英雄的攻击距离 then if(CreepHealth<=WeakestCreep:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL)) --伤害是否足够 then return BOT_ACTION_DESIRE_LOW,WeakestCreep; end end end end(3) 发育打钱-- If we're farming and can hit 2+ creeps and kill 1+ if ( npcBot:GetActiveMode() == BOT_MODE_FARM ) then if ( #creeps >= 2 )--单位是不是足够多 then if (CreepHealth<=WeakestCreep:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL))--伤害是否足够 then return BOT_ACTION_DESIRE_LOW, WeakestCreep; end end end(4) 推进防守 -- If we're pushing or defending a lane and can hit 3+ creeps, go for it if ( npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_TOP or npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_MID or npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_BOT or npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_TOP or npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_MID or npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_BOT ) then if ( #enemys+#creeps > 2 and ManaPercentage>0.4)--蓝量大于40%，敌方单位数>2 then if (WeakestEnemy~=nil) then if ( CanCast1( WeakestEnemy )and GetUnitToUnitDistance(npcBot,WeakestEnemy)< CastRange + 75*#allys ) --判断目标，判断英雄的位置是否安全 then return BOT_ACTION_DESIRE_LOW, WeakestEnemy; end end if (WeakestCreep~=nil) then if ( CanCast1( WeakestCreep )and GetUnitToUnitDistance(npcBot,WeakestCreep)< CastRange + 75*#allys ) then return BOT_ACTION_DESIRE_LOW, WeakestCreep; end end end end(5) 通用对模式决定的当前目标使用技能-- If we're going after someone if ( npcBot:GetActiveMode() == BOT_MODE_ROAM or npcBot:GetActiveMode() == BOT_MODE_TEAM_ROAM or npcBot:GetActiveMode() == BOT_MODE_DEFEND_ALLY or npcBot:GetActiveMode() == BOT_MODE_ATTACK ) then local npcTarget = npcBot:GetTarget(); if(ManaPercentage>0.4) then if ( npcTarget ~= nil ) then if ( CanCast1( npcTarget ) and GetUnitToUnitDistance(npcBot,npcTarget)< CastRange + 75*#allys) --距离是不是足够近 then return BOT_ACTION_DESIRE_MODERATE, npcTarget; end end end end(6)如果上面的部分没有获取到合适的目标，返回欲望0，和空单位，以防出现错误。 return BOT_ACTION_DESIRE_NONE, 0;2.宙斯2技能与之前类似的部分便不再详细指出。(1)打断目标本技能有打断功能，应打断敌方英雄的吟唱。 -- Check for a channeling enemy for _,enemy in pairs( enemys ) do if ( enemy:IsChanneling() and CanCast2( enemy )) then return BOT_ACTION_DESIRE_HIGH, enemy,"target"; --由于本技能有多种目标类型，可以返回类型是什么。 end end(2)击杀附近可以击杀的敌人 -- Kill enemy if(npcBot:GetActiveMode() ~= BOT_MODE_RETREAT ) then if (WeakestEnemy~=nil) then if(HeroHealth<=WeakestEnemy:GetActualIncomingDamage(Damage,DAMAGE_TYPE_MAGICAL)) --伤害是否足够 then if ( CanCast2( WeakestEnemy ) ) then return BOT_ACTION_DESIRE_HIGH,WeakestEnemy,"target"; end end end end(3)保护自己，消耗靠近英雄的敌人 --protect myself local enemys2 = npcBot:GetNearbyHeroes( 500, true, BOT_MODE_NONE ); --获取500范围内的敌人 if(npcBot:WasRecentlyDamagedByAnyHero(5)) --最近是否被敌人伤害 then for _,enemy in pairs( enemys2 ) do if ( CanCast2( enemy ) ) then return BOT_ACTION_DESIRE_HIGH, enemy,"target" end end end(4)消耗敌方英雄 if(npcBot:GetActiveMode() ~= BOT_MODE_RETREAT ) if(ManaPercentage>0.4 and ability:GetLevel()>=2 ) --蓝量大于40%，技能大于或等于2级 then if (WeakestEnemy~=nil and CanCast2( WeakestEnemy )) then return BOT_ACTION_DESIRE_LOW,WeakestEnemy,"target"; end end end3.宙斯大招检测所有敌方英雄的血量，如果能够击杀，且附近没有友方英雄，那么则使用技能。详细代码略。4.宙斯雷云放在防御塔附近，或敌方英雄附近。 local tower=nil if ( npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_TOP or npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_MID or npcBot:GetActiveMode() == BOT_MODE_PUSH_TOWER_BOT ) then local tower=npcBot:GetNearbyTowers(1500,false) end if (npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_TOP or npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_MID or npcBot:GetActiveMode() == BOT_MODE_DEFEND_TOWER_BOT ) then local tower=npcBot:GetNearbyTowers(1000,true) end if(tower~=nil and GetUnitToUnitDistance(npcBot,tower[1])<CastRange+500) then return BOT_ACTION_DESIRE_LOW,tower[1]:GetLocation() end if (WeakestEnemy~=nil) then return BOT_ACTION_DESIRE_LOW,WeakestEnemy:GetLocation() end 判断技能能否对目标使用其实这部分很简单，就是判断目标是否魔法免疫，是否无敌之类的，以防止英雄重复尝试对无效目标使用技能。function CanCast1( npcTarget ) return npcTarget:CanBeSeen() and not npcTarget:IsMagicImmune() and not npcTarget:IsInvulnerable(); end function CanCast2( npcTarget ) return not npcTarget:IsMagicImmune() and not npcTarget:IsInvulnerable(); end function CanCast5( npcTarget ) return npcTarget:IsHero() and not npcTarget:IsMagicImmune() and not npcTarget:IsInvulnerable(); end至此，我们已经完成了一个英雄的技能使用设计，详细代码请参考附件。参考通用函数utility.GetWeakestUnit(EnemyUnits)函数function GetWeakestUnit(EnemyUnits) if EnemyUnits==nil or #EnemyUnits==0 then return nil,10000; end local WeakestUnit=nil; local LowestHealth=10000; for _,unit in pairs(EnemyUnits) do if unit~=nil and unit:IsAlive() then if unit:GetHealth()<LowestHealth then LowestHealth=unit:GetHealth(); WeakestUnit=unit; end end end return WeakestUnit,LowestHealth end总结总算写完了，真的是很久没有写这么长一篇文章了，希望大家能有所启发。在下一篇文章中，我会为大家介绍如何配置AI出装。附件所有代码已测试运行通过1.示例代码
经过一段时间的测试，本站已经成功启用了 https。现在，本站与用户之间的通信已经加密，能有效保护用户与网站间的通信安全。虽然很早前就知道了 https 是怎么一回事，但之前怕麻烦就没有部署，但是根据这次的经验，启用 https 也不是很难。下面我就介绍一下本站启用 https 协议的经验。申请 SSL 证书要启用 https 协议，首先需要申请一个由数字证书授权机构颁发的 SSL 证书。由于本站部署于腾讯云上，便在这里找到了免费的 SSL 证书申请。申请过程也很简单，填写信息后很快就收到了由 Trust Asia 颁发的免费域名 SSL 证书。部署 SSL 证书在申请证书通过后，下载证书到服务器上，之后按照腾讯云的教程便轻松安装。由于用户一般是不会主动在链接上加上 https 的，所以需要将 http 请求重定向至 https。由于本站使用的服务器是 IIS，便按照教程用 URL 重写模块完成了请求重定向。细节处理在启用 https 后，网站内部的链接还是使用的 http 协议，所以需要调整。首先现在 typecho 后台设置的站点地址中，将 http 开头的网址改为 https。之后在 typecho 根目录下的配置文件 config.inc.php 中，添加一行define('__TYPECHO_SECURE__',true);。保存后重启 iis 服务器便可完成启用。再重新进入网站主界面时，浏览器提示访问的页面有一部分是不安全的，这是因为网页上混合了 https 和 http 的元素。我开始也不清楚是哪个地方引用了 http 元素，经过检查发现 cnzz 的统计代码是引用了 http 来源的 JS 脚本，将链接改为 https 后便解决了。总之，启用 https 不仅能提高站点的安全性，更能让站点看起来高大上一些。
人工智能首部诗集之小冰：是你的声音啊
微明的灯影里我知道她的可爱的土壤是我的心灵成为俘虏了我不在我的世界里街上没有一只灯儿舞了是最可爱的你睁开眼睛做起的梦是你的声音啊当然，这首诗不是我写的，而是人工智能创作的。原来从没想到人工智能能做出艺术性的创作，没想到今天也成为了现实。但是小冰所写的诗歌，还是有些稚 嫩，似乎并没有其个人的思想，只是映射出了中国现代诗的集体意识。为了测试小冰的创作水平，微软让小冰化名在报刊、豆瓣、贴吧和天涯等多个网络社区诗歌讨 论区中发布作品。其中用过的笔名有 23 个，我闲来无事，在豆瓣和简书上找到了小冰笔名为 “风的指尖 2017” 的主页。简书 豆瓣曾有人担心，当人工智能取代人类大部分的工作后，我们将何去何从？殊不知，一个行业的衰落总伴随着另一个行业的兴起，当机器人承担了那些枯燥重复的 工作时，就会有很大数量的人们从流水线上解放，那样我们便可以将更多的精力投入到创造性的工作上去。高晓松曾在微博发言忧虑，人工智能都能做出艺术创作 了，那我们人类又和机器有何区别？哈哈，当然有，因为是人创造出了人工智能。人工智能与人之间也许并不是竞争的关系，而是传承与创新。阳光失了玻璃窗微软小冰推出首部诗集：《阳光失了玻璃窗》
前言众所周知，v 社在 7.00 版本推出了自定义机器人功能，我也做了一个 ai 放到了创意工坊上。应广大玩家要求，也为了与大家交流 dota2 ai 的开发技术，我打算写一点浅显易懂的开发教程，希望无论是开发者还是普通玩家都能够理解。dota2 在刚推出时，新闻上就列举了很多 ai 的特性，那时候 ai 可以说是很强。但是由于 v 社天天度假，忽视了 ai 的开发，现在的 ai 还停留在远古版本。所以，为了更好度假！不不不，是为了提升 ai 的水平，便把 ai 开放给玩家制作。IceFrog：Dota2 新增血魔和船长，全新 AI 加入DOTA2 为适应各水平玩家 大幅优化 AI 智能浅谈 DOTA2 AI 打匹配的五大优点和三大缺点Dota2 ai 简介说了这么多，还是回归正题吧，Dota2 的 ai 到底是怎样制作的呢？dota2ai 是用 Lua 脚本语言实现的。Lua 是一种解释型编程语言，如果以前学过编程语言那就很好掌握，没学过也没关系，因为 Lua 语言的语法很简洁，即使是小白也能很快理解。当然，本文不会介绍 Lua 语言的基本语法，如果想进一步学习，可以参考 Lua 教程或者是《Lua 程序设计第二版》。那么，我们应该在什么环境下编写 Lua 脚本呢？很简单，我们没有什么 IDE（集成开发环境）。任何文本编辑器都可以拿来编写，就连记事本也可以！不过还是不推荐使用记事本，因为没有基本的语法高亮等功能，我使用的是 notepad++，一个很简洁的文本编辑器，当然如果你有更好的编辑器也可以直接使用。所有正在开发的 ai 脚本都存放于dota 2 beta\game\dota\scripts\vscripts\bots文件夹下，如果没有 bots 目录便需要自己创建一个。而当你上传你的脚本到工坊时，就会上传该目录下的内容。而下载的脚本则放在你 Steam 安装目录下自己的文件夹中。不出意外的话，你会找到bots_example文件夹，里面有 V 社原版 ai 的一部分。当然，原版 AI 并不是由 lua 编写的，而是由 C++ 编写，而完整的 AI 源码并没有公布。这一部分示例，是由 C++ 翻译为 Lua 的。目前，开发 ai 大致有两种路线，第一种是完全控制，这意味着你需要编写从游戏开始到游戏结束的所有 ai 代码。而第二种则是部分控制，这只需要你接手你想控制的部分，比如某个英雄的技能操作，游走的思路等。前一种工作量很大，需要完全重构 AI 系统。而后一种则比较简单的方法，本系列文章主要是讲解后一种。有的玩家经常反馈：为什么 ai 总是喜欢抱团一起推，一个个送。这也很好解释，因为目前创意工坊里的 ai 大部分都是属于后一种，继承了大部分默认 ai 的思路。至于如何开启一局社区原创机器人游戏，想必大家都已身经百战，不用我说了。不过我还是介绍一下。打开 dota2， 创建房间，选择本地主机，选择 “编辑”，在高级房间设置中，勾选 “机器人填满空位”，随后订阅并使用创意工坊的脚本。如果选择本地开发脚本，那么使用的便是我们在 bots 文件夹下编写的脚本。在接下来的文章中，我会为大家介绍如何开发编辑英雄出装加点，英雄的技能操作，喝神泉模式的实现等等。参考文档：Dota2 AI 开发 tutorial（一）AI 的 环境配置DOTA 机器人脚本 Wiki（英文版更全）Dota2 AI api 说明
近日，国外著名新闻论坛 reddit 的水友们发起了 dota2 BOT Major，也就是一场只有机器人参加的联赛，参赛队伍都来自创意工坊中玩家制作的机器人脚本。这次比赛可以让我们见证有史以来的第一次机器人联赛，也许 在不久的将来，机器人战队也能与人类职业战队一战。Dota 2 Bot Major 赛事总结祝贺 Extrem Push 一波推进流 获得冠军亚军：Ranked Matchmaking AI by:adamqqq 天梯匹配模拟器季军：Alchemist and His Four Friends 炼金术士和他的 4 个小伙伴如果你不熟悉本次联赛，你可以在这里找到更多的信息决赛视频：GAME 1 ,GAME 2 ,GAME 3对不起，游戏中的镜头和界面有些问题，请不要责备我和解说们，我想这是 V 社的问题。在我看来，这是一个很好的比赛。小组赛打得并不是很好，只有一个小组的比赛势均力敌，该组剩下的两支队伍比其他队伍都要强。机器人最大的问题就是推 进的力度不够，而且他们所掌握的英雄数太少。就像你看到的那样，位列前 3 的机器人战队中有的只能使用 6 个不同的英雄。这些机器人有一个很好的或至少体面的团队阵容，并且可以不断赢得游戏，而那些会使用很多英雄的队伍，他们的发挥很大地取决于他们所挑选的英 雄。据了解，开发者已经能够使机器人支持队长模式，但实际上很少有机器人战队支持队长模式，所以我们不得不使用全阵营选择。我真的希望下次更多的机器人 （或全部）将支持队长模式，那时我们就可以举办一个更平常的比赛。机器人还有很多发挥的余地，也许这是 V 社 api 的问题，我希望这些问题将很快修复，届时我们可以看到一些更好的机器人。我不认为这些机器人不好，前 7 名或者这附近的机器人都十分不错，比默认的机器人要好得多！感谢所有的开发者所做出的工作，他们已经击败了 V 社的 AI 了，加油！我不希望这篇文章太长，所以我会在这里宣布未来的计划。我打算继续举办这一系列比赛，直到 V 社或者更大地组织举报机器人联赛。下一场比赛将有 16 支战队，这将使小组赛更看重实力，而不仅仅因为 BO1 的失败而结束联赛。这次比赛的前 8 名队伍将直接被邀请参与下一届联赛，而第 9-12 名将以双重淘汰赛相互争夺 2 个出线资格，最后的 2支战队将在预选赛中与其余的机器人队伍进行联赛，我还没有决定赛程。新的种子战队可以在这里看到。请输入图片描述我希望 V 社能尽快支持在服务器上运行机器人游戏，或允许观众在本地服务器上使用 DotaTV 来观战，而不是像这次只能很麻烦地使用录像来观看比赛。谢谢你们，我们国际邀请赛之前再见！这次我会尝试回答每个比赛或机器人相关的问题！祝大家生活愉快！以上内容转自 https://redd.it/676zz6半决赛：总决赛：GAME 1 ,GAME 2 ,GAME 3很高兴自己的 ai 能拿下第二名，如果你对我的 ai 有任何建议，请移步贴吧或创意工坊
一个人的政治倾向总是多变的，更何况 是成长中的青少年。我还记得初中时，老师要我们把自己的理想写在纸条上并贴在后面的黑板上，那时的我心中只有着朴素而纯粹的理想，于是我高兴地写下了 “为社会主义建设做出一份微薄的贡献”。直到后来我从同学那了解到了一些历史事实，便走向了追逐民主自由的道路。高中时的地理老师也是一位对政治有独特见 解的人，经常在上课时给我们讲述国外的政治发展史。但直到读大学后，我才真正地领略到马克思主义的魅力。其实，早在高中时，我就曾尝试阅读马克思的著作《资本论》，但是学识有限，没有读完，也未曾真正地读懂。直到这个学期我才读完了《资本论》的简编插 图本，虽然只写出了其中的精华，但也让我略微理解了马克思主义经济观。至于《共产党宣言》，在以前我以为只是很短的一段话，也只对 “全世界无产者，联合起来” 有所耳闻，这几天阅读了全文，没想到居然有几万字，慢慢品味后感受颇深，便把自己的感想写下。高中政治课本上描述的资本主义腐朽生活在当代却成为了很多人所向往的生活，资本主义文化大幅入侵，社会上弥漫着一股金钱至上娱乐至死的气息，人们也从仇富走向了嫌贫。所幸的是马克思和恩格斯早已指出了资本主义的脆弱之处。为什么《共产党宣言》如此经典？正是因为其中对资本主义的预言直至今日仍有应验。“有哪一个反对党不被它的当政的敌人骂为共产党呢？又有哪一个反对 党不拿共产主义这个罪名去回敬更进步的反对党人和自己的反动敌人呢？” 美国总统罗斯福在改革时就被保守党批评：“这是社会主义，它是否是共产主义尚待观察”。在社会保障法的听证会上，也有人高喊 “这个方案是从《共产党宣言》第 18 页逐字逐句抄来的”。而罗斯福的反击也是和他们出奇地一致：“你们正在建立共产主义”、“你们骑的是一匹垂死的马”。其实罗斯福是为了防止资本主义在未来 被取代，而主动改革为资本主义延续生命。有人说马克思主义不合实际，现代无产阶级的生活水平已经大幅提高，不需要反对资本主义制度。然而，资本主义在法律名义上的平等下却隐藏着更多的不平 等。资本家正是理解了马克思主义，意识到如果继续加大剥削力度就是自寻死路，给予无产阶级一些基本的福利，其实只是资本家放弃短期利益而获取更长远利益的 手段，即无产阶级永远为资本主义工作。但是我们要知道，正是无产阶级先烈用一次又一次暴力的革命，付出生命的代价来逼迫资本家，获得了八小时工作制，工资 提高等优越的条件。共产党人从不屑于隐瞒自己的观点和意图，而忘记历史就意味着背叛，就会陷入修正主义的圈套，有人甚至背叛了自己的阶级，为资产阶级说 话，学习资产阶级价值观，终生奋斗在资产阶级的理想当中！钱理群教授所说的大学中的 “精致的利己主义者” 便是其中一员。当一个人没有了超越自我的远大理想，所剩下的便只有资本主义价值观了。马克思曾以 “我不是马克思主义者” 来讽刺社会上对他理论的扭曲和异化。有部分政治投机分子，完全不理解马克思主义，抛弃本来就没有的共产主义信仰，只为获取现世的功名利禄。资本主义把所有的一切都变为可以交换的商品，商品拜物教在社会中大肆传播，一个人的幸福被定义为其所拥有的财富与商品，这难道不是一个时代的最大悲 哀吗？“我们的资产者不以他们的无产者的妻子和女儿受他们支配为满足，正式的卖淫更不必说了，他们还以互相诱奸妻子为最大的享乐”。连妻子，儿女都变成了 生产工具的资产阶级，居然敢嘲讽共产共妻，而在共产主义下女性能反而能解放自我，而不是成为附庸在资产阶级下的生产工具。一个真正的马克思主义者，始终坚持唯物史观的分析方法，即经济基础决定上层建筑。要发展到一个更美好的世界，不能通过无谓的道德说教，而必须解放并 发展生产力。有人说穷人穷是因为他们不努力，但是他们压根就没有努力上升的环境。资本主义来到世间, 从头到脚, 每个毛孔都滴着血和肮脏的东西，而劳动者来到世界上就已经一无所有了。在资本主义制度下，必然会造成相对人口过剩和相对生产力过剩，并不是因为消费者没有 需求，而是消费者根本没有能力购买这些商品。一个人究竟能不能够实现自我？我并不知道答案，但我知道在共产主义社会中，每个人都能平等自由地发展。最后用马克思的墓志铭做结尾吧 “哲学家只是用不同的方式解释世界，而问题在于改变世界。全世界劳动者联合起来！”这篇文章本来是马克思主义原理的作业，顺便发上来给大家看看。
一个人的命运啊，当然要靠自我奋斗，但是也要考虑历史的行程。开学的这一个月可以说是我个人历史中一个微小的转折点，那就是我从环境科学专业转到了计算机科学与技术专业。我不知道究竟是什么驱使着我转了专业，那么还是说一说我和计算机的渊源吧。在我出生时，家里就已经有了电脑，据说要接近一万元才能买下，这在 20 世纪末可以说是一个比较大的数字了。据父母说，在我记事前，我就已经学会了电脑的正常开关机，还能够 “教” 舅妈玩电脑。在小学时，我记得家里的系统还是 windows98，奔腾 4 的 cpu 加上 500MB 的内存，构成了当时最强的家用计算机，记得当时玩过一个很好玩的驾驶飞机游戏，可惜不记得叫什么名字了。当时每天放学后，我的同学们总是跑到我家里来，玩 一玩电脑上的游戏。最初在低年级时玩的是飞机大战，一个和雷电很像的小游戏，每天都玩得不亦乐乎，之后玩过的游戏有大航海时代 4，帝国 2，文明 3，国家之崛起，英雄无敌 3 等等。大家都知道文明是一个耗时很久的游戏，每天回家读档都只能玩一点点，好不容易玩到了后期，结果那天突然断电了，档没存都是小事，结果来电后发现存档 损坏了，我和小伙伴们真是沮丧啊，花费这么久时间玩出来的成果突然间就消失了。初中高中时，我的历史地理都很好，可以说和这些游戏还有我家里墙上的两幅地 图有些联系，父母的同事经常向我家请教我地理好的秘籍，那自然是天天看见的世界地图和中国地图了，没有它们我怎么能上知天文，下晓地理。好像是三年级时，家里接入了互联网，那时好像还是通过电话拨号上网，网速很慢很慢，带宽大概只有现在的 1/100 吧。我也忘了我是通过什么途径了解到 qq 的，那时候申请了很多个 qq，每申请一次，过几天就被盗了，可能是密码太简单了，后来我换了一个强一点的密码，申请到的 qq 就一直用到现在了。至于我的昵称就是由英语老师给我取的英文名和中文名缩写得到的，大概也没有几个重名的吧。刚接触到网络的我没过多久就帮几个同学申请了 qq 号，尽管大家也不知道这有什么用，但始终觉得这是个很好玩的东西。第一个接触的网络游戏似乎是跑跑卡丁车然后是泡泡堂、地下城与勇士和反恐精英 ol。电脑玩多了还是不太好，主要是对视力影响很大，四年级时在苏州玩了快一个暑假的跑跑卡丁车，我的眼睛就有点近视了，这就把我带上了眼镜这条不归路。关于编程方面，我小学时就自己学会了 windows 批处理和 vbscript 的一点皮毛。当时还做了一个微型 “病毒”，功能就是开机自启动并弹框 “我是猪”，下面只有确定，而且按了也关不掉，同时任务管理器也被禁止启动。这个微型病毒被我绑定到一个小游戏里发给了一个同学，结果第二天他就传来噩耗 “我家电脑中毒了!”，苦苦哀求了我一会，我才给他把病毒清除了。遗憾的是，没过多久 360 就有了主动防御功能，像修改注册表来自启动的敏感操作，很容易就被 360 拦截掉了。初中时，我学会了极其简单的易语言，并用其写了一个小游戏弹弹堂的辅助工具，看上去很像外挂，其实也没什么太大的用处。再之后，就是陷入了魔兽 争霸地图编辑器 WE 的坑了，做了一个地图 dotc 的人工智能系统，这也是我与人工智能结缘的开始。大一时，我在群里看到了程协的招新通知，果断就加入了，之后便是我学习编程语言的又一个起点。幸运的是，在校大学生程序设计大赛中，我取得了二等 奖，这也帮助我进一步了解了计算机这个专业。后来在学计算机网络这门课时，我便回忆起了小学时看的一本书，大致内容就是如何搭建一个网吧的网络。以前从没 想到学校的专业课程是如此的简单，这大概都是以前看的书和杂志的功劳。还记得初中英语老师在课堂上问及大家的梦想，我站起来就说到 “Computer scientist”，╮(￣▽￣)╭哈哈，也不知道当时是怎么想的。尽管时间无情，消磨了人们的初心，但我还是要祝愿，愿我们的理想在未来都能如夏花般璀璨。
前几天聆听了何善蒙教授的讲座，感受颇深，特此记下。人们常说中国历史上一共有两个半圣人，孔子，王阳明，而曾国藩算半个。“立德立功立言真三不朽，明理明知明教乃万人师。” 是后人对王阳明一生的总结。人们往往只记住了他的心学，却忘记了他自身的成就，其实他的一生也是具有传奇色彩的。王阳明幼时在京师读书时，曾问老师：“什 么事情是最重要的”，老师回答他说要考取功名做官，而他却回答老师，最重要的应该是读书做圣人。这真是何等崇高的理想愿望啊，幸运的是他用一生最后完成了 这一壮举，并提出了心学的理论。其心学理论对日本明治维新和中国近代都产生了显著的影响。心是天地万物的所在，心外无理、心外无物，是心学的基本观点。意思就是如果要认识事物的真相，那么只需要探求自己的内心就可以了。“你未看此花时, 此花与汝心同归于寂。你来看此花时, 则此花颜色一时明白起来。便知此花不在你的心外。” 常常被作为王阳明心学是主观唯心主义的证据，但其实他并没有说没看这朵花时，花就消失了，而是这朵花在你没看时便失去了意义。也就是说心学并没有否定事物 的客观存在，而是强调外物与内心的联系和意义。其实，我曾经对死亡感到恐惧，人类难道只是基因和模因的载体吗？中国传统中最注重的就是事物与内心的关联，如果一个事物没有意义，那么这就不应该存 在，一个事物是否存在并不重要。人在宇宙中是微不足道的，人总有一天会死去，是不是这一切都没有意义呢？人生本来就没有什么意义，人生的意义在于你赋予他 什么意义。我们幼时，常常与 “别人家的孩子” 作比较，总是将他人作为自己的榜样，模仿着他人的生活轨迹，努力成为别人，却忘记了思考自己想成为一个什么样的人。不然殷浩也不会说出 “我与我周旋久，宁作我。” 这句话。那么在当今的社会中应该如何保持自我? 何教授认为，人所做的事情可以分为两种，一种是自己想要做的，另一种是不得不做的，只有当前一种占到生活的多数时，自己才会感到快乐。怎样判断自己的内心是否安宁？这没有一个固定的标准，取决于每个人的自我判断。心安理得，以前一直用着这个成语却不知其准确的含义。然而王阳明认为，唯有心安才能理得，如果自己的内心都不相信自己是否合理，那么自己肯定会感到 焦虑。良知，在心学中也就意味着终极真理，致良知则是把良知运用到生活中的各种事物当中去，也就一位置知行合一。而知行合一指的是认识事物的道理和实践是 密不可分的，也就是言行一致，但在这里知并不是指普通知识，而是道德意识。比如说看到老人跌倒应不应该扶起来，人的直觉当然是扶起来，则也就是人们的良 知。如果经过思考，想到自己扶起来的利弊，那么这就背离了良知了。王阳明先生临终前，弟子问他还有什么想说的，他便留下了 “此心光明，亦复何言” 这短短几个字。这样的境界恐怕没有几个人再能够达到了。王阳明的致良知和迈克尔桑德尔的培养德行和推理共同善有异曲同工之妙，看来人类的崇高价值总是相似的——为了整个世界的幸福而努力奋斗。
数独其实是个很有趣的游戏，我小学时就在电脑上就玩了很久的数独，不仅可以锻炼思维，而且乐趣无穷。当我在食堂旁的宣传点上发现数独大赛时，内心是十分激动的，原以为数独只是一个小众游戏，没想到在学校里还能有一群志同道合的同学来一试高下。原本想着在 电脑上下个数独游戏练练手，最后还是没有下。只是在参加之前，在网上查了一些数独的技巧，也许能够用上。当时，拿着纸和笔就跑到了七教，一看两个教室都坐 满了同学，心想这可是高手如云啊。本来想着凭借我以前的经验，应该能做出很多题，结果数独题目发下来后，可真是相当的难啊。没办法，只好硬着头皮解了。第一个题就出师不利，解到一半就出现矛盾了，十分尴尬，擦干净后重做还是如此，只能跳过一题。还好，第二题和第三题不久就解出来了, 心中那个喜悦啊... 可惜时间不多了。第四个题做着做着在最后又出错了，只好放弃。交卷时看旁边的同学，水平也都差不多。回去就在群里交流了下，等结果出来。到了第二天，我 去，第一名居然解出了九道题... 最后一名入选决赛的同学也解出了六道。看来高手都是很低调的，交流时一个都不冒泡。虽然没能拿到名次，但是意外知道了社团文化艺术节这个活动，没想到我们学校这么多社团居然能举办这么多有趣的活动，以后要多关注关注，而且自己也玩得很高兴。果然这就是丰富多彩的大学文化生活啊。
Even the effort that some people expend, 即使是一些人所付出的努力conscientious striving,the work ethic, 奋斗精神，职业道德even effort depends a lot on fortunate family circumstances.即使是努力本身， 很大程度上也依赖于幸运的家庭环境For which you,we,can claim no credit.无论是你，还是我们，都不敢妄自邀功。——迈克尔 · 桑德尔 哈佛大学公开课：公正 - 该如何做是好？究竟是爱笑的女孩运气不差，还是幸运的女孩更容易笑？曾经以为，努力就能得到一切。在我读中学的时候，发现有一些同学无论如何努力学习，也不能提高太多成绩。同样的作业题，有的同学一点就通，而他们却百思不得其解。他们是不是真的比别人傻呢？也许是，也许又不是。一个人的发展不可能脱离他所处的环境。也许有的孩子从小就衣食无忧，家庭和睦，无需为明天的生活考虑，课外书与培训也是应有尽有。他们身处省级重点高中，享受着最优质的教育，谈笑着自己高中没怎么学习就能考上重点大学的故事；而他们却饥寒交迫，留守在家，为了生存几乎牺牲了一切，唯一的知识来源只是教材。他们不断学习，却也不能够继续接受高等教育，甚至不能完成义务教育，被迫提早走入社会。如此幸运的孩子又怎敢嘲笑他们暂时的不解呢。精英统治制度所提倡的公正 “对个人的奖励取决于他自身的努力”，但是努力并不意味着贡献，更何况努力受到各种随机因素的影响, 其中也包括机会。某位高官的女儿这样说过：“我的成长是自己一步一步努力的成果。从大学毕业到去基层工作，从最初的技术员、工程师、科长、副处长、处长、副总裁、到总裁，我一个台阶也没有漏。一个人出生在比较好的家庭，如果没有自己的努力，只靠父辈的影响，即使给了你这个位置，你也是扶不起的阿斗！” 不知道是有意还是无意，她竭力强调着自身的不懈努力，却忽视掉了自己强大的家庭背景。记得有一位中国人民大学的同学想在母校创立一个奖学金，以资助那些承担学费困难的同学。但是学校的老师却说，现在的贫困学生已经不像当年那样多了，这个奖学金最好另做他用吧！家庭贫困的学子，已经不像几十年前能与其他同学一并竞争，他们在进入大学前就已经远远落在了别人的身后，在进入大学后还要被别人因 “综合素质低” 而瞧不起。这应该也就是所谓的 “这个时代，寒门再难出贵子” 吧。但是另一位年仅 13 岁的少年就能够列席深圳两会，提议不要让考卷决定未来，其背后的含义就是让综合素质来决定升学，素质教育听上去很不错，但各种各样的素质培训岂是普通家庭所能承担得起的？寒门学子也许只能让考卷决定未来了。小学时代的我以为，身在湖南的我，去湖南大学读书应该不是一件很难的事，但是到了最后才发现，考上湖南大学的同学只有我们高中班上的第一名。那时的我，怎能理解抽象的高考分数中所蕴含的意义呢？有时候心想，如果考上清华大学，人生是不是会变得更精彩一些？每一个比较幸运的人都欠那些不够幸运的人一份机遇。中国的经济腾飞即将落下帷幕，改变命运的机会在衰落的经济环境下将会越来越少，社会阶层的快速流动也将不复存在，那时候我们面对的将是无穷的未知变化。不知什么时候开始，感觉到同学们的志向不再那么高远，似乎只想拥有一份普通的生活。小时候所向往成为的科学家也渐渐离我们远去了，同学间的交流也总离不开就业，他们好像抛弃了年少的自己，离自己的理想也是渐行渐远。这其中究竟发生了什么？难道所有人都愿意看透自己的未来——从参加工作到退休，一成不变的生活真的不会没有意义吗？古人云：“取乎其上，得乎其中；取乎其中，得乎其下；取乎其下，则无所得矣。” 少年应当是社会的希望，志向也应高远，如果我们的志向仅仅止于基本物质的满足，那么未来必定坎坷。18 岁的史学天才林嘉文在自杀前的遗书中这样写道，“未来对我太没有吸引力了。仅就世俗的生活而言，我能想象到我能努力到的一切，也早早认清了我永远不能超越的界限”。是怎样的社会前景，居然能让一个对历史兴亡有着透彻理解的人选择永远地离开世界呢？我不知道答案，也许将来会知道。吾尝终日而思矣，不如须臾之所学也；吾尝跂而望矣，不如登高之博见也。面对变幻莫测的机遇时，我所能做的只有珍惜眼前的学习机会，以期未来能帮助那些不如我幸运的人。他们需要的，不仅仅是登高的一条路。幸运的我们更需要像约翰 · 罗尔斯所说的那样，与他人分享命运。