<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>超级码力</title>
  <icon>https://www.gravatar.com/avatar/11653e84492ba4297c8d37a4be727325</icon>
  <subtitle>Stay hungry, stay foolish!</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://supercoder.xyz/"/>
  <updated>2024-04-17T08:28:41.922Z</updated>
  <id>http://supercoder.xyz/</id>
  
  <author>
    <name>Pele Chen</name>
    <email>chpei@foxmail.com</email>
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>《&lt;论语&gt;导读》读书笔记</title>
    <link href="http://supercoder.xyz/2024/04/15/%E3%80%8A%E8%AE%BA%E8%AF%AD%E3%80%8B%E5%AF%BC%E8%AF%BB/"/>
    <id>http://supercoder.xyz/2024/04/15/《论语》导读/</id>
    <published>2024-04-15T02:02:00.000Z</published>
    <updated>2024-04-17T08:28:41.922Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/《论语》导读/cover.jpg" class="img-topic" /><p>“半部论语治天下 ”，《论语》对中国人的影响非常深远，甚至可以说是中国文化的“元典”。</p><p>在学生时代，每个人都或多或少学习过论语中的部分内容，然而仅靠部分只言片语，加之年代久远，部分文字与今天的使用习惯相去甚远，我们很难理解《论语》的精神内核，有些时候还会断章取义。</p><p>如今，重读鲍鹏山先生解读的《论语》，通过理性客观的解析，还原了更加真实的孔子，也对之前一知半解的“温故而知新”，“以直报怨”，“学而优则仕”有了更深刻的理解。</p><span id="more"></span><h2 id="原文摘录"><a href="#原文摘录" class="headerlink" title="原文摘录"></a>原文摘录</h2><p>P28</p><blockquote><p>子曰：“温故而知新，可以为师矣。”<br>今译——孔子说： “能够温习旧知识，判断新事物，就可以做老师了。”<br>导读——孔子这里讲的是什么样的人才配做老师。我们一般理解，老师就是掌握了大量的知识，并把它传授给学生的人。但在孔子看来，这还只是“温故”。真正的好老师，不仅要有知识，而且还要有头脑，有眼光，有对人间是非善恶美丑的判断力，要有见识。<strong>他教给学生的，不仅是已有的知识，而且还要教给学生思想的方法和判断的价值标准。</strong>有了思想的方法和判断的标准，才能对这个世界层出不穷的事件做出正确的判断，才算是“知新”。只有既能温故，又能知新的人，才配做老师。</p></blockquote><p>P34</p><blockquote><p>哀公问曰：“何为则民服？”孔子对曰：“举直错诸枉，则民服；举枉错诸直，则民不服。”<br>今译——鲁哀公问孔子：“怎样做才能使百姓服从？”孔子答道：“举用正直的人，置于邪曲的人之上，百姓就会服从了；如果把邪曲的人，置于正直的人之上，百姓就会不服。”<br>导读——<strong>人民并不是服从权势，而是服从真理，服从正义。</strong>权势的压服并不能改变天赋的良知。哪怕我们不得不暂时屈服，我们心中仍然向往光明。这和法家如韩非，认为人民总是屈从权势而不是向慕正义(参见韩非《五蠹》)形成鲜明对比。<strong>哀公之问，立足于如何管制人民；孔子之答，立足于如何做好自己。</strong>哀公之问，是讨教使人民服从之方法；孔子之答，是讨还要人民服从之条件。“举枉错诸直，则民不服”，是孔子赋予了人民不服从的权力。</p></blockquote><p>P64</p><blockquote><p>子曰：“唯仁者能好人，能恶人。”<br>今译——孔子说：“只有仁德的人才能（有资格、有能力）喜爱一个人，憎恶个人。”<br>导读——仁者爱正义，必恨不正义。不仁者未必恨不正义，也就未必爱正义。<strong>仁者的爱憎是公正的</strong>。所以，只有仁者才有资格爱，尤其是有资格恨。被仁者所爱的人，必有可贵可爱之处；被仁者所恨的人，亦必有可恨之处。<strong>不仁者的爱憎是私爱与私仇</strong>。所以，不仁者未必有真爱，但却常常有刻骨的恨。被不仁者爱的人，未必真可爱；被不仁者恨的人，更未必真可恨—恰恰相反，倒有可能是一个正直的人。仁者之于爱恨，有三个逻辑层次。第一，仁者有爱有恨，是为仁者的道德。无爱无恨是道德的麻木。第二，仁者能爱能恨，是为仁者的能力。仁者有能力区分善恶美丑并予以爱恨。第三，仁者必须表达自己的爱恨，是为仁者的责任。仁者的爱恨是这个世界激浊扬清的能量，不可或缺，仁者的爱，是对善的鼓励；仁者的恨，是对恶的制约。在仁者的爱恨里，世界上的善恶在此长彼消。</p></blockquote><p>P123</p><blockquote><p>子曰：“饭疏食，饮水，曲肱而枕之，乐亦在其中矣。不义而富且贵，于我如浮云。”<br>今译——孔子说：“吃粗粮，喝冷水，弯起胳膊当枕头，乐趣就在其中了。用不义的手段得到的富与贵，对于我如同浮云。”<br>导读——真正幸福的生活都是简单、单纯的。物质的简朴正好减轻了精神的负担，使之轻松自如。<strong>那些愿意在简朴的物质条件中生活的人，才能真正体验到生活的快乐与丰富。</strong>不义而富且贵——一个“不义”，做贼心虚和道德上的自责，会把我们的心境破坏殆尽。这一段说得极高尚而极美，极感性而极哲学。</p></blockquote><p>P167</p><blockquote><p>子曰：“民可使由之，不可使知之。”<br>今译——孔子说：“百姓可以让他们听从指引而行事，却没办法做到让他们都明白为什么要这样。”<br>导读——很多人拿这一句话来指责孔子鼓吹愚民。首先，这是历史的局限性：那时代，教育不能普及，民智不可能大面积开发；政权不能开放，人民不可能大面积参政。在此情形之下，孔子有这样的言论，固然不必赞扬，也似乎不必上纲上线大加挞伐。《史记·滑稽列传》载西门豹言：“民可以乐成，不可与虑始。”《史记·商君列传》：“民不可与虑始，而可以乐成。论至德者不和于俗，成大功者不谋于众。”可见这类思想在那时的精英阶层中颇为流行。但是，孔子一生从事教育开启民智，显然不是主张愚民。屈原《离骚》：“众不可户说”，其中的“不可”二字，显然<strong>不是主观不愿意，而是客观情势不可能</strong>。孔子这句话，正可以这样理解。这不仅符合语法，也符合一直主张“有教无类”并终生“诲人不倦”深知开启民智之难的孔子的口吻和心情。</p></blockquote><p>P309</p><blockquote><p>子曰：“君子道者三，我无能焉：仁者不忧，知者不惑，勇者不惧。”子贡曰：“夫子自道也。”<br>今译——孔子说：“君子努力达到的境界有三条，我没能做到：仁德的人不忧愁，智慧的人不迷惑，勇敢的人不畏惧。”子贡说：“老师说自己啊。”<br>导读——这三条君子努力实行的道理，是否孔子的“夫子自道”，并不重要。重要的是这几句话所包含的哲理：<strong>仁德的人因为关爱万物，所以不会有一己得失的忧愁；智慧的人因为洞察万物，所以不会有一物难通的迷惑；勇敢的人因为勇气充溢心胸，所以不会有什么畏怕。</strong>君子应当做到仁、智、勇，也就大致相当于我们后来提倡的“德、智、体全面发展”。</p></blockquote><p>P311</p><blockquote><p>子曰：“不患人之不已知，患其不能也。”<br>今译——孔子说：“不要担心别人不了解自己（的才能），要担心自己没有才能。”<br>导读——为什么这样？因为，一、从逻辑先后上说，你必须先有才能，然后才可能让人了解；二、一个人，假如真有才能，迟早都会被人认识到，是真金子总会发光。所以，<strong>君子不要急于推销自己，而要耐心磨砺自己。</strong></p></blockquote><p>P314</p><blockquote><p>或曰：“以德报怨，何如？”子曰：“何以报德？以直报怨，以德报德。”<br>今译——有人说：“用恩惠来报答仇怨，如何呢？”孔子说：“那用什么来报答恩惠呢?用公平正直来对待仇怨，用恩惠来报答恩惠。”<br>导读——关于如何报怨，有三种选择：第一，以怨报怨；第二，以德报怨；第三，以直报怨……可见，提倡“以德报怨”不但不能促进道德，反而要促退道德。所以，孔子提出了“以直报怨”的观点。用公正来对待仇怨。即使是坏人，他也应该得到公正的对待。既不特别宽恕他，也不过分报复他，让他得到他该得到的。</p></blockquote><p>P348</p><blockquote><p>子曰：“君子谋道不谋食。耕也，馁在其中矣；学也，禄在其中矣。君子忧道不忧贫。”<br>今译——孔子说：“君子谋求道义不谋求衣食。(怕挨饿去）耕田，未必不挨饿；学习知识，则反而获得了俸禄。君子只担忧不能学到道，不担忧贫穷。”<br>导读——谋食者，器也；谋道者，道也。“君子不器”，岂能谋食？谋食虽然不下贱，却毕竟也不高尚。君子要担当道义，要忧国忧民，求田问舍，不亦下乎！此则对于今日之功利浮躁，以及教育之实用主义，尤有针对性。今日的教育，几乎完全变成了谋生的教育。其实，孔子说得对：<strong>一切为了谋生，还真的未必能谋生；不汲汲于富贵者，反倒有可能成就事业，到那时，谋生也就不成问题了。</strong></p></blockquote><p>P368</p><blockquote><p>孔子曰：“生而知之者，上也；学而知之者，次也；困而学之，又其次也；困而不学，民斯为下矣。”<br>今译——孔子说：“生来就知道的，是上等；经过学习然后知道的，是次一等；实践中遇到问题然后再学习，是再次一等；遇到不懂的问题还不学习，这样的百姓就是下等的了。”<br>导读——生下来就懂得很多的人，大约没有。连孔子也说自己是“学而知之”的。那么，学习的人就剩两种情况：知道学习的重要，主动去学习的人；在实践中遇到不能解决的问题，然后再去学习的人。情况虽不同，但最终的结果是一样的：都通过“学”到达了“知”。只有那些不懂又不学的人，是万劫不复，永远也无救的下等贱人。生而知之者，神也；学而知之者，圣也；困而学之者，众人也；困而不学者，下愚不移之人也。<strong>人是有高低贵贱之别的，这种差别，不是来自于血缘、出身，而是自身的修为。</strong></p></blockquote><p>P418</p><blockquote><p>子夏曰： “仕而优则学，学而优则仕。”<br>今译——子夏说：“做官而有余力就去学习；学习而有余力便去做官。”<br>导读——“仕而优则学”，我们不大听人说起； “学而优则仕”，则成了国人的口头禅。这是一种很值得反思的文化现象，我们从中可以感觉到中国的“官本位”文化影响之深。到了科举考试时代，做官要考试，考试当然要选拔成绩优秀的，于是，这个“学而优则仕”就成了——学习好了，就可以做官了。其实，子夏这里说的，应该是孔门包括他自己的门风：做官，有了闲暇，或有了间歇，就来跟老师学习一段时间；学习，有了间歇和机会，就出去做做官。来去自由——这是一种非常值得我们羡慕的生活方式。要知道，孔子开创的私学，并非我们今天的学校，有一定的学制，有一定的年龄，有一定的人籍和毕业要求。它是成人的终生学习和生活方式，无学制，无年限，无时限，无人籍，无毕业。所以，孔子的学生，如冉求，如子路，如子贡，等等等等，都是<strong>有时在学，有时在仕，仕与学，学与仕，两种状态，随时转换。</strong>如果像后世理解的那样，把“学而优则仕”解释为学习好了就去做官，那么，难道“仕而优则学”倒成了“官做好了要来学习”？做不好的反倒要一直做下去？</p></blockquote><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>《论语》导读 鲍鹏山著 中国青年出版社 2017年08月</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/《论语》导读/cover.jpg&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;“半部论语治天下 ”，《论语》对中国人的影响非常深远，甚至可以说是中国文化的“元典”。&lt;/p&gt;
&lt;p&gt;在学生时代，每个人都或多或少学习过论语中的部分内容，然而仅靠部分只言片语，加之年代久远，部分文字与今天的使用习惯相去甚远，我们很难理解《论语》的精神内核，有些时候还会断章取义。&lt;/p&gt;
&lt;p&gt;如今，重读鲍鹏山先生解读的《论语》，通过理性客观的解析，还原了更加真实的孔子，也对之前一知半解的“温故而知新”，“以直报怨”，“学而优则仕”有了更深刻的理解。&lt;/p&gt;
    
    </summary>
    
      <category term="书评" scheme="http://supercoder.xyz/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
      <category term="论语" scheme="http://supercoder.xyz/tags/%E8%AE%BA%E8%AF%AD/"/>
    
      <category term="孔子" scheme="http://supercoder.xyz/tags/%E5%AD%94%E5%AD%90/"/>
    
  </entry>
  
  <entry>
    <title>《技术与文明》读书笔记</title>
    <link href="http://supercoder.xyz/2024/04/02/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%96%87%E6%98%8E/"/>
    <id>http://supercoder.xyz/2024/04/02/技术与文明/</id>
    <published>2024-04-02T11:02:00.000Z</published>
    <updated>2024-04-17T08:28:41.922Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/技术与文明/cover.jpg" class="img-topic" /><p>本书从技术视角，阐述了新技术对人类社会发展所起的推动作用，这些技术包括弩、枪炮、活字印刷、蒸汽机、核能、人工智能等。</p><p>社会是复杂的，妄想从历史中抽丝剥茧，找出决定历史演进的关键因素是不现实的，无论是英雄人物还是技术，将任何一个归因放大都是不可取的。然而，以往的历史书经常记录王侯将相，让我们误以为某个人在历史进程中起了决定作用，但实际上，有很多不起眼的小人物，或者技术，又或者其他因素，也扮演了举足轻重的作用。从这个角度来讲，本书帮我们从技术角度来看待社会的发展，真是开了脑洞，值得推荐。</p><p>作者知识广博，对史料的运用也是信手拈来，文笔流畅，读起来酣畅淋漓。但作者在字里行间流露出对于部分专家观点的不懈甚至否定，有点过于偏激，感觉就像在写高考作文或者参加辩论赛，对别人的论点全面否定才能证明自己的眼光独到。个人认为，在这一点上，有点减分。</p><p>总体而言，本书还是值得一读的。</p><span id="more"></span><h2 id="原文摘录"><a href="#原文摘录" class="headerlink" title="原文摘录"></a>原文摘录</h2><p>P29</p><blockquote><p>“弩机猜想”的内容是：当“弩机”这种军事技术在一国内大范围普及时，它会给这个国家的统治者提供一种战略优势，那便是用技术的力量将原先无法有效动员的平民百姓充分动员起来，变成可以驱策的部队，以适应战国时代的大规模冲突。<br>批注：貌似是商鞅变法依赖的技术基础。</p></blockquote><p>P123</p><blockquote><p>事实上，毕升发明的活字印刷术后，这一技术并未能大范围流通。相反，从清代《四库全书》对印本记载的资料来看，中国通行的印刷术仍然以雕版为主。</p></blockquote><p>P124</p><blockquote><p>活字印刷最大的问题是，印刷工人需要从几千个成型的活字模中选择需要的那个汉字，如果工人不识字，这个工作几乎无法进行，而雕版印刷就不存在这个问题。</p></blockquote><p>P125</p><blockquote><p>从技术上讲，中国的活字印刷比起雕版印刷自然是进步的，但从商业形态上讲，它却是失败的。因此，一项技术是否能够促成大规模改变，往往不止取决于它本身先进与否，也取决于它的商业应用效果，比如，是否能降低成本、增加销量，以及是否能赚钱。</p></blockquote><p>P185</p><blockquote><p>从这个角度，我们或许也可以说，现代国家的出现，更是另外一种意义上的陷阱——“进步的陷阱”。军事技术的进步，让人们迫切寻求国家力量的庇护，政府也因此发展起来，更高效地汲取资源，提高税率，统计人口，建立发达的监控体系，增强保卫自己的能力。但是与此同时，人民也被迫征召入伍，被迫武装起来，被迫拉上战场，在严格的训练体系下，以“排队枪毙”的方式一列列死去。我们总是愿意相信“进步”在道德上比“落后”要高尚，但对普通人而言，这个预设很可能是不成立的。无论是历史进步的车轮还是历史退步的车轮，他们很可能都是被碾过的对象。</p></blockquote><p>P257</p><blockquote><p>在过去的历史叙事中，我们习惯于把这三个故事分开来理解，并且从中找到不同的意义：对清朝统治者来说，我们指责他们闭关锁国，不肯睁眼看世界；对非洲土著来说，我们同情他们文明发展程度的落后和遭受的欧洲殖民者的欺凌；对欧洲国家来说，我们认为是利益集团疯狂的扩张欲望和严重固化的阶级结构导致帝国主义的诞生，而帝国的混战又使自身走向灭亡，唯一的出路在于推动阶级和身份平等的革命。但当以“机枪”为线索把这三个故事串起来之后，我们却发现，它们其实是同一个故事：新技术把人类文明带到了一个从未想象过的运行规模和运行层面上，以至于即便是技术的发明国，也没有为这样巨大规模和快速的变化做好准备。而且，这三个故事的时间线其实也差不太多：19世纪末的清朝统治者固然不知道机枪的威力，但20世纪初的欧陆贵族军官的表现也没有好到哪里去。</p></blockquote><p>P354</p><blockquote><p>人与机器之间的边界，最危险之处并不在于机器能多么像人，而在于人在多大意义上已经变得像机器——像机器一样只在规范之内定义自己， 接受权威灌输和社会主流观念的潜移默化以及消费主义的各种操纵，而<strong>无力反思更高层面的问题</strong>。</p></blockquote><p>P449</p><blockquote><p>如何不做技术的奴隶？答案是，清楚地了解技术能做什么和不能做什么。首先，我们要学会一种思维方式：任何领域，随着技术的发展，一定会有90%的工作流程被技术取代。……仔细观察一下这些消失的职业，我们会发现，他们实质上都只做一件事情：技术的辅助者。接线员是因为特定的电话技术存在的；电报收发员是因为特定的电报技术存在的；底片冲洗工是因为特定的照片冲洗技术存在的。这些工作流程；就是属于那90%能被技术取代的流程。那么，剩下的10%是什么呢？是与人相关的工作。——<strong>要么连接技术与人，要么连接人与人</strong>。</p></blockquote><p>P450</p><blockquote><p>你并不是要把一项技术卖给什么人，而是要发现，某项技术能够为什么领域带来价值。要实现这一点，既要真正了解这项技术能够实现什么，它的优缺点和发展进程大致是怎样的，又要了解它所施展的领域，它真正的需求在哪里，市场规模是怎样的，能够取得多大的替代效应。</p></blockquote><p>P452</p><blockquote><p>如果你是技术型人才，不妨借鉴一下社会科学的视角；如果你更擅长人文社科领域，不妨试着关心一下技术的上“硬变量”。</p></blockquote><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>《技术与文明》 张笑宇著 广西师范大学出版社 2021年04月</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/技术与文明/cover.jpg&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;本书从技术视角，阐述了新技术对人类社会发展所起的推动作用，这些技术包括弩、枪炮、活字印刷、蒸汽机、核能、人工智能等。&lt;/p&gt;
&lt;p&gt;社会是复杂的，妄想从历史中抽丝剥茧，找出决定历史演进的关键因素是不现实的，无论是英雄人物还是技术，将任何一个归因放大都是不可取的。然而，以往的历史书经常记录王侯将相，让我们误以为某个人在历史进程中起了决定作用，但实际上，有很多不起眼的小人物，或者技术，又或者其他因素，也扮演了举足轻重的作用。从这个角度来讲，本书帮我们从技术角度来看待社会的发展，真是开了脑洞，值得推荐。&lt;/p&gt;
&lt;p&gt;作者知识广博，对史料的运用也是信手拈来，文笔流畅，读起来酣畅淋漓。但作者在字里行间流露出对于部分专家观点的不懈甚至否定，有点过于偏激，感觉就像在写高考作文或者参加辩论赛，对别人的论点全面否定才能证明自己的眼光独到。个人认为，在这一点上，有点减分。&lt;/p&gt;
&lt;p&gt;总体而言，本书还是值得一读的。&lt;/p&gt;
    
    </summary>
    
      <category term="书评" scheme="http://supercoder.xyz/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
      <category term="技术" scheme="http://supercoder.xyz/tags/%E6%8A%80%E6%9C%AF/"/>
    
      <category term="文明" scheme="http://supercoder.xyz/tags/%E6%96%87%E6%98%8E/"/>
    
      <category term="未来" scheme="http://supercoder.xyz/tags/%E6%9C%AA%E6%9D%A5/"/>
    
  </entry>
  
  <entry>
    <title>《中国人的修养》读书笔记</title>
    <link href="http://supercoder.xyz/2024/03/19/%E4%B8%AD%E5%9B%BD%E4%BA%BA%E7%9A%84%E4%BF%AE%E5%85%BB/"/>
    <id>http://supercoder.xyz/2024/03/19/中国人的修养/</id>
    <published>2024-03-19T11:02:00.000Z</published>
    <updated>2024-04-17T08:28:41.922Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/中国人的修养/cover.jpg" class="img-topic" /><p>本书主要收录了蔡元培先生给学生授课所用的《华工学校讲义》和《中学修身教科书》，还有数篇关于道德修养的演讲稿，充分体现了蔡元培先生对于现代中国人应具有的道德素养的总体构想。</p><p>书中内容，主要是用半白话，半文言文方式写成的。既有中华传统文化，还有欧美进步思想。时隔近百年，仍被蔡元培先生学贯中西，迫切想提升民族道德修养的精神所感动。</p><p>先生在书中多次强调，<strong>体育、美育、德育</strong>的重要作用，我想这也是当下内卷时代最应该“卷”的方向。</p><p>如今，我们的物质生活极大丰富，而精神生活却极度匮乏，这部一百年前的书仍有非常重要的指导意义。</p><span id="more"></span><h2 id="要点"><a href="#要点" class="headerlink" title="要点"></a>要点</h2><h3 id="修己"><a href="#修己" class="headerlink" title="修己"></a>修己</h3><p>何谓“道德”？蔡元培先生认为</p><blockquote><p>人之生也，<strong>不能无所为，而为其所当为者，是谓道德</strong>。道德者，非可以猝然而袭取也，必也有理想，有方法。吾国圣人，<strong>以孝为百行之本</strong>，小之一人之私德，大之国民之公义，无不由是而推演之者，故曰唯孝友于兄弟，施于有政，由是而行之于社会，则宜尽力于职分之所在，而于他人之生命若财产若名誉，皆护惜之，不可有所侵毁。行有余力，则又当博爱及众，而勉进公益，由是而行之于国家，则于法律之所定，命令之所布，皆当恪守而勿违。而有事之时，又当致身于国，公而忘私，以尽国民之义务，是皆道德之教所范围，为吾人所不可不勉者也。</p></blockquote><p>如何培养良好的道德？</p><blockquote><p>夫道德之方面，虽个个不同，而行之则在己。知之而不行，犹不知也；知其当行矣，而未有所以行此之素养，犹不能行也。怀邪心者，无以行正义；贪私利者，无以图公益。未有自欺而能忠于人，自侮而能敬于人者。故道德之教，虽统各方面以为言，而其本则在乎修己。修己之道不一，而以康强其身为第一义。身不康强，虽有美意，无自而达也。康矣强矣，而不能启其知识，练其技能，则奚择于牛马；故又不可以不求知能。知识富矣，技能精矣，而不率之以德性，则适以长恶而遂非，故又不可以不养德性。<strong>是故修己之道，体育、智育、德育三者，不可以偏废也。</strong></p></blockquote><h3 id="孔子之精神生活"><a href="#孔子之精神生活" class="headerlink" title="孔子之精神生活"></a>孔子之精神生活</h3><p>蔡元培先生认为，但使物质生活与精神生活在不可兼得的时候，孔子一定偏重精神方面。他从3个方面观察孔子的精神生活：</p><ul><li>在智的方面，“朝闻道，夕死可矣。”这是何等的高尚！</li><li>在仁的方面，“志士仁人，无求生以害仁，有杀身以成仁。”这是何等的伟大！</li><li>在勇的方面，“君子有勇而无义为乱，小人有勇而无义为盗。”这是何等的谨慎！</li></ul><p>除了以上三个方面外，还有2个特点：</p><ul><li>毫无宗教的迷信。孔子也言天，也言命，照孟子的解释，莫之为而为是天，莫之致而致是命，等于数学上的未知数，毫无宗教的气味。凡宗教不是多神，便是一神；孔子不语神，敬鬼神而远之，说“未能事人，焉能事鬼?”完全置鬼神于存而不论之列。凡宗教总有一种死后的世界；孔子说: “未知生，焉知死?”</li><li>利用美术的熏陶。孔子的时代，建筑、雕刻、图画等美术，虽然有一点萌芽，还算是实用与装饰的工具，那时候认为纯粹的美术是音乐。孔子以乐为六艺之一，对于音乐的美感，是后人所不及。</li></ul><p>最后，他说</p><blockquote><p>以智、仁、勇为范围，无宗教的迷信而又音乐的陶养，这是完全可以为师法的。</p></blockquote><h3 id="美育与人生"><a href="#美育与人生" class="headerlink" title="美育与人生"></a>美育与人生</h3><p>先生认为，知识可以解决眼前的问题，而情感可以解决长远问题。</p><blockquote><p>人的一生，不外乎意志的活动，而意志是盲目的，其所恃以为较近之观照者，是知识；所以供远照、旁照之用者，是感情。<br>当着重要关头，有“富贵不能淫，贫贱不能移，威武不能屈”的气概；甚且有“杀身以成仁”而不“求生以害仁”的勇敢；这种是完全不由知识的计较，而由于感情的陶养，就是不源于智育，而源于美育。</p></blockquote><p>先生建议，我们平时除了工作之外 ，一定要多读书、听音乐。</p><blockquote><p>所以吾人固不可不有一种普通职业，以应利用厚生的需要；而于工作的余暇，又不可不读文学，听音乐，参观美术馆，以谋知识与感情的调和，这样，才算是认识人生的价值了。</p></blockquote><h3 id="复兴民族与学生"><a href="#复兴民族与学生" class="headerlink" title="复兴民族与学生"></a>复兴民族与学生</h3><p>蔡元培先生认为，我们要实现民族复兴，需要从以下3个方面入手：</p><ul><li>体格</li><li>知识及能力</li><li>品性的修养</li></ul><p>总结起来，还是<strong>体育、智育、德育</strong>这3个方面。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>《中国人的修养》蔡元培著 金城出版社 2014年08月</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/中国人的修养/cover.jpg&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;本书主要收录了蔡元培先生给学生授课所用的《华工学校讲义》和《中学修身教科书》，还有数篇关于道德修养的演讲稿，充分体现了蔡元培先生对于现代中国人应具有的道德素养的总体构想。&lt;/p&gt;
&lt;p&gt;书中内容，主要是用半白话，半文言文方式写成的。既有中华传统文化，还有欧美进步思想。时隔近百年，仍被蔡元培先生学贯中西，迫切想提升民族道德修养的精神所感动。&lt;/p&gt;
&lt;p&gt;先生在书中多次强调，&lt;strong&gt;体育、美育、德育&lt;/strong&gt;的重要作用，我想这也是当下内卷时代最应该“卷”的方向。&lt;/p&gt;
&lt;p&gt;如今，我们的物质生活极大丰富，而精神生活却极度匮乏，这部一百年前的书仍有非常重要的指导意义。&lt;/p&gt;
    
    </summary>
    
      <category term="书评" scheme="http://supercoder.xyz/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
      <category term="教育" scheme="http://supercoder.xyz/tags/%E6%95%99%E8%82%B2/"/>
    
      <category term="修养" scheme="http://supercoder.xyz/tags/%E4%BF%AE%E5%85%BB/"/>
    
      <category term="道德" scheme="http://supercoder.xyz/tags/%E9%81%93%E5%BE%B7/"/>
    
  </entry>
  
  <entry>
    <title>《自卑与超越》读书笔记</title>
    <link href="http://supercoder.xyz/2024/01/07/what-life-could-mean-to-you/"/>
    <id>http://supercoder.xyz/2024/01/07/what-life-could-mean-to-you/</id>
    <published>2024-01-07T11:02:00.000Z</published>
    <updated>2024-04-17T08:28:41.922Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/what-life-could-mean-to-you/cover.jpg" class="img-topic" /><p>每个人都有不同程度的自卑感，因为没有一个人对其现时的地位感到满意；对优越感的追求是所有人的通性。然而，并不是人人都能超越自卑，关键在于正确对待职业、社会和性，在于正确理解生活。——阿尔弗雷德·阿德勒</p><p>本书成书于1932年，距今将近100年，书中谈到了童年、家庭、学校等方方面面对个人成长的影响，也举了很多案例，虽然感觉不成体系，但是有些观点还是值得反复咀嚼的。</p><span id="more"></span><h2 id="要点"><a href="#要点" class="headerlink" title="要点"></a>要点</h2><h3 id="兴趣与合作"><a href="#兴趣与合作" class="headerlink" title="兴趣与合作"></a>兴趣与合作</h3><p>本书一开篇，作者就带着我们探讨生活的意义，他提出人活在地球上，会受到三种限制：</p><ul><li>我们无法脱离地球表面去生活</li><li>我们不是孤立的生活着，要和其他人产生联系</li><li>我们生命的延续依赖于人的两种性别</li></ul><p>对于个体来说，就是每个人不得不面临的<code>职业</code>、<code>社交</code>和<code>性</code>的问题。几乎所有的失败者，都处理不好这些关系，其根本原因是缺乏归属感和社会兴趣。作者提出，<strong>合作才是解决之道</strong>，包括在家庭和学校，都要广泛培养孩子的合作能力。</p><h3 id="性本善还是恶？"><a href="#性本善还是恶？" class="headerlink" title="性本善还是恶？"></a>性本善还是恶？</h3><p>作者否定了遗传决定性格的观念，他认为“人之初，性本善”或“性本恶”的想法是站不住脚的，人们最终选择走向何方，取决于他从环境所接受的感觉和印象，以及他对这些感觉和印象的解释。他还否认卓越出自于天赋，甚至连莫扎特这样的音乐天才，他都不认为是天赋起了决定作用，这个观点与刻意练习的理论不谋而合。</p><h3 id="自卑感与优越感"><a href="#自卑感与优越感" class="headerlink" title="自卑感与优越感"></a>自卑感与优越感</h3><p>不是说有强烈自卑感的人一定是个显得柔顺、安静、拘束而与世无争的人。愤怒、眼泪、紧张、道歉都可能是自卑的表现。</p><p>我们每个人都有不同程度的自卑感，因为我们都想让自己变得更优秀。如果我们勇往直前，通过改进环境，可以逐渐摆脱自卑感。就像作者所说，<strong>人类的全部文化都是以自卑感作为基础的，在每件人类的行为之后，都隐藏有对优越感的追求</strong>，比如，科学的兴起就是因为人类感到他们的无知，和他们对预测未来的需要，从而努力奋斗的结果。</p><p>可是，没有人能长期忍受自卑感，如果暂时摆脱不了自卑感，他的目标仍然是“凌驾于困难之上”，可是他却不再设法克服障碍，<strong>反倒用一种优越感来自我陶醉或麻木自己</strong>。同时，他的自卑感会愈积愈多，因为造成自卑的情境仍然一成未变，问题也依旧存在。他所采取的每一步都会逐渐将他导入自欺之中，而他的各种问题也会以日渐增大的压力逼迫着他。他不是把自己锻炼得更强壮、更有适应能力，而是训练自己，让自己在自己的眼中显得更强壮。他可以用这种方式来麻醉自己，但是他的自卑感仍然原封未动。</p><h2 id="原文摘录"><a href="#原文摘录" class="headerlink" title="原文摘录"></a>原文摘录</h2><p>P20</p><blockquote><p>每种生活问题的解决都需要合作的能力，而每种工作也都必须在人类社会的架构下，以能够增进人类福利的方式来予以执行，<strong>只有了解生活的意义在于奉献的人，才能够有较大的机会成功地克服困难。</strong>如果老师、父母及心理学家们都能了解：赋予生活以某种意义时可能会犯错误，当遇到问题时，我们应该不断努力，而不能把肩上的重担推给别人、口出怨言以博取关怀和同情，或觉得非常丢脸而自暴自弃。我们应该说： “我们必须开拓我们的生活。这是我们的责任，我们也能够对付它。我们是自己行为的主宰。除旧布新的工作，舍我其谁！”假如每个独立自主的人，都能以这种合作的方式来对待生活，那么人类社会的进步必然是无止境的。</p></blockquote><p>P45</p><blockquote><p>争取优越感的动作总是朝向生活中无用的一面，真正的问题却被遮掩起来或避开不谈。个人限制了他的活动范围，苦心孤诣地要避免失败，而不是追求成功。他在困难面前会表现出犹疑、彷徨，甚至是退却的举动。</p></blockquote><p>P134</p><blockquote><p>事实上，不仅是我们的社会生活，我们的整个世界都是如此——那么我们便会认识到：人类都在追求想要成为征服者，想要超越并压垮别人的目标。这种目标是早年训练的结果，也是觉得自己在家庭中未曾受到平等待遇的儿童努力奋斗、拼命竞争的结果。我们要避免这一类的危害，唯一的方法就是给予儿童更多的合作训练。</p></blockquote><p>P142</p><blockquote><p>在我们现行的教育制度下，我们通常会发现：当孩子开始上学时，<strong>他们对竞争的准备比对合作的准备更为充分。</strong>在他们的学校生活中，对竞争的训练也一直持续不断。对孩子而言，这是一种不幸。假如他击败了别的孩子，遥遥领先，他的不幸并不见得比屈居人后而万念俱灰的孩子少。在这两种情况下，他都会变得只对自己感兴趣。他的目标将不会是奉献和施予，而是夺取能供自己享用之物。正如家庭应该团结一致，每个成员都是团体中平等的一分子一样，班级里的同学也应该如此。只有按照这个方向开展教育，孩子们才会真正彼此感兴趣，并享受到合作的快乐。</p></blockquote><p>P146</p><blockquote><p>现在，有许多精神病学家和心理学家也都殊途同归地得出同样的看法，认为<strong>性格中有遗传成分的信念只能称为迷信而已</strong>。这种迷信已经存在几千年了。当人们想要逃避责任，并对人类行为采取宿命论的观点时，性格特征是来自遗传的理论便自然而然地出现。它最简单的形式就是“人之初，性本善”或“性本恶”的想法。这种说法显然是站不住脚的，只有逃避责任的欲望很强的人才会坚持它。<strong>“善恶”像其他各种性格的表现一样，只有在社会环境中才有意义。</strong>它们是在社会环境中和同类相互切磋所得的结果，它们蕴含了一种判断，“顾全他人的利益”，或“违反他人的利益”。在孩子出生之前，他并没有这一类的社会环境。出生之后，他的潜能足以使他往任何一个方向发展。他所选择的途径决定于他从环境和从自己身体所接受的感觉和印象，以及他对这些感觉和印象的解释。</p></blockquote><p>P178</p><blockquote><p><strong>罪犯全部都是懦夫。</strong>他们逃避了他们觉得自己的能力不足以应付的问题。除了他们所犯的罪行之外，我们可以在他们面对生活的方式中看出他们的懦弱。即使是在他们所犯的罪行里，我们也可以看到他们的懦弱。他们隐藏在僻静和黑暗中，恐吓过往行人，在行人采取防卫措施之前先亮出了武器。罪犯以为自己是很勇敢的，但是我们绝不可认同他们的想法，否则，我们就被愚弄了。<strong>罪行是懦夫模仿英雄行径的表现。</strong>他们在追求着一种自己构想出来的个人优越感目标，他们以为自己是英雄，但其实这又是一种错误的统觉表，也是缺少常识的表现。我们知道他们是懦夫，假如他们知道我们对这一点很清楚时，必然会大吃一惊。</p></blockquote><p>P199</p><blockquote><p>我们发现，在形形色色的罪犯之间，在各种不同的失败者之间，他们最主要的共同点就是缺乏合作精神，缺乏对别人及对人类幸福的兴趣。</p></blockquote><p>P212</p><blockquote><p>有些孩子在16岁结束高中学业之时，对自己未来的职业仍然拿不定主意。他们经常是品学兼优的学生，但是对以后的生活却一点主意也没有。如果详加注意，我们会发现这些孩子大多野心勃勃，不过却不肯真正与人合作。</p></blockquote><p>P221</p><blockquote><p>我们应该认识到，婚姻并不是私人的事情，而是全体人类在心灵上和精神上都必须参与的共同事务。结婚之后，双方都必须负起某些责任，这是整个社会对他们的期待。社会希望他们生育健全的子女，并以合作的精神将之抚育成人。因此，在每一桩婚姻中，每一个人都应当乐于合作。原始社会用图腾和其复杂的制度来控制婚姻的方法，在今日看来也许相当可笑，但是它们在当时的重要性则是不容忽视的。它们的真正目的在于增加人类的合作。在生活中会遭遇最大困难，并做出损人利己之事的人，就是对其同胞不感兴趣的人。人类所有的失败者都是从这批人中孕育出来的。各种不同的宗教都以自己的方式鼓励合作。站在我的观点，任何人类的努力，只要是以合作为最高目标的，我都完全赞同。争执、批评和贬抑对方都是不必要的。</p></blockquote><p>P226</p><blockquote><p>忧郁症患者还有以自杀作为报复手段的倾向，因此医生第一件要注意的事，就是避免给他们自杀的借口。我自己解除这种紧张的方法是向他们建议治疗中最重要的规则：“不要做你不喜欢做的任何事情。”这似乎是微不足道的小事，但是我相信它牵涉到整个问题的基础。</p></blockquote><p>P235</p><blockquote><p>我们甚至可以说，要完全解决这种两个人的合作问题，<strong>每一个配偶都应该关心对方更甚于关心自己。这是爱情和婚姻成功的唯一基础。</strong>我们应该已经能够看出，许多关于婚姻的意见及其改革计划都犯了什么样的错误。如果每一个配偶对于其伴侣的兴趣都高于对自己的兴趣，那么他们之间便会有真正的平等。如果他们都很诚心地奉献出自己，他们便不会觉得自己低声下气或受人压制。只有男女双方都有这种态度，平等才有出现的可能。他们两人都应该努力使对方的生活安适和富裕，这样，他们才会有安全感。他们会觉得自己有价值，他们觉得自己被需要。</p></blockquote><p>P240</p><blockquote><p>最坏的情况是个人只顾及自己利益的时候。如果他受过这种训练，他会终日盘算着：我能从生活中得到什么样的快乐或兴奋？他会一直要求自由和解脱，从不考虑要怎样才能使其伴侣的生活更轻松，更富裕。这是一种不幸的做法。我把它比拟为缘木求鱼。它不是罪恶，而是一种错误的方法。因此,在准备我们对爱情的态度之时，我们不能只图安逸或只想逃避责任。爱情中如果含有犹豫和怀疑，爱情便不会坚固。合作需要有永恒不变的决心；当这种结合中包含有固定不变的决心时，我们才认为它是真正爱情和幸福婚姻的例子。这种决心不仅包括有生儿育女的决心，并且要教育他们，训练他们学会合作，尽我们的力量使他们成为良好的公民，成为人类种族中平等负责的一分子。<strong>美好的婚姻是我们养育人类未来一代的最好方法</strong>，所有人都应该记住这一点。婚姻其实是一项工作，它有它自己的规则和律法，我们不能只选用其中一部分，规避其他部分，而又不损及地球上的永恒定律——合作。</p></blockquote><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>《自卑与超越》【奥地利】阿尔弗雷德·阿德勒著 曹晚红译 中国友谊出版公司 2017年01月</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/what-life-could-mean-to-you/cover.jpg&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;每个人都有不同程度的自卑感，因为没有一个人对其现时的地位感到满意；对优越感的追求是所有人的通性。然而，并不是人人都能超越自卑，关键在于正确对待职业、社会和性，在于正确理解生活。——阿尔弗雷德·阿德勒&lt;/p&gt;
&lt;p&gt;本书成书于1932年，距今将近100年，书中谈到了童年、家庭、学校等方方面面对个人成长的影响，也举了很多案例，虽然感觉不成体系，但是有些观点还是值得反复咀嚼的。&lt;/p&gt;
    
    </summary>
    
      <category term="书评" scheme="http://supercoder.xyz/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
      <category term="心理" scheme="http://supercoder.xyz/tags/%E5%BF%83%E7%90%86/"/>
    
      <category term="合作" scheme="http://supercoder.xyz/tags/%E5%90%88%E4%BD%9C/"/>
    
      <category term="自卑" scheme="http://supercoder.xyz/tags/%E8%87%AA%E5%8D%91/"/>
    
  </entry>
  
  <entry>
    <title>《饥饿的盛世：乾隆时代的得与失》读书笔记</title>
    <link href="http://supercoder.xyz/2023/12/31/the-heyday-of-hunger/"/>
    <id>http://supercoder.xyz/2023/12/31/the-heyday-of-hunger/</id>
    <published>2023-12-31T11:36:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/the-heyday-of-hunger/cover.jpg" class="img-topic" /><p>这本书参考了大量史料，帮我们从多个角度，还原“乾隆盛世”的真相，读时酣畅淋漓，读完回味无穷，值得推荐。</p><span id="more"></span><h2 id="得不偿失的盛世"><a href="#得不偿失的盛世" class="headerlink" title="得不偿失的盛世"></a>得不偿失的盛世</h2><p>爱新觉罗·弘历（1711年9月25日—1799年2月7日），清朝第六位皇帝，年号“乾隆”，寓意“天道昌隆”，享年89岁，是我国古代最长寿的皇帝，庙号高宗。</p><p>乾隆皇帝一生的运势极佳。在康熙和雍正七十三年的治理下，大清天下国泰民安，一派生平之象。乾隆属兔，25岁继位，可以说乾隆是在最佳年龄、最佳时机登上了帝位。他的智商、情商都是寻常帝王难以企及的。他熟读史书，对造成朝局不稳的主要因素，比如朋党、权臣、外戚、宦官等，都了然于胸，立志在自己统治时期，革除这些弊端，超过历代帝王成为最伟大的君主。</p><p>乾隆非常勤政，每天早早上朝，六十年如一日。初登帝位，乾隆便一改雍正严苛的治国策略，他化严为宽，一时间，所有人都认为他是一位仁慈善良，甚至有点柔弱的贤君。然而，在乾隆十三年，富察皇后去世后，他像变了个人似的，重回到雍正的老路，甚至比他老爹更甚。他对官员严酷苛刻，虽然对平民百姓十分慈祥，但却大兴文字狱镇压底层百姓。晚年，他精力不济，又回到宽松的治理之路，在禅让大典后，自称“千古完人”，却带着未能平定白莲教起义的遗憾，离开了人世。</p><p>乾隆皇帝是中国历史上最伟大的皇帝之一，他统治下的中国，纵向比，是中国几千年历史中人口最多（近三亿，是登基时的2倍）、国力最盛的时期。横向比，是当时世界上最强大、最富庶的国家。然而这个盛世却是饥饿的盛世、恐怖的盛世、僵化的盛世，是基于少数统治者利益最大化而设计出来的盛世。从物质层面来看，虽然GDP占全球三分之一，但人均GDP却少的可怜，民众吃糠咽菜的记载比比皆是。从精神层面看，乾隆时代的中国人，只需有胃肠，不许有头脑，是中国历史上民众权利被剥夺得最干净、意志被压制得最靡弱的时代。</p><p>虽然登峰造极，但乾隆的统治并没有任何新意。乾隆盛世不过是文景之治、贞观之治和开元盛世的大总结和大重复。不幸的是，这个盛世出现在不应该出现的时候。乾隆所处的18世纪，是人类历史伟大的转折点。在这以前，人类进步的脚步一直是迟缓的。而从这个世纪起，历史开始跑步前进。英国经过产业革命，科技、生产力得到极大地提升，工农业产值几百倍、成千倍的增加，物质财富滚滚而来。法国资产阶级大革命、美国独立、《论法的精神》发表等事件表明，世界正朝着更文明的方向发展。而乾隆盛世却朝着反方向发展，他沉浸在“盛世”的梦境中不能自拔，想尽一切办法维护他的封建统治，没有赶上世界发展的大潮。后来，这片土地沦为半殖民地半封建的悲惨社会，其实在乾隆时代就已埋下了祸根。而他自己，也在百年之后遭遇坟墓被炸、尸骨无存的惨剧，给后人留下“十全天子骨难全”的慨叹。</p><h2 id="原文摘录"><a href="#原文摘录" class="headerlink" title="原文摘录"></a>原文摘录</h2><p>P55</p><blockquote><p>皇帝关心的是天下长治久安，一家一姓的统治永远不变；官员们的考虑却没有这么长远。归根结底，天下是皇帝的天下，官员们只是挣份工资。他们更关心的是如何利用政策空子，占皇帝的便宜，为自己和亲人朋友捞取最大好处。官僚集团运转的规律是：在没有利益驱动时，官员们执行皇帝的政策，总是倾向于被动应付，只求形式上能交代，由此导致敷衍塞责、形式主义，甚至弄虚作假。而当他们发现政策的空子时，通常会把个人利益伪装于国家利益之中，刻意把经念歪。基于利益最大化的原理，官员们热衷于编织关系网，相互通风报信，十分默契地协调行动。在他们的集体努力下，国家政治很快会陷入腐败的泥淖，每一位官员都会成为中饱私囊的“硕鼠”，本来属于皇帝或者说国家的“民脂民膏”被大量消耗，国家的治理成本大幅上升，最终出现“官逼民反”这个命定的结局。</p></blockquote><p>P95</p><blockquote><p>从这一年开始，乾隆回到了雍正的老路上。乾隆朝的君臣关系，从此变成了刁钻刻薄的主子与屏息而侍的奴才间的关系，或者说严厉的班主任与小学生的关系。下面的小学生稍有小动作，额头上就会遭到老师的粉笔头。诛杀和折磨大臣，越来越成为乾隆发泄自己不良情绪的主要渠道。</p></blockquote><p>P137</p><blockquote><p>清代皇帝一直以明朝为他们的前车之鉴，而明王朝给他们的最大教训是“水可载舟,亦可覆舟”。谁都知道，清朝得以入关，是捡了个大便宜，明王朝实际上是被饥饿的农民颠覆的。而颠覆的直接原因，就是对农民剥削过重。万历年间加派三饷，每年从农民身上多搜刮一千多万两白银，剜肉补疮，动摇了大明帝国的根基。所以,清代皇帝经常讲，明不是亡于崇祯，而是亡于万历。熟读历史的乾隆知道，饥饿的农民是国家最危险的敌人，而温饱了的农民则是皇权最坚定的支持者。为了江山万代，乾隆必须减轻对农民的剥削，使绝大多数老百姓有饭吃。这是国家政治的重中之重。统治者的自我克制，在乾隆身上表现得比较明显。乾隆一朝鼓励农民开垦荒地不遗余力，但是出发点却仅仅是为了百姓生计，而不是为国家增加税收。</p></blockquote><p>P270</p><blockquote><p>君权像恶性肿瘤一样，是世界上最具扩张性的事物之一，它不允许任何独立的事物存在。专制权力的独占性本质驱使它永远努力冲破一切限制，挣脱所有束缚，深入社会每一个角落，毒化每一个细胞，直至最后整个社会在它的紧紧拥抱中窒息而死。士人的人格追求，在专制达到极峰的清代就成了君权的障碍。</p></blockquote><p>P295</p><blockquote><p>专制政治中，皇帝是整个国家的神经中枢，官僚体系的精神状态就是皇帝一个人精神状态的放大。不但是人亡政息，同一个统治者的心境变化，也可以使国家面貌发生根本变化。</p></blockquote><p>P341</p><blockquote><p>盛世是中华民族的一个梦。生逢盛世，是每一个中国人对时代的最大期望。所谓盛世，就是内无严重的政治腐败，外无迫在眉睫的敌国外患，社会治安良好，老百姓普遍能吃饱饭的时代。在中国古代历史上，这样大规模的盛世出现过三次，即汉文景之治、唐代的贞观开元盛世及清康雍乾盛世。除了这三大盛世，还有过几个小规模的盛世或治世，比如东汉的“光武中兴”、隋代的“开皇之治”、明代的“仁宣之治”。甚至在大分裂的背景下，一些角落里的小王朝也取得过不错的治理成就。比如十六国时期南侵之前的前秦苻坚，南北朝的刘宋文帝时代，以及五代十国的后周南唐统治下的某个时段。</p></blockquote><p>P342</p><blockquote><p>有人统计过，数千年中国古代历史，盛世和治世累计加在一起，不过四百年左右，剩下的都是充斥着灾荒、动乱和腐败的平世和衰世。</p></blockquote><p>P346</p><blockquote><p>事实上，一代帝王的精明强干还不够。盛世的出现，都是几代人的接力努力达到的结果。中国盛世出现的规律是，一个英明强悍的开国帝王为新王朝立定规模，打下基础。开国帝王去世后，往往会出现一个小小的磨合动荡调整期，再由另一个精明强干的子孙打开王朝发展的瓶颈期，将王朝推上盛世。汉代刘邦开国，确立了清静无为的治国思路，但也留下了诸侯分裂的政治隐患。刘邦去世后，出现了吕后、惠帝时期的动荡。直到文帝、景帝，一方面将“与民休息”的治国方略发扬光大，另一方面又成功地打击了同姓王侯的分裂势力，消除了政治体制上的重大隐患，从而催生出武帝时代的极盛。唐代的盛世，经高祖、太宗开基立业，奠定基础，再有高宗、武后、中宗、睿宗的短期动荡调整，直到玄宗时才达到高峰。清代的盛世，也是由多尔衮和顺治打下基础。而康熙继位，解决了权臣和三藩这两个发展的瓶颈问题，由此大清才走上盛世之路。出现一个英明的帝王,在中国历史上本来就是小概率事件，而连续几代帝王都能雄才大略，那就更是如同彩票中奖一样难得，因此中国历史上盛世如此之少也就不难解释了。</p></blockquote><p>P346</p><blockquote><p>盛世难以出现，更难以保持。盛世的前奏是衰世，结局也是衰世。中国历史上的三大盛世，都未能避免“盛极而衰”的结局。</p></blockquote><p>P347</p><blockquote><p>从盛到衰，如此迅速，其原因当然是这些盛世的出现依赖的是人治。中国历史上的几大盛世，只在史书上留下了统治者手腕的精明，人格的强大，却没有留下太多制度性的成就。中国帝王都是人治的信奉者……中国古代的几千年间，专制制度的框架和运转规则没有根本的突破和进步。统治绩效如何，更多地依赖于统治者个人的精神振作与否。没有内外条件的严厉制约，个人的英明与自制无法抵制环境的纵容与腐蚀。由胜而骄，由劳而逸，是人性不变的规律。纵观中国历史，盛世君主往往是英明与昏聩集于一身，理智与膨胀合为一体。他们既是辉煌成绩的创造者，也是王朝衰落的罪魁祸首。</p></blockquote><p>P363</p><blockquote><p>乾隆皇帝治理天下的秘诀就是收紧缰绳，强化控制。在他眼里，任何民间的自发性和主动性都是危险的。整个社会的每一个分子，都要归拢到政权的罗网之内。大清王朝的千秋万代，固若金汤，是他考虑一切问题的根本出发点。虽然重新启用宁波等港口，会给浙江经济带来推动，但是却给帝国的管理增加了不必要的麻烦。</p></blockquote><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>《饥饿的盛世：乾隆时代的得与失》张宏杰著 358千字 重庆出版集团 2020年10月</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/the-heyday-of-hunger/cover.jpg&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;这本书参考了大量史料，帮我们从多个角度，还原“乾隆盛世”的真相，读时酣畅淋漓，读完回味无穷，值得推荐。&lt;/p&gt;
    
    </summary>
    
      <category term="书评" scheme="http://supercoder.xyz/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
      <category term="历史" scheme="http://supercoder.xyz/tags/%E5%8E%86%E5%8F%B2/"/>
    
      <category term="清朝" scheme="http://supercoder.xyz/tags/%E6%B8%85%E6%9C%9D/"/>
    
      <category term="乾隆" scheme="http://supercoder.xyz/tags/%E4%B9%BE%E9%9A%86/"/>
    
  </entry>
  
  <entry>
    <title>《草与禾》读书笔记</title>
    <link href="http://supercoder.xyz/2022/01/23/notes-on-reading-grass-and-rice/"/>
    <id>http://supercoder.xyz/2022/01/23/notes-on-reading-grass-and-rice/</id>
    <published>2022-01-23T02:53:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/notes-on-reading-grass-and-rice/cover.png" class="img-topic" /><p>“草”与“禾”分别指代什么？草原文明和华夏文明如何从“双峰对峙”，走向“胡汉难分”，再到“天下一家”？两种文明的冲突、融合，到底有哪些影响因素？作者波音在《草与禾》中，带我们从4000年前的史前文化时代开始，一路走过商周秦汉、三国两晋南北朝、唐宋元明清，也一路走过匈奴、鲜卑、柔然、突厥、回鹘、契丹、女真、蒙古，以多种视角，来观察华夏与草原的演进历史，展现各文明的融合过程，并试着为文明的冲突与融合给出合理的解释。</p><span id="more"></span><p>本书所讲的“草的世界”，主要是指长城以外的区域，以草原为主。“禾的世界”主要是指长城以内的区域，以农耕平原为主。地理环境的不同造就了不同的文明，草与禾，分别指代草原文明和华夏文明。在两大文明融合过程中，出现了几种政权模式：</p><ul><li>单一的华夏政权</li><li>单一的草原政权</li><li>以华夏为主体的混合政权模式</li><li>以草原为主体的混合政权模式</li></ul><p>刚开始，草原文明和华夏文明不热衷于侵占对方的土地，更倾向于划江而治，希望对方能够长治久安。随着文明融合的日益深入，某些政权阴差阳错的拥有了跨文明的疆域，从而变成了混合政权。</p><h2 id="原文摘录"><a href="#原文摘录" class="headerlink" title="原文摘录"></a>原文摘录</h2><p>P306</p><blockquote><p>统一天下的重任最终由草原背景的族群而非华夏背景的族群来完成，这是因为统一首先要以疆土的统一为基础，草原强大的军事力量是华夏王朝所不具备的、难以抵挡的。当然疆土的统一只是浅层次的统一，甚至在统一之前，经由漫长的混合政权模式的历练，草原背景的族群就已经对不同区域文明的政权组织、生产方式、文化传统有了充分的认知和融合尝试，这是元朝能够实现统一政权的历史背景。</p></blockquote><p>P307</p><blockquote><p>这个统一政权模式之前，中华文明的融合有着强烈的递进关系，从草原、华夏各自群星闪耀的远古文化，到整合为单一政权，再演进到混合政权，最后形成统一政权，即使偶有反复，但大趋势几乎可以认为是必然的结果。</p></blockquote><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>《草与禾：中华文明4000年融合史》波音著 中信出版集团 2019年06月</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/notes-on-reading-grass-and-rice/cover.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;“草”与“禾”分别指代什么？草原文明和华夏文明如何从“双峰对峙”，走向“胡汉难分”，再到“天下一家”？两种文明的冲突、融合，到底有哪些影响因素？作者波音在《草与禾》中，带我们从4000年前的史前文化时代开始，一路走过商周秦汉、三国两晋南北朝、唐宋元明清，也一路走过匈奴、鲜卑、柔然、突厥、回鹘、契丹、女真、蒙古，以多种视角，来观察华夏与草原的演进历史，展现各文明的融合过程，并试着为文明的冲突与融合给出合理的解释。&lt;/p&gt;
    
    </summary>
    
      <category term="书评" scheme="http://supercoder.xyz/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
      <category term="历史" scheme="http://supercoder.xyz/tags/%E5%8E%86%E5%8F%B2/"/>
    
      <category term="草原文明" scheme="http://supercoder.xyz/tags/%E8%8D%89%E5%8E%9F%E6%96%87%E6%98%8E/"/>
    
      <category term="华夏文明" scheme="http://supercoder.xyz/tags/%E5%8D%8E%E5%A4%8F%E6%96%87%E6%98%8E/"/>
    
      <category term="民族融合" scheme="http://supercoder.xyz/tags/%E6%B0%91%E6%97%8F%E8%9E%8D%E5%90%88/"/>
    
  </entry>
  
  <entry>
    <title>Windows下独立部署支持SNAPPY算法的HBase</title>
    <link href="http://supercoder.xyz/2021/09/25/deploy-hbase-on-windows/"/>
    <id>http://supercoder.xyz/2021/09/25/deploy-hbase-on-windows/</id>
    <published>2021-09-25T10:33:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<p>在HBase的实际应用中，往往需要压缩数据以便节省空间，其中snappy压缩算法的使用比较广泛，但很少有博客提到，如何在windows下，部署支持snappy压缩算法的HBase环境。本文介绍一种方法，在独立部署HBase后，不依赖完整的Hadoop环境、zookeeper环境，即可启动HBase，并支持snappy压缩算法。</p><span id="more"></span><h2 id="安装软件"><a href="#安装软件" class="headerlink" title="安装软件"></a>安装软件</h2><h3 id="安装Java"><a href="#安装Java" class="headerlink" title="安装Java"></a>安装Java</h3><p>安装Java相对比较简单，网上教程比较多，本文不再赘述。本文采用的JDK版本是1.8.181。</p><h3 id="安装Hadoop"><a href="#安装Hadoop" class="headerlink" title="安装Hadoop"></a>安装Hadoop</h3><p>HBase依赖Hadoop，由于是独立部署模式，因此不需要完整的Hadoop，从<a href="/file/hadoop-2.7.2-windows.zip">此处</a>下载适配windows的hadoop2.7.2软件包，解压到合适目录即可。</p><h3 id="安装HBase"><a href="#安装HBase" class="headerlink" title="安装HBase"></a>安装HBase</h3><p>从<a href="http://archive.apache.org/dist/hbase/">HBase官网</a>下载合适的版本，本文采用的版本是hbase-1.3.6。解压到合适的目录后，打开hbase-1.3.6/conf/hbase-site.xml，添加如下配置（注意，根据实际情况修改文件路径，路径不需要提前创建，程序会自动创建）</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- HBase数据保存路径，独立部署模式不依赖HDFS，指定本地目录即可，需要在路径前加file:/// --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>hbase.rootdir<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>file:///D:/bigdata/hbase-1.3.6/runtime/data<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- HBase临时文件保存路径，独立部署模式不依赖HDFS，指定本地目录即可 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span>&gt;</span>  </span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>hbase.tmp.dir<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>D:/bigdata/hbase-1.3.6/runtime/tmp<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- HBase自带zookeeper的文件保存路径，指定本地目录即可 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span>&gt;</span>  </span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>hbase.zookeeper.property.dataDir<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>D:/bigdata/hbase-1.3.6/runtime/zoo<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- HBase的UI界面，默认端口为60010，如果冲突，请重新选择一个 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>hbase.master.info.port<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>60010<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="添加环境变量"><a href="#添加环境变量" class="headerlink" title="添加环境变量"></a>添加环境变量</h2><p>依次添加<code>HADOOP_HOME</code>，<code>HBASE_HOME</code>，<code>JAVA_HOME</code>环境变量，效果如下：<br><img src="/img/deploy-hbase-on-windows/sys-env-params.png" alt="环境变量"></p><p>然后将<code>%HADOOP_HOME%\bin</code>，<code>%HBASE_HOME%\bin</code>，<code>%JAVA_HOME%\bin</code>添加到<code>PATH</code>环境变量中，效果如下：<br><img src="/img/deploy-hbase-on-windows/path-env-params.png" alt="PATH变量"></p><h2 id="启动HBase"><a href="#启动HBase" class="headerlink" title="启动HBase"></a>启动HBase</h2><p>进入hbase-1.3.6/bin目录，双击<code>start-hbase.cmd</code>，如果控制台无报错信息，打开浏览器，输入地址localhost:60010，看到如下界面，说明HBase启动正常。<br><img src="/img/deploy-hbase-on-windows/hbase-ui.png" alt="HBase UI"></p><h2 id="测试HBase"><a href="#测试HBase" class="headerlink" title="测试HBase"></a>测试HBase</h2><p>在任意路径下，启动cmd或者PowerShell，依次输入命令：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动hbase客户端</span></span><br><span class="line">hbase shell</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建表，表名<span class="built_in">test</span>，列族cf，采用snappy压缩</span></span><br><span class="line">create &#x27;test&#x27;, &#123;NAME =&gt; &#x27;cf&#x27;, COMPRESSION =&gt; &#x27;SNAPPY&#x27;&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看表<span class="built_in">test</span>的详细信息</span></span><br><span class="line">describe &#x27;test&#x27;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">向表中添加数据，行为row1，列族为cf，列为column1，值为123456789</span></span><br><span class="line">put &#x27;test&#x27;, &#x27;row1&#x27;, &#x27;cf:column1&#x27;, &#x27;123456789&#x27;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查询表中的所有内容</span></span><br><span class="line">scan &#x27;test&#x27;</span><br></pre></td></tr></table></figure><p>出现如下回显，说明HBase工作正常。<br><img src="/img/deploy-hbase-on-windows/hbase-shell.png" alt="HBase shell"></p><h2 id="清空HBase"><a href="#清空HBase" class="headerlink" title="清空HBase"></a>清空HBase</h2><p>HBase在运行过程中，会产生数据文件、zookeeper文件、日志文件等，如果需要恢复环境，只要将hbase-1.3.6/runtime目录（具体目录依配置而定）删除，重新启动HBase即可，非常方便。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在HBase的实际应用中，往往需要压缩数据以便节省空间，其中snappy压缩算法的使用比较广泛，但很少有博客提到，如何在windows下，部署支持snappy压缩算法的HBase环境。本文介绍一种方法，在独立部署HBase后，不依赖完整的Hadoop环境、zookeeper环境，即可启动HBase，并支持snappy压缩算法。&lt;/p&gt;
    
    </summary>
    
      <category term="技术" scheme="http://supercoder.xyz/categories/technology/"/>
    
    
      <category term="HBase" scheme="http://supercoder.xyz/tags/HBase/"/>
    
      <category term="SNAPPY" scheme="http://supercoder.xyz/tags/SNAPPY/"/>
    
      <category term="Windows" scheme="http://supercoder.xyz/tags/Windows/"/>
    
  </entry>
  
  <entry>
    <title>Java中各种同步机制的性能测试</title>
    <link href="http://supercoder.xyz/2020/02/29/locks-benchmark-of-java/"/>
    <id>http://supercoder.xyz/2020/02/29/locks-benchmark-of-java/</id>
    <published>2020-02-29T10:33:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/locks-benchmark-of-java/results_picture.png" class="img-topic" /><p>Java提供了多种同步机制，比如AtomicLong、LongAdder、ReentrantLock等，但是他们的性能到底如何？网上也有一些性能测试文章，但是要么同步机制不全，要么场景不全，因此笔者设计了一个性能测试框架，支持多场景、多种同步机制的性能测试，代码请参见<a href="https://github.com/chenpy228/locksbenchmark">locksbenchmark</a>，后续有时间了再通过JMH进行对比测试。</p><span id="more"></span><h2 id="测试原理"><a href="#测试原理" class="headerlink" title="测试原理"></a>测试原理</h2><p>既然是同步测试，当然要使用多线程才行，而且最好覆盖多种场景，总结起来本次测试有以下几个关键点：</p><ul><li>可以指定读、写线程数，来模拟读多写少、读少写多，读写等比等场景。</li><li>通过<code>CyclicBarrier</code>保证，所有线程开始工作那一刻才启动计时。通过<code>CountDownLatch</code>保证，只要有一个线程达成目标，就结束计时，保证计时尽量准确。</li><li>每种同步机制，经过多轮测试，结果去掉最小值、最大值然后取平均值，避免JVM未预热出现奇异值。</li><li>同步代码块中的代码非常简单，就是累加long型数值到一个目标值。如果需要测试新的同步机制，只需要扩展<code>Counter</code>类即可，具体实现可以参照类<a href="https://github.com/chenpy228/locksbenchmark/blob/c16a89903948e543340d7e956dc10d0b88245196/src/main/java/xyz/supercoder/locksbenchmark/Counter.java#L9">Raw</a>。</li></ul><h2 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h2><p>代码托管在github，使用maven工具构建，具体命令如下：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">git <span class="built_in">clone</span> git@github.com:chenpy228/locksbenchmark.git</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cd</span> locksbenchmark</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">mvn clean package</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">java -jar target/locksbenchmark-1.0.jar -h    <span class="comment"># add -h to show help info</span></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">java -jar target/locksbenchmark-1.0.jar       <span class="comment"># begin to test by using default parameter</span></span></span><br></pre></td></tr></table></figure><h2 id="测试结果"><a href="#测试结果" class="headerlink" title="测试结果"></a>测试结果</h2><p>测试环境是Ubuntu 14.04.5 LTS，内核版本是4.4.0-101-generic，CPU是2核，JVM信息如下：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">java -version</span></span><br><span class="line">java version &quot;1.8.0_151&quot;</span><br><span class="line">Java(TM) SE Runtime Environment (build 1.8.0_151-b12)</span><br><span class="line">Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)</span><br></pre></td></tr></table></figure><p>最终的测试结果如下，为了方便对比，Raw为没有使用任何同步机制的测试结果：<br><img src="/img/locks-benchmark-of-java/results_data.png" alt="results"></p><p>由于部分同步机制的运行时间相差太大，所以对坐标轴进行了对数化（log10）处理，绘制图表如下（越短越好）：<br><img src="/img/locks-benchmark-of-java/results_picture.png" alt="results"></p><p>去掉公平锁和读写锁后绘图如下（越短越好）：<br><img src="/img/locks-benchmark-of-java/results_without_fair_rwlock_picture.png" alt="results without fair and rw lock"></p><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul><li>公平锁<code>ReentrantLock(true)</code>，即上图中的FairReentrantLock，在所有场景下的表现都比较差，所以在实际应用中很少看到它的身影。如果必须要用，一定要经过谨慎测试。</li><li>读写锁<code>ReentrantReadWriteLock</code>，即上图中的RWLock，在读多写少的场景下表现的比较差，这跟我们的直觉可能不符，所以在java8中又引入了升级版的读写锁StampedLock。当然在写多读少的情况下，表现比较好，基本跟<code>StampedLock</code>持平。</li><li>在所有场景下，<code>AtomicLong</code>、<code>LongAdder</code>和非公平锁<code>ReentrantLock(false)</code>的表现相差不大，而且<code>AtomicLong</code>略有优势。按照文档的说法，只有竞争非常激烈的时候，<code>LongAdder</code>才更有优势，读写比20:20估计还不是竞争激烈的时候，针对这两个类补充测试了读写比为200:200场景，结果显示<code>LongAdder</code>更胜一筹。目前来看，用<code>AtomicLong</code>可以满足需求，而且个人认为<code>AtomicLong</code>的接口更丰富。</li><li>再来看看<code>StampedLock</code>，在读多写少的场景下，它的乐观锁（即上图中的OptimisticStampedLock）确实更胜一筹，其他场景下悲观锁略好一些。</li><li>最后看<code>synchronized</code>，整体跟<code>StampedLock</code>表现差不多。</li><li>基本上，<code>AtomicLong</code>和<code>LongAdder</code>属于第一梯队，<code>synchronized</code>、<code>StampedLock</code>和非公平锁<code>ReentrantLock(false)</code>属于第二梯队，<code>ReentrantReadWriteLock</code>和公平锁<code>ReentrantLock(true)</code>属于第三梯队。</li></ul><h2 id="建议"><a href="#建议" class="headerlink" title="建议"></a>建议</h2><p>如果被保护的是基本数据类型，在大多数场景下，建议使用<code>Atomic*</code>系列锁，如果竞争非常激烈可以使用<code>LongAdder</code>。如果被保护的是复杂的数据结构，在读多写少的场景下，可以用<code>StampedLock</code>的乐观锁，在读少写多的场景下，可以用<code>StampedLock</code>的悲观锁，其他场景直接用<code>ReentrantLock</code>的非公平锁即可。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://github.com/chenpy228/locksbenchmark">测试源码</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/locks-benchmark-of-java/results_picture.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;Java提供了多种同步机制，比如AtomicLong、LongAdder、ReentrantLock等，但是他们的性能到底如何？网上也有一些性能测试文章，但是要么同步机制不全，要么场景不全，因此笔者设计了一个性能测试框架，支持多场景、多种同步机制的性能测试，代码请参见&lt;a href=&quot;https://github.com/chenpy228/locksbenchmark&quot;&gt;locksbenchmark&lt;/a&gt;，后续有时间了再通过JMH进行对比测试。&lt;/p&gt;
    
    </summary>
    
      <category term="技术" scheme="http://supercoder.xyz/categories/technology/"/>
    
    
      <category term="多线程" scheme="http://supercoder.xyz/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
    
      <category term="性能" scheme="http://supercoder.xyz/tags/%E6%80%A7%E8%83%BD/"/>
    
      <category term="Java" scheme="http://supercoder.xyz/tags/Java/"/>
    
      <category term="同步" scheme="http://supercoder.xyz/tags/%E5%90%8C%E6%AD%A5/"/>
    
  </entry>
  
  <entry>
    <title>每天学习一小时，轻松超过80%的人</title>
    <link href="http://supercoder.xyz/2020/01/01/look-ahead-2020/"/>
    <id>http://supercoder.xyz/2020/01/01/look-ahead-2020/</id>
    <published>2020-01-01T02:36:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/look-ahead-2020/basic.png" class="img-topic" /><p>哈哈，有点儿标题党。昨天“极客时间”APP给我推送了一份专属的学习报告，看到一个数据很有意思：我全年在这个APP上只学习了39天，但却超过了80%的人。再次证明，以现在大家的努力程度，还真没有到拼智商的时候。2020已经到来，希望自己每天能够坚持学习，不求超越别人，但求每天能看到不一样的自己。</p><span id="more"></span><h2 id="我的学习报告"><a href="#我的学习报告" class="headerlink" title="我的学习报告"></a>我的学习报告</h2><p>我的学习报告详情如下，很惭愧，订阅了4个专栏，基本都只学习了一半，今年要先把这4个专栏学完，再订阅其他的。<br><img src="/img/look-ahead-2020/study_info.png" alt="我的极客时间学习报告"></p><h2 id="战胜惰性，保持自律"><a href="#战胜惰性，保持自律" class="headerlink" title="战胜惰性，保持自律"></a>战胜惰性，保持自律</h2><p>左耳朵耗子（陈皓）在2019-12-13发了一条微博，值得深思。</p><blockquote><p>跟极客时间的运营看了一下后台数据，发现我的专栏第50篇后，就剩下30%的人还在持续学习，能坚持到最后人还不到千分之一。</p></blockquote><p>我也发现，一般专栏刚开始几篇文章的阅读量、评论数都非常多，越往后越少，能坚持到最后的，寥寥无几。所以，人的惰性很难战胜，如果能保持自律，始终坚持做一件事的人，我想过的一定不会太差。共勉！</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://m.weibo.cn/detail/4449102098449946">左耳朵耗子微博</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/look-ahead-2020/basic.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;哈哈，有点儿标题党。昨天“极客时间”APP给我推送了一份专属的学习报告，看到一个数据很有意思：我全年在这个APP上只学习了39天，但却超过了80%的人。再次证明，以现在大家的努力程度，还真没有到拼智商的时候。2020已经到来，希望自己每天能够坚持学习，不求超越别人，但求每天能看到不一样的自己。&lt;/p&gt;
    
    </summary>
    
      <category term="日记" scheme="http://supercoder.xyz/categories/diary/"/>
    
    
      <category term="学习" scheme="http://supercoder.xyz/tags/%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>期待微软的新一代Edge浏览器</title>
    <link href="http://supercoder.xyz/2019/11/04/looking-forward-to-ms-edge/"/>
    <id>http://supercoder.xyz/2019/11/04/looking-forward-to-ms-edge/</id>
    <published>2019-11-04T13:36:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/looking-forward-to-ms-edge/edge-logo.png" class="img-topic" /><p>昨天，微软为基于Chromium内核的Edge浏览器发布了新的logo，新logo很漂亮，变化也很大，可能表明了微软要重新收复失地的决心吧。本文主要介绍一点儿微软浏览器的变迁史，由于个人认知有限，只能称为简史。</p><span id="more"></span><h2 id="微软浏览器logo的变迁简史"><a href="#微软浏览器logo的变迁简史" class="headerlink" title="微软浏览器logo的变迁简史"></a>微软浏览器logo的变迁简史</h2><h3 id="IE"><a href="#IE" class="headerlink" title="IE"></a>IE</h3><p>IE可能是微软家族在市面上使用最多、吐槽最厉害的老牌浏览器。很多老的系统，尤其是办公系统，只能使用IE。程序员朋友一提起IE，简直就是噩梦。随着win10的推广，IE后面会逐渐收缩，最终会被Edge替代。下面是IE的logo，虽说这些年每个版本都有变化，但是整体样式没有改变过。嗯，熟悉的味道。<br><img src="/img/looking-forward-to-ms-edge/ie-logo.jpg" alt="ie logo"></p><h3 id="Edge"><a href="#Edge" class="headerlink" title="Edge"></a>Edge</h3><p>自从2015年Windows10系统推出后，系统自带的就是Edge浏览器。Edge是IE的升级版，从使用体验上，更接近“现代”浏览器。logo变化不大，整体上还是字母e，就是去掉了外面的环。个人感觉，这个logo最丑，去掉“环”后，感觉还不如IE，没准是看IE时间长的原因吧。微软想用这款浏览器替代IE，但目前感觉收效甚微。<br><img src="/img/looking-forward-to-ms-edge/old-edge-logo.png" alt="Edge logo"></p><h3 id="Edge-Chromium"><a href="#Edge-Chromium" class="headerlink" title="Edge(Chromium)"></a>Edge(Chromium)</h3><p>新logo外形仍然是字母e，但与IE、旧版的Edge差异较大。新logo变得更加圆润且富有现代感，它的形态看上去像是波浪，更有“网上冲浪”的感觉。该logo与以往的相差很大，笔者猜想，微软想让用户彻底忘记过去，重新收复浏览器失地。<br>目前还尚不清楚，微软何时推出新款的Edge浏览器，但是鉴于全新logo已推出，估计时间不会太远，咱们拭目以待，笔者也会第一时间测评，希望这次不会让人失望。<br><img src="/img/looking-forward-to-ms-edge/edge-logo.png" alt="Edge(Chromium) logo"></p><h2 id="微软最近的新动作"><a href="#微软最近的新动作" class="headerlink" title="微软最近的新动作"></a>微软最近的新动作</h2><p>自从纳德拉接管微软以后，这只巨兽一改以往老态龙钟的形象。微软家族的产品也越来越受欢迎，比如vs code，笔者此时正在用它撰写该博客的markdown文稿。有意思的是，vs code的logo最近也发生了变化，logo更具设计感，也符合微软最新的设计风格。<br><img src="/img/looking-forward-to-ms-edge/vscode-logo.jpg" alt="vs code logo"></p><p>似乎远离我们的微软又回来了。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>文中图片均来自网络，如有侵权，请及时知会，带来不便，请谅解</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/looking-forward-to-ms-edge/edge-logo.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;昨天，微软为基于Chromium内核的Edge浏览器发布了新的logo，新logo很漂亮，变化也很大，可能表明了微软要重新收复失地的决心吧。本文主要介绍一点儿微软浏览器的变迁史，由于个人认知有限，只能称为简史。&lt;/p&gt;
    
    </summary>
    
      <category term="工具" scheme="http://supercoder.xyz/categories/tool/"/>
    
    
      <category term="Edge" scheme="http://supercoder.xyz/tags/Edge/"/>
    
  </entry>
  
  <entry>
    <title>git与区块链</title>
    <link href="http://supercoder.xyz/2019/10/27/git-and-blockchain/"/>
    <id>http://supercoder.xyz/2019/10/27/git-and-blockchain/</id>
    <published>2019-10-27T11:18:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/git-and-blockchain/blockchain.jpg" class="img-topic" /><p>最近这几天，沉寂已久的区块链突然火了起来，各种文章铺天盖地，起因是，10月24号习大大把区块链技术提升到国家高度，希望借此技术能够实现弯道超车。说起区块链，不得不提比特币，前几年比特币大火，也带火了区块链技术，笔者还曾长时间跟进一个区块链创新项目storj。当时也简单了解过背后的原理，其实，对于现在的码农来说，区块链技术并不神秘，我们每天在用的git就跟它比较相似。本文就来简单对比下这两种技术的异同。</p><span id="more"></span><h2 id="相似点"><a href="#相似点" class="headerlink" title="相似点"></a>相似点</h2><h3 id="可追溯"><a href="#可追溯" class="headerlink" title="可追溯"></a>可追溯</h3><ul><li>区块链，顾名思义，是由区块组成的链式结构，每个区块都包含前一个区块的索引（除了第一块，即创世区块），所以从任一块出发，可以到追溯之前所有的交易。</li><li>git在每次提交代码时，会将本次修改内容打成一个快照（可以理解为区块），并跟上一次提交进行关联（除了第一次commit），这样也可以从任意提交记录出发，追溯之前的提交。</li></ul><h3 id="分布式存储"><a href="#分布式存储" class="headerlink" title="分布式存储"></a>分布式存储</h3><ul><li>区块链，每一个节点都记录了完整的数据。</li><li>通过git clone后，本地不仅会保存完整的代码，还保存了每次提交的详细信息，可以追溯到每行代码的提交人。</li></ul><h3 id="支持离线访问"><a href="#支持离线访问" class="headerlink" title="支持离线访问"></a>支持离线访问</h3><p>既然本地保存了完整的数据，当然可以离线访问。</p><h3 id="不可篡改"><a href="#不可篡改" class="headerlink" title="不可篡改"></a>不可篡改</h3><p>无论是区块链还是git，每个块的唯一标示都是根据块内容算出来的，并且保存了上一个块的信息，如果修改，标示信息会不一致（当然这里可能会有hash碰撞，但是概率极低），所以是无法修改的。</p><h2 id="差异点"><a href="#差异点" class="headerlink" title="差异点"></a>差异点</h2><h3 id="合并方式"><a href="#合并方式" class="headerlink" title="合并方式"></a>合并方式</h3><ul><li>区块链是基于集体共识（POW/POS)来合入一个区块，形成最长链，最长链即为主链。</li><li>git一般是由项目的管理者合入一个提交，管理者可能是一个人，或者几个人的小团队，但是权利掌握在少数人手里。</li></ul><h3 id="一致性"><a href="#一致性" class="headerlink" title="一致性"></a>一致性</h3><ul><li>区块链要求强一致性，冲突时根据链的长度决定，自动废弃多余分支</li><li>git不追求强一致性，人工解决冲突</li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>git和区块链在很多方面都很像，不知道谁借鉴的谁，不过从时间上看，git发起于2005年，区块链（比特币）发起于2008年，可能区块链借鉴了git的一些思想。但也不好说，可能世界就是这样奇妙，就像微积分的出现，当年莱布尼兹和牛顿几乎同时发明了这一伟大的工具，可能这就是英雄所见略同。</p><p>鉴于笔者对区块链了解不深，如有纰漏，还望批评指正。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://baike.baidu.com/item/%E5%8C%BA%E5%9D%97%E9%93%BE/13465666?fr=aladdin">区块链-百度百科</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/git-and-blockchain/blockchain.jpg&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;最近这几天，沉寂已久的区块链突然火了起来，各种文章铺天盖地，起因是，10月24号习大大把区块链技术提升到国家高度，希望借此技术能够实现弯道超车。说起区块链，不得不提比特币，前几年比特币大火，也带火了区块链技术，笔者还曾长时间跟进一个区块链创新项目storj。当时也简单了解过背后的原理，其实，对于现在的码农来说，区块链技术并不神秘，我们每天在用的git就跟它比较相似。本文就来简单对比下这两种技术的异同。&lt;/p&gt;
    
    </summary>
    
      <category term="技术" scheme="http://supercoder.xyz/categories/technology/"/>
    
    
      <category term="git" scheme="http://supercoder.xyz/tags/git/"/>
    
      <category term="区块链" scheme="http://supercoder.xyz/tags/%E5%8C%BA%E5%9D%97%E9%93%BE/"/>
    
  </entry>
  
  <entry>
    <title>手写KNN分类算法</title>
    <link href="http://supercoder.xyz/2019/09/15/knn-from-scratch/"/>
    <id>http://supercoder.xyz/2019/09/15/knn-from-scratch/</id>
    <published>2019-09-15T03:04:54.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/knn-from-scratch/knn.png" class="img-topic" /><p>近朱者赤，近墨者黑，看一个人经常跟什么人来往，就可以大致推算出这个人的水平。在机器学习领域，有一个采用类似思想实现的算法，那便是KNN(K-Nearest Neighbor)，即K近邻算法，其中K是关键参数。该算法比较简单，本文简单介绍如何从零开始实现这个算法，以便加深对算法的理解。</p><span id="more"></span><h2 id="KNN算法简介"><a href="#KNN算法简介" class="headerlink" title="KNN算法简介"></a>KNN算法简介</h2><p>KNN算法的主要实现步骤如下：</p><ul><li>算距离：对于给定的一条测试数据，计算它与训练集中每个样本的距离（一般采用欧式距离）</li><li>找邻居：找到距离这条测试数据最近的K个训练样本</li><li>做决策：根据这K个训练样本的标签，投票决定测试数据的预测值。对于分类问题，一般取出现次数多的标签，即少数服从多数；对于回归问题，一般取这K个标签的平均值</li></ul><h3 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h3><ul><li>简单，易实现</li><li>只有一个超参数K，参数调优方便快捷</li><li>特别适合多分类问题</li></ul><h3 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h3><ul><li>惰性算法，在预测时，需要遍历所有的训练样本，内存开销大，性能差</li><li>可解释性差，无法给出明确的预测规则</li></ul><h3 id="经验"><a href="#经验" class="headerlink" title="经验"></a>经验</h3><ul><li>K选择：一般来说K值越大，决策边界越平滑，模型越稳定，但是不代表K越大越好。一般采用交叉验证来确定K值。K的取值范围是[1, 训练样本数的平方根]，并且最好是奇数</li><li>距离选择：对于文本来说，夹角余弦比欧式距离更合适，其他场景还是用欧式距离</li><li>特征工程：涉及到距离计算的算法，在特征工程阶段，最好进行标准化或者归一化</li></ul><h3 id="应用"><a href="#应用" class="headerlink" title="应用"></a>应用</h3><ul><li>客户流失预测</li><li>欺诈侦测</li><li>推荐</li></ul><h2 id="KNN算法实现"><a href="#KNN算法实现" class="headerlink" title="KNN算法实现"></a>KNN算法实现</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">from</span> collections <span class="keyword">import</span> Counter</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> sklearn <span class="keyword">import</span> datasets</span><br><span class="line"><span class="keyword">from</span> sklearn.model_selection <span class="keyword">import</span> train_test_split</span><br><span class="line"><span class="keyword">from</span> sklearn.metrics <span class="keyword">import</span> accuracy_score</span><br><span class="line"><span class="keyword">from</span> sklearn.neighbors <span class="keyword">import</span> KNeighborsClassifier  </span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">KNNClassifier</span>(<span class="title class_ inherited__">object</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, k=<span class="number">3</span></span>):</span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        构造方法，只有一个参数k，最小值为1，默认为3。最好是奇数。</span></span><br><span class="line"><span class="string">        k: 邻居数，int型</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line">        <span class="keyword">assert</span> k &gt;= <span class="number">1</span>, <span class="string">&quot;k must be integer and larger than 0&quot;</span></span><br><span class="line">        </span><br><span class="line">        self.k = k</span><br><span class="line">        self.X = <span class="literal">None</span></span><br><span class="line">        self.y = <span class="literal">None</span></span><br><span class="line"> </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">fit</span>(<span class="params">self, X, y</span>):</span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        训练，KNN无训练过程，因此只做赋值。同时要求以下两点：</span></span><br><span class="line"><span class="string">        1、X和y的维度要一致</span></span><br><span class="line"><span class="string">        2、k要小于X的训练样本个数，否则没有意义</span></span><br><span class="line"><span class="string">        </span></span><br><span class="line"><span class="string">        X: 训练样本，array型</span></span><br><span class="line"><span class="string">        y: 训练标签，array型</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line">        <span class="keyword">assert</span> X.shape[<span class="number">0</span>] == y.shape[<span class="number">0</span>], <span class="string">&quot;the shape of X and y must be match&quot;</span></span><br><span class="line">        <span class="keyword">assert</span> self.k &lt;= X.shape[<span class="number">0</span>], <span class="string">&quot;k must be smaller than shape of X&quot;</span></span><br><span class="line">        </span><br><span class="line">        self.X = X</span><br><span class="line">        self.y = y</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">_calc_euclidean_distance</span>(<span class="params">self, array1, array2</span>):</span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        计算两个样本array1和array2之间的欧式距离</span></span><br><span class="line"><span class="string">        array1: 第一个样本，array型</span></span><br><span class="line"><span class="string">        array2: 第二个样本，array型</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line">        <span class="keyword">return</span> np.linalg.norm(array1 - array2)</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">_vote</span>(<span class="params">self, topk_y</span>):</span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        根据选出的k个标签，进行投票，少数服从多数</span></span><br><span class="line"><span class="string">        topk_y: 选出的k个标签值，array型</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line">        <span class="keyword">return</span> Counter(topk_y).most_common()[<span class="number">0</span>][<span class="number">0</span>]</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">predict</span>(<span class="params">self, x</span>):</span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        预测，遍历测试样本，对于每个样本，分别与所有训练样本计算距离，然后选出距离最近的k个标签，进行决策</span></span><br><span class="line"><span class="string">        x: 测试样本，维度要与训练样本X保持一致，array型</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line">        <span class="keyword">assert</span> self.X <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span> <span class="keyword">and</span> self.y <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span> , <span class="string">&quot;must training before predict&quot;</span></span><br><span class="line">        <span class="keyword">assert</span> x.shape[<span class="number">1</span>] == self.X.shape[<span class="number">1</span>]</span><br><span class="line">        </span><br><span class="line">        y_pred = []</span><br><span class="line">        <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(x)):</span><br><span class="line">            distances = [self._calc_euclidean_distance(x[i], self.X[j]) <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(self.X))]</span><br><span class="line">            nearest_index = np.argsort(distances)</span><br><span class="line">            topk_index = nearest_index[:self.k]</span><br><span class="line">            y_pred.append(self._vote(self.y[topk_index]))</span><br><span class="line">        <span class="keyword">return</span> np.array(y_pred)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">##############  以上是算法实现过程，下面对算法进行测试，以及与sklearn自带的KNN进行对比    ###############</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 导入iris数据</span></span><br><span class="line">iris = datasets.load_iris()</span><br><span class="line">X = iris.data</span><br><span class="line">y = iris.target</span><br><span class="line">X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=<span class="number">888</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用我的算法进行预测，并给出准确率</span></span><br><span class="line">knn_me = KNNClassifier(<span class="number">3</span>)</span><br><span class="line">knn_me.fit(X_train, y_train)</span><br><span class="line">y_predict_me = knn_me.predict(X_test)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;The accuracy of my knn is &#123;&#125;.&quot;</span>.<span class="built_in">format</span>(accuracy_score(y_test, y_predict_me)))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用sklearn的算法进行预测，并给出准确率</span></span><br><span class="line">knn_std = KNeighborsClassifier(n_neighbors=<span class="number">3</span>)</span><br><span class="line">knn_std.fit(X_train, y_train)</span><br><span class="line">y_predict_std = knn_std.predict(X_test)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;The accuracy of sklearn knn is &#123;&#125;.&quot;</span>.<span class="built_in">format</span>(accuracy_score(y_test, y_predict_std)))</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>执行上面代码，输出如下，可以看出，精度是一致的。当然，我的算法没有考虑各种异常，以及大数量下的性能优化，切不可应用在生产环境下。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">The accuracy of my knn is 0.9473684210526315.</span><br><span class="line">The accuracy of sklearn knn is 0.9473684210526315.</span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://blog.csdn.net/jmydream/article/details/8644004">KNN算法理解</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/knn-from-scratch/knn.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;近朱者赤，近墨者黑，看一个人经常跟什么人来往，就可以大致推算出这个人的水平。在机器学习领域，有一个采用类似思想实现的算法，那便是KNN(K-Nearest Neighbor)，即K近邻算法，其中K是关键参数。该算法比较简单，本文简单介绍如何从零开始实现这个算法，以便加深对算法的理解。&lt;/p&gt;
    
    </summary>
    
      <category term="技术" scheme="http://supercoder.xyz/categories/technology/"/>
    
    
      <category term="Python" scheme="http://supercoder.xyz/tags/Python/"/>
    
      <category term="机器学习" scheme="http://supercoder.xyz/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>《刷新》读书笔记</title>
    <link href="http://supercoder.xyz/2019/08/25/hit-refresh/"/>
    <id>http://supercoder.xyz/2019/08/25/hit-refresh/</id>
    <published>2019-08-25T02:52:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/hit-refresh/cover.jpg" class="img-topic" /><p>曾经一度以为，微软会像摩托罗拉、柯达一样，日薄西山，没想到在第三任CEO纳德拉的带领下竟然获得重生，他做了什么，促使这头大象翩翩起舞？带着这个问题，最近几天阅读了他的第一部著作《刷新》（英文名《Hit Refresh》）。</p><span id="more"></span><p>《刷新》主要分两个部分，第一部分主要讲述微软变革始末，第二部分讲述科技公司面临的挑战。个人觉得第一部分更精彩，让我们看到一家巨头公司是如何转型的。第二部分更多的是开放思考。</p><h2 id="微软转型"><a href="#微软转型" class="headerlink" title="微软转型"></a>微软转型</h2><p>曾经的微软是多么的封闭，多么的不可一世，可近几年我们看到，微软Office软件可以在iPhone、Mac上运行、Windows系统集成Linux内核、计算器程序开源、VScode开源、收购最大的开源仓库GitHub、甚至在发布会上掏出iPhone等等，这些动作表明，微软正以积极开放的心态拥抱世界，这在以前是不可想象的。是什么促成了这种转变？</p><p>纳德拉在接任CEO时，微软已然患上了大公司病，正如他在书中所写：</p><blockquote><p>他们怀着伟大梦想来到微软，但感觉真正面对的却是处理与高级管理层的关系，执行繁杂冗余的程序，以及会议中无休止的争吵。</p></blockquote><p>这让我想起了网上曾经一度流传比较久的各大公司的组织结构图，拿着枪指着对方的正是微软，<img src="/img/hit-refresh/pic.jpg" alt="组织结构图"><br>他意识到，是文化出了问题，需要从内到外推动文化变革，才有可能重生，</p><blockquote><p>领导意味着做选择，然后将团队团结在这些选择周围。我的父亲是一名印度高级政府官员，我从他那里学到的一点是，<strong>这个世界上没有比打造一个永续的组织更加艰难的任务</strong>。对领导者而言，通过命令达成的共识并不是真正的共识。任何机构建设都源于清晰的、既能自上而下也能自下而上推动进步的愿景和文化。</p></blockquote><blockquote><p>没有任何一名领导者、任何一个团队或任何一名首席执行官能够成为微软复兴的英雄。微软要实现复兴，靠的是我们所有人以及我们所有人的努力。文化转型是缓慢而艰难的，但也是值得的。</p></blockquote><p>而管理者又是变革过程中的关键一环，</p><blockquote><p>一个无可辩驳的事实是，在任何一家大型组织，任何艰难的转型都必须从内部突破。</p></blockquote><blockquote><p>关键在于，高层管理者不能带给员工恐惧和恐慌，而是帮助员工解决现有问题，并从中吸取教训。</p></blockquote><blockquote><p>我们需要的是一个能够接纳彼此问题、促进对话和高效率的高级管理团队；我们需要每一个人都将高级管理团队视为他们的最重要的团队，而不仅仅是当做他们参加的另一场会议；我们还需要在使命、战略和文化上保持一致。</p></blockquote><blockquote><p>我觉得领导者首先要做的事情就是：<strong>激发所带团队中成员的信心</strong>。</p></blockquote><p>如何推进文化变革？纳德拉认为是<strong>重塑同理心和建立成长型思维</strong>。</p><h3 id="重塑同理心"><a href="#重塑同理心" class="headerlink" title="重塑同理心"></a>重塑同理心</h3><p>大部分公司都把“以客户为中心”当做自己的核心价值观，可是真正做到的公司究竟有多少？如何才能以客户为中心，我想至少应该站在客户立场上思考问题，其实这就是同理心。纳德拉的儿子身患疾病，这一度让他很难过，不过正像他说的，这对他建立同理心帮助巨大，</p><blockquote><p>我认识到，只有经历过人生起伏，才能培养其同理心；要想不受苦难，或者少受苦难，就必须接纳无常。…。如果你能够深刻地体会无常，那么你会获得更多的宁静，你不会因为人生中的起起落落而反应过于激烈。而只有到那时，你才能对周围的事物产生深远的同理心和慈悲心。</p></blockquote><h3 id="建立成长型思维"><a href="#建立成长型思维" class="headerlink" title="建立成长型思维"></a>建立成长型思维</h3><p>纳德拉引用了卡罗尔·德维克的畅销书《终身成长：重新定义成功的思维模式》中的两种思维模式：成长型思维和固定型思维。他指出建立成长型思维的重要性，</p><blockquote><p>每一个人、每一个组织乃至每一个社会，在到达某一个点时，都应点击刷新——重新注入活力、重新激发生命力、重新组织并重新思考自己存在的意义。</p></blockquote><blockquote><p>我讲的并不是净利润的增长，而是我们个人的成长。<strong>如果我们每个人都能在工作和生活中成长，那么我们作为一家公司也会成长</strong>。</p></blockquote><blockquote><p>微软的变革并不依赖于我个人，甚至也不依赖于和我最密切共事的那几位高层领导者。它依赖于公司中的每一个人，包括我们广大的中层经理，他们必须致力于让每一个人每一天都能取得进步。</p></blockquote><p>曾经的天朝上国，固步自封，国人自认为知晓一切，错过了大航海、工业革命。假使郑和下西洋，不是为了炫耀国威，而是探索地球的奥秘，中国现在不至于处于发展中的状态。</p><p>时刻保持同理心，站在客户视角思考问题，同时不断“刷新”自己的认知，这样的公司想不成功都难。</p><h2 id="科技面临的挑战"><a href="#科技面临的挑战" class="headerlink" title="科技面临的挑战"></a>科技面临的挑战</h2><p>数字世界会面临一些列挑战，其中信任是最为核心的，</p><blockquote><p>言论自由、隐私、安全和主权是永恒的、不容质疑的价值观。</p></blockquote><blockquote><p>信任就像手里握着一只小鸟。握的太紧，会伤到小鸟；握的太松，小鸟就飞走了。</p></blockquote><blockquote><p>区分现代人类和穴居人的是信任</p></blockquote><p>这个担心不无道理，作为IT人，我就有这方面的顾虑。在采用某项云服务时，比如说<code>为知笔记</code>，我首先考虑的不是价格，而是我的信息是如何存储的，是否有人能查看我的数据，比如心存恶意的管理员是否能不经过授权就随意窃取数据等等。随着斯诺登事件的发酵，给云厂商建立信任带来极高的成本，但这件事也是刻不容缓的，因为时至今日，部分国内厂商宁可自建机房，也不愿意将服务、数据放到云上，尽管云会带来更多的好处。</p><p>纳德拉在各国政府访问期间，经常被问到<code>如何利用最新的科技浪潮来增加就业机会和经济机会？</code>，他的答案是，</p><blockquote><p>教育加创新，广泛应用于整个经济，尤其是那些具备比较优势的国家或地区，再乘以科技使用强度，久而久之，就会产生经济增长和生产力。</p></blockquote><p>同时也有人会问，人工智能会导致更多的下岗，他的思考是，</p><blockquote><p>我相信，解决经济冲击的唯一办法，就是确保我们不仅要为走出大学和其他高等教育项目的人提供技能培训，还要为那些正在因为自动化失去工作的人提供培训。</p></blockquote><p>其实，只有拒绝学习的人才有这个担心，比如前段时间收费站被裁撤后，被迫下岗的37岁大姐。人工智能替代了部分岗位，会迫使人类从事其他更有价值的工作。比如，火车替代了马车，虽然马车夫下岗了，但围绕火车会创造更多的岗位，只要肯终身学习，定会找到符合自身价值的岗位，政府需要做的就是及时引导、培训。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>《刷新：重新发现商业与未来》萨提亚·纳德拉著 中信出版集团 2018年02月</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/hit-refresh/cover.jpg&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;曾经一度以为，微软会像摩托罗拉、柯达一样，日薄西山，没想到在第三任CEO纳德拉的带领下竟然获得重生，他做了什么，促使这头大象翩翩起舞？带着这个问题，最近几天阅读了他的第一部著作《刷新》（英文名《Hit Refresh》）。&lt;/p&gt;
    
    </summary>
    
      <category term="书评" scheme="http://supercoder.xyz/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
      <category term="商业" scheme="http://supercoder.xyz/tags/%E5%95%86%E4%B8%9A/"/>
    
      <category term="同理心" scheme="http://supercoder.xyz/tags/%E5%90%8C%E7%90%86%E5%BF%83/"/>
    
      <category term="成长型思维" scheme="http://supercoder.xyz/tags/%E6%88%90%E9%95%BF%E5%9E%8B%E6%80%9D%E7%BB%B4/"/>
    
  </entry>
  
  <entry>
    <title>如何合并多个etcd集群的数据</title>
    <link href="http://supercoder.xyz/2019/06/08/how-to-merge-multi-etcd-clusters-data/"/>
    <id>http://supercoder.xyz/2019/06/08/how-to-merge-multi-etcd-clusters-data/</id>
    <published>2019-06-08T12:46:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/how-to-merge-multi-etcd-clusters-data/etcd-logo.svg" class="img-topic" /><p>如果多个etcd集群的键值不重复，能否将数据合并？能否像数据库一样，将数据从旧库导出，然后在新库插入就万事大吉呢？答案是不能，etcd并没有提供类似功能，倒是有个备份功能，但是多个集群的备份数据却无法直接合并到一起。难道只能写个循环，将老集群的数据遍历出来，然后再插入新集群吗？这样也太土了吧，于是开始在网上找各种资料，可总是无功而返，看来只能老老实实看etcd官方资料了。功夫不负有心人，终于找到一条类似命令make-mirror，这条命令可以实时将一个集群的数据备份到其他集群，感觉跟我上面的想法一致，那么它可以用来做数据合并吗？请看接下来的实验吧！</p><span id="more"></span><h2 id="make-mirror简介"><a href="#make-mirror简介" class="headerlink" title="make-mirror简介"></a>make-mirror简介</h2><p>命令语法如下，详情见<a href="https://www.mankier.com/1/etcdctl3-make-mirror">命令手册</a>。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ETCDCTL_API=3 etcdctl make-mirror [options] &lt;destination&gt; [flags]</span><br></pre></td></tr></table></figure><p>其中<code>[options]</code>主要是配置源集群和目的集群证书信息，以及源集群的客户端地址等。<code>&lt;destination&gt;</code>是目的集群的客户端地址。该命令是单向的，目的集群的变化不会影响源集群。</p><h2 id="准备测试环境"><a href="#准备测试环境" class="headerlink" title="准备测试环境"></a>准备测试环境</h2><p>在windows本地搭建3套etcd集群，名字分别是cluster1、cluster2、cluster3，这里假设将cluster1和cluster2的数据合并到cluster3，为了实验方便，只开放http访问。</p><p>启动集群1，并写入测试键/cluster1。为了避免混淆，在官方推荐的2379/2380端口前面加上数字代表不同的集群，例如对于集群1来说，客户端访问端口是<strong>1</strong>2379，集群通信端口是<strong>1</strong>2380。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">nohup</span> etcd -name cluster1                    \</span></span><br><span class="line"><span class="language-bash">--data-dir /tmp/cluster1/data/                 \</span></span><br><span class="line"><span class="language-bash">--listen-client-urls http://localhost:12379    \</span></span><br><span class="line"><span class="language-bash">--advertise-client-urls http://localhost:12379 \</span></span><br><span class="line"><span class="language-bash">--listen-peer-urls http://localhost:12380      \</span></span><br><span class="line"><span class="language-bash">--initial-cluster-state new &amp;</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 etcdctl --endpoints=http://localhost:12379 put /cluster1 <span class="string">&quot;this is cluster1&quot;</span></span></span><br><span class="line">OK</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 etcdctl --endpoints=http://localhost:12379 get --prefix /</span></span><br><span class="line">/cluster1</span><br><span class="line">this is cluster1</span><br></pre></td></tr></table></figure><p>启动集群2，并写入测试键/cluster2。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">nohup</span> etcd -name cluster2                    \</span></span><br><span class="line"><span class="language-bash">--data-dir /tmp/cluster2/data/                 \</span></span><br><span class="line"><span class="language-bash">--listen-client-urls http://localhost:22379    \</span></span><br><span class="line"><span class="language-bash">--advertise-client-urls http://localhost:22379 \</span></span><br><span class="line"><span class="language-bash">--listen-peer-urls http://localhost:22380      \</span></span><br><span class="line"><span class="language-bash">--initial-cluster-state new &amp;</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 etcdctl --endpoints=http://localhost:22379 put /cluster2 <span class="string">&quot;this is cluster2&quot;</span></span></span><br><span class="line">OK</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 etcdctl --endpoints=http://localhost:22379 get --prefix /</span></span><br><span class="line">/cluster2</span><br><span class="line">this is cluster2</span><br></pre></td></tr></table></figure><p>启动集群3，并写入测试键/cluster3。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">nohup</span> etcd -name cluster3                    \</span></span><br><span class="line"><span class="language-bash">--data-dir /tmp/cluster3/data/                 \</span></span><br><span class="line"><span class="language-bash">--listen-client-urls http://localhost:32379    \</span></span><br><span class="line"><span class="language-bash">--advertise-client-urls http://localhost:32379 \</span></span><br><span class="line"><span class="language-bash">--listen-peer-urls http://localhost:32380      \</span></span><br><span class="line"><span class="language-bash">--initial-cluster-state new &amp;</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 etcdctl --endpoints=http://localhost:32379 put /cluster3 <span class="string">&quot;this is cluster3&quot;</span></span></span><br><span class="line">OK</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 etcdctl --endpoints=http://localhost:32379 get --prefix /</span></span><br><span class="line">/cluster3</span><br><span class="line">this is cluster3</span><br></pre></td></tr></table></figure><h2 id="启动数据同步"><a href="#启动数据同步" class="headerlink" title="启动数据同步"></a>启动数据同步</h2><p>将集群1的数据同步到集群3。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 <span class="built_in">nohup</span> etcdctl make-mirror --endpoints=http://localhost:12379 http://localhost:32379 &amp;</span></span><br></pre></td></tr></table></figure><p>将集群2的数据同步到集群3。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 <span class="built_in">nohup</span> etcdctl make-mirror --endpoints=http://localhost:22379 http://localhost:32379 &amp;</span></span><br></pre></td></tr></table></figure><p>查看集群3的数据，可以看到集群1、集群2的键值已经同步到集群3了。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 etcdctl --endpoints=http://localhost:32379 get --prefix /</span></span><br><span class="line">/cluster1</span><br><span class="line">this is cluster1</span><br><span class="line">/cluster2</span><br><span class="line">this is cluster2</span><br><span class="line">/cluster3</span><br><span class="line">this is cluster3</span><br></pre></td></tr></table></figure><p>修改集群2的键值，然后查看集群3的键值信息，发现数据已实时同步。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 etcdctl --endpoints=http://localhost:22379 put /cluster2 <span class="string">&quot;renew cluster2&quot;</span>  <span class="comment"># 修改集群2的值</span></span></span><br><span class="line">OK</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ETCDCTL_API=3 etcdctl --endpoints=http://localhost:32379 get --prefix /</span></span><br><span class="line">/cluster1</span><br><span class="line">this is cluster1</span><br><span class="line">/cluster2</span><br><span class="line">renew cluster2      # 已同步最新修改</span><br><span class="line">/cluster3</span><br><span class="line">this is cluster3</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ul><li>make-mirror命令不仅能用来实时备份数据、异地容灾，还能将多个数据合并到一个集群。</li><li>遇到问题，最好的解决方案是阅读官方资料。</li></ul><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.mankier.com/1/etcdctl3-make-mirror">make-mirror命令手册</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/how-to-merge-multi-etcd-clusters-data/etcd-logo.svg&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;如果多个etcd集群的键值不重复，能否将数据合并？能否像数据库一样，将数据从旧库导出，然后在新库插入就万事大吉呢？答案是不能，etcd并没有提供类似功能，倒是有个备份功能，但是多个集群的备份数据却无法直接合并到一起。难道只能写个循环，将老集群的数据遍历出来，然后再插入新集群吗？这样也太土了吧，于是开始在网上找各种资料，可总是无功而返，看来只能老老实实看etcd官方资料了。功夫不负有心人，终于找到一条类似命令make-mirror，这条命令可以实时将一个集群的数据备份到其他集群，感觉跟我上面的想法一致，那么它可以用来做数据合并吗？请看接下来的实验吧！&lt;/p&gt;
    
    </summary>
    
      <category term="技术" scheme="http://supercoder.xyz/categories/technology/"/>
    
    
      <category term="etcd" scheme="http://supercoder.xyz/tags/etcd/"/>
    
  </entry>
  
  <entry>
    <title>AI速查图</title>
    <link href="http://supercoder.xyz/2019/04/27/ai-cheatsheets/"/>
    <id>http://supercoder.xyz/2019/04/27/ai-cheatsheets/</id>
    <published>2019-04-27T12:42:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/ai-cheatsheets/Numpy.png" class="img-topic" /><p>在github上发现了一个<a href="https://github.com/kailashahirwar/cheatsheets-ai">repo</a>，里面将常见机器学习python库的用法总结成了N张速查图，可以把这些图当做手册经常翻出来看看，加深记忆。PDF版可以从<a href="/img/ai-cheatsheets/All-Cheat-Sheets.pdf">这里</a>下载。</p><span id="more"></span><h2 id="基础库"><a href="#基础库" class="headerlink" title="基础库"></a>基础库</h2><h3 id="Numpy"><a href="#Numpy" class="headerlink" title="Numpy"></a>Numpy</h3><p><img src="/img/ai-cheatsheets/Numpy.png" alt="Numpy"></p><h3 id="Scipy"><a href="#Scipy" class="headerlink" title="Scipy"></a>Scipy</h3><p><img src="/img/ai-cheatsheets/Scipy.png" alt="Scipy"></p><h3 id="Pandas"><a href="#Pandas" class="headerlink" title="Pandas"></a>Pandas</h3><p><img src="/img/ai-cheatsheets/Pandas-1.jpg" alt="Pandas1"><br><img src="/img/ai-cheatsheets/Pandas-2.jpg" alt="Pandas2"><br><img src="/img/ai-cheatsheets/Pandas-3.png" alt="Pandas3"></p><h2 id="绘图"><a href="#绘图" class="headerlink" title="绘图"></a>绘图</h2><h3 id="Matplotlib"><a href="#Matplotlib" class="headerlink" title="Matplotlib"></a>Matplotlib</h3><p><img src="/img/ai-cheatsheets/Matplotlib.png" alt="Matplotlib"></p><h2 id="机器学习"><a href="#机器学习" class="headerlink" title="机器学习"></a>机器学习</h2><h3 id="sklearn"><a href="#sklearn" class="headerlink" title="sklearn"></a>sklearn</h3><p><img src="/img/ai-cheatsheets/Scikit-Learn.png" alt="Scikit Learn.png"></p><h3 id="PySpark"><a href="#PySpark" class="headerlink" title="PySpark"></a>PySpark</h3><p><img src="/img/ai-cheatsheets/PySpark.jpg" alt="PySpark"><br><img src="/img/ai-cheatsheets/PySpark-RDD.png" alt="PySpark-RDD"><br><img src="/img/ai-cheatsheets/PySpark-SQL.png" alt="PySpark-SQL"></p><h2 id="深度学习"><a href="#深度学习" class="headerlink" title="深度学习"></a>深度学习</h2><h3 id="Keras"><a href="#Keras" class="headerlink" title="Keras"></a>Keras</h3><p><img src="/img/ai-cheatsheets/Keras.jpg" alt="Keras"></p><h3 id="常见神经网络"><a href="#常见神经网络" class="headerlink" title="常见神经网络"></a>常见神经网络</h3><p><img src="/img/ai-cheatsheets/Neural-Networks-Zoo.png" alt="Neural Networks Zoo"></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://github.com/kailashahirwar/cheatsheets-ai">https://github.com/kailashahirwar/cheatsheets-ai</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/ai-cheatsheets/Numpy.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;在github上发现了一个&lt;a href=&quot;https://github.com/kailashahirwar/cheatsheets-ai&quot;&gt;repo&lt;/a&gt;，里面将常见机器学习python库的用法总结成了N张速查图，可以把这些图当做手册经常翻出来看看，加深记忆。PDF版可以从&lt;a href=&quot;/img/ai-cheatsheets/All-Cheat-Sheets.pdf&quot;&gt;这里&lt;/a&gt;下载。&lt;/p&gt;
    
    </summary>
    
      <category term="技术" scheme="http://supercoder.xyz/categories/technology/"/>
    
    
      <category term="Python" scheme="http://supercoder.xyz/tags/Python/"/>
    
      <category term="机器学习" scheme="http://supercoder.xyz/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>聚类算法综述</title>
    <link href="http://supercoder.xyz/2019/04/13/about-clustering/"/>
    <id>http://supercoder.xyz/2019/04/13/about-clustering/</id>
    <published>2019-04-13T14:26:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/about-clustering/sklearn-clustering.png" class="img-topic" /><p>聚类是机器学习中一种重要的无监督算法，它试图将数据集中的样本划分为若干个通常不相交的子集，每个子集成为一个“簇”（cluster），理论上来说，每一簇对应一个潜在的概念，但这个概念事先并不知道，需要使用者来把握。本文是常见聚类算法的综述，为了加深理解，大部分算法配有动图。</p><span id="more"></span><h2 id="常见聚类算法"><a href="#常见聚类算法" class="headerlink" title="常见聚类算法"></a>常见聚类算法</h2><h3 id="K均值（Kmeans）"><a href="#K均值（Kmeans）" class="headerlink" title="K均值（Kmeans）"></a>K均值（Kmeans）</h3><p>这一最著名的聚类算法，主要基于数据点之间的均值和与聚类中心的聚类迭代而成。它主要的优点是十分的高效，由于只需要计算数据点与聚类中心的距离，其计算复杂度只有O(n)。<br><img src="/img/about-clustering/kmeans.gif" alt="K均值"></p><p>1.首先我们需要预先给定聚类的数目同时随机初始化聚类中心。我们可以粗略的观察数据并给出较为准确的聚类数目；<br>2.每一个数据点通过计算与聚类中心的距离了来分类到最邻近的一类中；<br>3.根据分类结果，利用分类后的数据点重新计算聚类中心；<br>4.重复步骤2、3直到聚类中心不再变化。（可以随机初始化不同的聚类中心以选取最好的结果）</p><p>这种方法在理解和实现上都十分简单，但缺点却也非常明显：十分依赖于初始给定的聚类数目；同时随机初始化可能会生成不同的聚类效果，所以它缺乏重复性和连续性。<br>和K均值类似的K中值算法，在计算过程中利用中值来计算聚类中心，使得局外点对它的影响大大减弱；但每一次循环计算中值矢量带来了计算速度的大大下降。</p><h3 id="均值漂移（Mean-Shift）"><a href="#均值漂移（Mean-Shift）" class="headerlink" title="均值漂移（Mean Shift）"></a>均值漂移（Mean Shift）</h3><p>这是一种基于滑动窗口的均值算法，用于寻找数据点中密度最大的区域。其目标是找出每一个类的中心点，并通过计算滑窗内点的均值更新滑窗的中心点。最终消除临近重复值的影响并形成中心点，找到其对应的类别。<br><img src="/img/about-clustering/mean-shift.gif" alt="均值漂移"></p><p>1.首先，以随机选取的点为圆心，r为半径做一个圆形的滑窗。其目标是找出数据点中密度最高点并作为中心；<br>2.在每个迭代后，滑动窗口的中心将向较高密度的方向移动；<br>3.连续移动，直到任何方向的移动都不能增加滑窗中点的数量，此时滑窗收敛；<br>4.将上述步骤在多个滑窗上进行以覆盖所有的点。当多个滑窗收敛重叠时，其经过的点将会通过其滑窗聚类为一个类。</p><p>下图中每一个黑点都代表一个滑窗的中心，他们最终重叠在每一类的中心；<br><img src="/img/about-clustering/mean-shift2.gif" alt="均值漂移"></p><p>与K均值相比最大的优点是，我们无需指定指定聚类数目，聚类中心处于最高密度处也是符合直觉认知的结果。但其最大的缺点在于滑窗大小r的选取，对于结果有着很大的影响。</p><h3 id="DBSCAN"><a href="#DBSCAN" class="headerlink" title="DBSCAN"></a>DBSCAN</h3><p>DBSCAN同样是基于密度的聚类算法，但其原理却与均值漂移大不相同：<br><img src="/img/about-clustering/DBSCAN.gif" alt="DBSCAN"></p><p>1.首先从没有被遍历的任一点开始，利用邻域距离epsilon来获取周围点；<br>2.如果邻域内点的数量满足阈值则此点成为核心点并以此开始新一类的聚类。（如果不是则标记为噪声）；<br>3.其邻域内的所有点也属于同一类，将所有的邻域内点以epsilon为半径进行步骤2的计算；<br>4.重复步骤2、3直到遍历完所有核心点的邻域点；<br>5.此类聚类完成，同时又以任意未遍历点开始步骤1到4直到所有数据点都被处理；<br>6.最终每个数据点都有自己的归属类别或者属于噪声。</p><p>这种方法最大的优点在于无需定义类的数量，其次可以识别出局外点和噪声点，并且可以对任意形状的数据进行聚类。<br>但也存在不可回避的缺点，当数据密度变化剧烈时，不同类别的密度阈值点和领域半径会产生很大的变化。同时在高维空间中准确估计领域半径也是不小的挑战。</p><h3 id="高斯混合模型"><a href="#高斯混合模型" class="headerlink" title="高斯混合模型"></a>高斯混合模型</h3><p>通过假设数据点符合均值和标准差描述的高斯混合模型来实现的。下图以二维情况下为例描述了如何利用最大期望优化算法来获取分布参数的过程：<br><img src="/img/about-clustering/gauss-mix.gif" alt="高斯混合模型"></p><p>1.首先确定聚类的数量，并随机初始化每一个聚类的高斯分布参数；<br>2.通过计算每一个点属于高斯分布的概率来进行聚类。与高斯中心越近的点越有可能属于这个类；<br>3.基于上一步数据点的概率权重，通过最大似然估计的方法计算出每一类数据点最有可能属于这一聚类的高斯参数；<br>4.基于新的高斯参数，重新估计每一点归属各类的概率，重复2，3步骤直到参数不再变化收敛为止。</p><p>在使用高斯混合模型时有两个关键的地方，首先高斯混合模型十分灵活，可以拟合任意形状的椭圆；其次这是一种基于概率的算法，每个点可以拥有属于多类的概率，支持混合属性。</p><h3 id="凝聚层次聚类"><a href="#凝聚层次聚类" class="headerlink" title="凝聚层次聚类"></a>凝聚层次聚类</h3><p>层次聚类法主要有自顶向下和自底向上两种方式。其中自底向上的方式，最初将每个点看做是独立的类别，随后通过一步步的凝聚最后形成独立的一大类，并包含所有的数据点。这会形成一个树形结构，并在这一过程中形成聚类。<br><img src="/img/about-clustering/Hierarchical-Agglomerative-Clustering.gif" alt="凝聚层次聚类"></p><p>1.首先将每一个数据点看成一个类别，通过计算点与点之间的距离将距离近的点归为一个子类，作为下一次聚类的基础；<br>2.每一次迭代将两个元素聚类成一个，上述的子类中距离最近的两两又合并为新的子类。最相近的都被合并在一起；<br>3.重复步骤2直到所有的类别都合并为一个根节点。基于此我们可以选择聚类的数目，并根据树来进行选择。</p><p>层次聚类无需事先指定类的数目，并且对于距离的度量不敏感。这种方法最好的应用在于恢复出数据的层次化结构。但其计算复杂度较高达到了O（n^3）.</p><h2 id="sklearn实现"><a href="#sklearn实现" class="headerlink" title="sklearn实现"></a>sklearn实现</h2><p>sklearn官网(<a href="http://scikit-learn.org/stable/modules/clustering.html#clustering">http://scikit-learn.org/stable/modules/clustering.html#clustering</a>) 对常见的聚类算法做了汇总比较，结果一目了然，可以看出<strong>DBSCAN</strong>在训练时长和结果上均有优异表现，最终效果如下：<br><img src="/img/about-clustering/sklearn-clustering.png" alt="聚类算法对比"></p><p>实现代码如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> warnings</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> sklearn <span class="keyword">import</span> cluster, datasets, mixture</span><br><span class="line"><span class="keyword">from</span> sklearn.neighbors <span class="keyword">import</span> kneighbors_graph</span><br><span class="line"><span class="keyword">from</span> sklearn.preprocessing <span class="keyword">import</span> StandardScaler</span><br><span class="line"><span class="keyword">from</span> itertools <span class="keyword">import</span> cycle, islice</span><br><span class="line"></span><br><span class="line">np.random.seed(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># ============</span></span><br><span class="line"><span class="comment"># Generate datasets. We choose the size big enough to see the scalability</span></span><br><span class="line"><span class="comment"># of the algorithms, but not too big to avoid too long running times</span></span><br><span class="line"><span class="comment"># ============</span></span><br><span class="line">n_samples = <span class="number">1500</span></span><br><span class="line">noisy_circles = datasets.make_circles(n_samples=n_samples, factor=<span class="number">.5</span>,</span><br><span class="line">                                      noise=<span class="number">.05</span>)</span><br><span class="line">noisy_moons = datasets.make_moons(n_samples=n_samples, noise=<span class="number">.05</span>)</span><br><span class="line">blobs = datasets.make_blobs(n_samples=n_samples, random_state=<span class="number">8</span>)</span><br><span class="line">no_structure = np.random.rand(n_samples, <span class="number">2</span>), <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Anisotropicly distributed data</span></span><br><span class="line">random_state = <span class="number">170</span></span><br><span class="line">X, y = datasets.make_blobs(n_samples=n_samples, random_state=random_state)</span><br><span class="line">transformation = [[<span class="number">0.6</span>, -<span class="number">0.6</span>], [-<span class="number">0.4</span>, <span class="number">0.8</span>]]</span><br><span class="line">X_aniso = np.dot(X, transformation)</span><br><span class="line">aniso = (X_aniso, y)</span><br><span class="line"></span><br><span class="line"><span class="comment"># blobs with varied variances</span></span><br><span class="line">varied = datasets.make_blobs(n_samples=n_samples,</span><br><span class="line">                             cluster_std=[<span class="number">1.0</span>, <span class="number">2.5</span>, <span class="number">0.5</span>],</span><br><span class="line">                             random_state=random_state)</span><br><span class="line"></span><br><span class="line"><span class="comment"># ============</span></span><br><span class="line"><span class="comment"># Set up cluster parameters</span></span><br><span class="line"><span class="comment"># ============</span></span><br><span class="line">plt.figure(figsize=(<span class="number">9</span> * <span class="number">2</span> + <span class="number">3</span>, <span class="number">12.5</span>))</span><br><span class="line">plt.subplots_adjust(left=<span class="number">.02</span>, right=<span class="number">.98</span>, bottom=<span class="number">.001</span>, top=<span class="number">.96</span>, wspace=<span class="number">.05</span>,</span><br><span class="line">                    hspace=<span class="number">.01</span>)</span><br><span class="line"></span><br><span class="line">plot_num = <span class="number">1</span></span><br><span class="line"></span><br><span class="line">default_base = &#123;<span class="string">&#x27;quantile&#x27;</span>: <span class="number">.3</span>,</span><br><span class="line">                <span class="string">&#x27;eps&#x27;</span>: <span class="number">.3</span>,</span><br><span class="line">                <span class="string">&#x27;damping&#x27;</span>: <span class="number">.9</span>,</span><br><span class="line">                <span class="string">&#x27;preference&#x27;</span>: -<span class="number">200</span>,</span><br><span class="line">                <span class="string">&#x27;n_neighbors&#x27;</span>: <span class="number">10</span>,</span><br><span class="line">                <span class="string">&#x27;n_clusters&#x27;</span>: <span class="number">3</span>&#125;</span><br><span class="line"></span><br><span class="line">datasets = [</span><br><span class="line">    (noisy_circles, &#123;<span class="string">&#x27;damping&#x27;</span>: <span class="number">.77</span>, <span class="string">&#x27;preference&#x27;</span>: -<span class="number">240</span>,</span><br><span class="line">                     <span class="string">&#x27;quantile&#x27;</span>: <span class="number">.2</span>, <span class="string">&#x27;n_clusters&#x27;</span>: <span class="number">2</span>&#125;),</span><br><span class="line">    (noisy_moons, &#123;<span class="string">&#x27;damping&#x27;</span>: <span class="number">.75</span>, <span class="string">&#x27;preference&#x27;</span>: -<span class="number">220</span>, <span class="string">&#x27;n_clusters&#x27;</span>: <span class="number">2</span>&#125;),</span><br><span class="line">    (varied, &#123;<span class="string">&#x27;eps&#x27;</span>: <span class="number">.18</span>, <span class="string">&#x27;n_neighbors&#x27;</span>: <span class="number">2</span>&#125;),</span><br><span class="line">    (aniso, &#123;<span class="string">&#x27;eps&#x27;</span>: <span class="number">.15</span>, <span class="string">&#x27;n_neighbors&#x27;</span>: <span class="number">2</span>&#125;),</span><br><span class="line">    (blobs, &#123;&#125;),</span><br><span class="line">    (no_structure, &#123;&#125;)]</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i_dataset, (dataset, algo_params) <span class="keyword">in</span> <span class="built_in">enumerate</span>(datasets):</span><br><span class="line">    <span class="comment"># update parameters with dataset-specific values</span></span><br><span class="line">    params = default_base.copy()</span><br><span class="line">    params.update(algo_params)</span><br><span class="line"></span><br><span class="line">    X, y = dataset</span><br><span class="line"></span><br><span class="line">    <span class="comment"># normalize dataset for easier parameter selection</span></span><br><span class="line">    X = StandardScaler().fit_transform(X)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># estimate bandwidth for mean shift</span></span><br><span class="line">    bandwidth = cluster.estimate_bandwidth(X, quantile=params[<span class="string">&#x27;quantile&#x27;</span>])</span><br><span class="line"></span><br><span class="line">    <span class="comment"># connectivity matrix for structured Ward</span></span><br><span class="line">    connectivity = kneighbors_graph(</span><br><span class="line">        X, n_neighbors=params[<span class="string">&#x27;n_neighbors&#x27;</span>], include_self=<span class="literal">False</span>)</span><br><span class="line">    <span class="comment"># make connectivity symmetric</span></span><br><span class="line">    connectivity = <span class="number">0.5</span> * (connectivity + connectivity.T)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># ============</span></span><br><span class="line">    <span class="comment"># Create cluster objects</span></span><br><span class="line">    <span class="comment"># ============</span></span><br><span class="line">    ms = cluster.MeanShift(bandwidth=bandwidth, bin_seeding=<span class="literal">True</span>)</span><br><span class="line">    two_means = cluster.MiniBatchKMeans(n_clusters=params[<span class="string">&#x27;n_clusters&#x27;</span>])</span><br><span class="line">    ward = cluster.AgglomerativeClustering(</span><br><span class="line">        n_clusters=params[<span class="string">&#x27;n_clusters&#x27;</span>], linkage=<span class="string">&#x27;ward&#x27;</span>,</span><br><span class="line">        connectivity=connectivity)</span><br><span class="line">    spectral = cluster.SpectralClustering(</span><br><span class="line">        n_clusters=params[<span class="string">&#x27;n_clusters&#x27;</span>], eigen_solver=<span class="string">&#x27;arpack&#x27;</span>,</span><br><span class="line">        affinity=<span class="string">&quot;nearest_neighbors&quot;</span>)</span><br><span class="line">    dbscan = cluster.DBSCAN(eps=params[<span class="string">&#x27;eps&#x27;</span>])</span><br><span class="line">    affinity_propagation = cluster.AffinityPropagation(</span><br><span class="line">        damping=params[<span class="string">&#x27;damping&#x27;</span>], preference=params[<span class="string">&#x27;preference&#x27;</span>])</span><br><span class="line">    average_linkage = cluster.AgglomerativeClustering(</span><br><span class="line">        linkage=<span class="string">&quot;average&quot;</span>, affinity=<span class="string">&quot;cityblock&quot;</span>,</span><br><span class="line">        n_clusters=params[<span class="string">&#x27;n_clusters&#x27;</span>], connectivity=connectivity)</span><br><span class="line">    birch = cluster.Birch(n_clusters=params[<span class="string">&#x27;n_clusters&#x27;</span>])</span><br><span class="line">    gmm = mixture.GaussianMixture(</span><br><span class="line">        n_components=params[<span class="string">&#x27;n_clusters&#x27;</span>], covariance_type=<span class="string">&#x27;full&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    clustering_algorithms = (</span><br><span class="line">        (<span class="string">&#x27;MiniBatchKMeans&#x27;</span>, two_means),</span><br><span class="line">        (<span class="string">&#x27;AffinityPropagation&#x27;</span>, affinity_propagation),</span><br><span class="line">        (<span class="string">&#x27;MeanShift&#x27;</span>, ms),</span><br><span class="line">        (<span class="string">&#x27;SpectralClustering&#x27;</span>, spectral),</span><br><span class="line">        (<span class="string">&#x27;Ward&#x27;</span>, ward),</span><br><span class="line">        (<span class="string">&#x27;AgglomerativeClustering&#x27;</span>, average_linkage),</span><br><span class="line">        (<span class="string">&#x27;DBSCAN&#x27;</span>, dbscan),</span><br><span class="line">        (<span class="string">&#x27;Birch&#x27;</span>, birch),</span><br><span class="line">        (<span class="string">&#x27;GaussianMixture&#x27;</span>, gmm)</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> name, algorithm <span class="keyword">in</span> clustering_algorithms:</span><br><span class="line">        t0 = time.time()</span><br><span class="line"></span><br><span class="line">        <span class="comment"># catch warnings related to kneighbors_graph</span></span><br><span class="line">        <span class="keyword">with</span> warnings.catch_warnings():</span><br><span class="line">            warnings.filterwarnings(</span><br><span class="line">                <span class="string">&quot;ignore&quot;</span>,</span><br><span class="line">                message=<span class="string">&quot;the number of connected components of the &quot;</span> +</span><br><span class="line">                <span class="string">&quot;connectivity matrix is [0-9]&#123;1,2&#125;&quot;</span> +</span><br><span class="line">                <span class="string">&quot; &gt; 1. Completing it to avoid stopping the tree early.&quot;</span>,</span><br><span class="line">                category=UserWarning)</span><br><span class="line">            warnings.filterwarnings(</span><br><span class="line">                <span class="string">&quot;ignore&quot;</span>,</span><br><span class="line">                message=<span class="string">&quot;Graph is not fully connected, spectral embedding&quot;</span> +</span><br><span class="line">                <span class="string">&quot; may not work as expected.&quot;</span>,</span><br><span class="line">                category=UserWarning)</span><br><span class="line">            algorithm.fit(X)</span><br><span class="line"></span><br><span class="line">        t1 = time.time()</span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">hasattr</span>(algorithm, <span class="string">&#x27;labels_&#x27;</span>):</span><br><span class="line">            y_pred = algorithm.labels_.astype(np.<span class="built_in">int</span>)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            y_pred = algorithm.predict(X)</span><br><span class="line"></span><br><span class="line">        plt.subplot(<span class="built_in">len</span>(datasets), <span class="built_in">len</span>(clustering_algorithms), plot_num)</span><br><span class="line">        <span class="keyword">if</span> i_dataset == <span class="number">0</span>:</span><br><span class="line">            plt.title(name, size=<span class="number">18</span>)</span><br><span class="line"></span><br><span class="line">        colors = np.array(<span class="built_in">list</span>(islice(cycle([<span class="string">&#x27;#377eb8&#x27;</span>, <span class="string">&#x27;#ff7f00&#x27;</span>, <span class="string">&#x27;#4daf4a&#x27;</span>,</span><br><span class="line">                                             <span class="string">&#x27;#f781bf&#x27;</span>, <span class="string">&#x27;#a65628&#x27;</span>, <span class="string">&#x27;#984ea3&#x27;</span>,</span><br><span class="line">                                             <span class="string">&#x27;#999999&#x27;</span>, <span class="string">&#x27;#e41a1c&#x27;</span>, <span class="string">&#x27;#dede00&#x27;</span>]),</span><br><span class="line">                                      <span class="built_in">int</span>(<span class="built_in">max</span>(y_pred) + <span class="number">1</span>))))</span><br><span class="line">        <span class="comment"># add black color for outliers (if any)</span></span><br><span class="line">        colors = np.append(colors, [<span class="string">&quot;#000000&quot;</span>])</span><br><span class="line">        plt.scatter(X[:, <span class="number">0</span>], X[:, <span class="number">1</span>], s=<span class="number">10</span>, color=colors[y_pred])</span><br><span class="line"></span><br><span class="line">        plt.xlim(-<span class="number">2.5</span>, <span class="number">2.5</span>)</span><br><span class="line">        plt.ylim(-<span class="number">2.5</span>, <span class="number">2.5</span>)</span><br><span class="line">        plt.xticks(())</span><br><span class="line">        plt.yticks(())</span><br><span class="line">        plt.text(<span class="number">.99</span>, <span class="number">.01</span>, (<span class="string">&#x27;%.2fs&#x27;</span> % (t1 - t0)).lstrip(<span class="string">&#x27;0&#x27;</span>),</span><br><span class="line">                 transform=plt.gca().transAxes, size=<span class="number">15</span>,</span><br><span class="line">                 horizontalalignment=<span class="string">&#x27;right&#x27;</span>)</span><br><span class="line">        plot_num += <span class="number">1</span></span><br><span class="line"></span><br><span class="line">plt.show()</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="http://m.elecfans.com/article/683501.html">机器学习中五种常用的聚类算法</a></li><li>《机器学习》周志华 第九章</li><li>sklearn官网</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/about-clustering/sklearn-clustering.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;聚类是机器学习中一种重要的无监督算法，它试图将数据集中的样本划分为若干个通常不相交的子集，每个子集成为一个“簇”（cluster），理论上来说，每一簇对应一个潜在的概念，但这个概念事先并不知道，需要使用者来把握。本文是常见聚类算法的综述，为了加深理解，大部分算法配有动图。&lt;/p&gt;
    
    </summary>
    
      <category term="技术" scheme="http://supercoder.xyz/categories/technology/"/>
    
    
      <category term="Python" scheme="http://supercoder.xyz/tags/Python/"/>
    
      <category term="机器学习" scheme="http://supercoder.xyz/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
      <category term="聚类" scheme="http://supercoder.xyz/tags/%E8%81%9A%E7%B1%BB/"/>
    
      <category term="sklearn" scheme="http://supercoder.xyz/tags/sklearn/"/>
    
  </entry>
  
  <entry>
    <title>pyspark模型结构解析</title>
    <link href="http://supercoder.xyz/2019/03/31/pyspark-model-analysis/"/>
    <id>http://supercoder.xyz/2019/03/31/pyspark-model-analysis/</id>
    <published>2019-03-31T02:16:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/pyspark-model-analysis/pyspark-logo.png" class="img-topic" /><p>最近在将自研算法集成到pyspark生态中，为了降低用户学习成本，计划将接口、最终生成模型都按照pyspark要求来实现，但是在互联网上并没有找到官方的开发指南，所以只能自己一步一步的琢磨，今天就先来看下pyspark最终保存的模型长什么样，后面再全面总结如何融入生态。</p><span id="more"></span><h2 id="生成模型"><a href="#生成模型" class="headerlink" title="生成模型"></a>生成模型</h2><p>首先训练一个模型，本文以逻辑回归为例，代码如下</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">data = [LabeledPoint(<span class="number">0.0</span>, [<span class="number">0.0</span>, <span class="number">1.0</span>]), LabeledPoint(<span class="number">1.0</span>, [<span class="number">1.0</span>, <span class="number">0.0</span>]),]</span><br><span class="line">lrm = LogisticRegressionWithSGD.train(sc.parallelize(data), iterations=<span class="number">10</span>)</span><br><span class="line">lrm.save(sc, <span class="string">&#x27;file:///lrm_model&#x27;</span>)</span><br></pre></td></tr></table></figure><p>生成的结果如下，可以看出模型包含2个文件夹，一个是data，一个是metadata，很明显这两个都是parquet格式的文件，data是DF格式的，metadata是文本格式的。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">$ tree lrm_model/</span><br><span class="line">lrm_model/</span><br><span class="line">├── data</span><br><span class="line">│   ├── _SUCCESS</span><br><span class="line">│   └── part-00000-ccd54944-8aed-4ed5-accd-5d854e8f89b9.snappy.parquet</span><br><span class="line">└── metadata</span><br><span class="line">    ├── _SUCCESS</span><br><span class="line">    └── part-00000</span><br><span class="line"></span><br><span class="line">2 directories, 4 files</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="解析模型"><a href="#解析模型" class="headerlink" title="解析模型"></a>解析模型</h2><p>尝试用parquet格式读取data下的内容，很显然是DF结构的数据，3个字段，一条记录，主要是逻辑回归的参数。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sqlContext.read.parquet(<span class="string">&#x27;file:///lrm_model/data&#x27;</span>).show()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">+--------------------+---------+---------+</span><br><span class="line">|             weights|intercept|threshold|</span><br><span class="line">+--------------------+---------+---------+</span><br><span class="line">|[0.94797638679085...|      0.0|      0.5|</span><br><span class="line">+--------------------+---------+---------+</span><br></pre></td></tr></table></figure><p>再解析metadata下的数据，如果再用parquet去读就会报错，用text()方法可以看到是一段文字，但并没有显示完全。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sqlContext.read.text(<span class="string">&#x27;file:///lrm_model/metadata&#x27;</span>).show()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">+--------------------+</span><br><span class="line">|               value|</span><br><span class="line">+--------------------+</span><br><span class="line">|&#123;&quot;class&quot;:&quot;org.apa...|</span><br><span class="line">+--------------------+</span><br></pre></td></tr></table></figure><p>由于是文本，所以直接用cat输出文件内容，可以看出是这个模型的元数据文件，包括类名、版本号及输入数据的特征。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ cat lrm_model/metadata/part-00000</span><br><span class="line">&#123;&quot;class&quot;:&quot;org.apache.spark.mllib.classification.LogisticRegressionModel&quot;,&quot;version&quot;:&quot;1.0&quot;,&quot;numFeatures&quot;:2,&quot;numClasses&quot;:2&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/pyspark-model-analysis/pyspark-logo.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;最近在将自研算法集成到pyspark生态中，为了降低用户学习成本，计划将接口、最终生成模型都按照pyspark要求来实现，但是在互联网上并没有找到官方的开发指南，所以只能自己一步一步的琢磨，今天就先来看下pyspark最终保存的模型长什么样，后面再全面总结如何融入生态。&lt;/p&gt;
    
    </summary>
    
      <category term="技术" scheme="http://supercoder.xyz/categories/technology/"/>
    
    
      <category term="Python" scheme="http://supercoder.xyz/tags/Python/"/>
    
      <category term="机器学习" scheme="http://supercoder.xyz/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
      <category term="pyspark" scheme="http://supercoder.xyz/tags/pyspark/"/>
    
  </entry>
  
  <entry>
    <title>Python中获取调用者信息的方法</title>
    <link href="http://supercoder.xyz/2017/09/26/get-caller-info-in-python/"/>
    <id>http://supercoder.xyz/2017/09/26/get-caller-info-in-python/</id>
    <published>2017-09-26T15:04:54.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/get-caller-info-in-python/python-logo.png" class="img-topic" /><p>在Python中，获取调用者信息对于调试、打印日志等非常有帮助，本文将介绍获取调用者信息的两种方法。</p><span id="more"></span><h2 id="使用sys-getframe方法"><a href="#使用sys-getframe方法" class="headerlink" title="使用sys._getframe方法"></a>使用sys._getframe方法</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">print_caller_by_sys</span>():</span><br><span class="line">    <span class="comment"># 获取被调用函数所在模块文件名</span></span><br><span class="line">    <span class="built_in">print</span>(sys._getframe(<span class="number">1</span>).f_code.co_filename)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取被调用函数名称</span></span><br><span class="line">    <span class="built_in">print</span>(sys._getframe(<span class="number">1</span>).f_code.co_name)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取被调用函数在被调用时所处代码行数</span></span><br><span class="line">    <span class="built_in">print</span>(sys._getframe(<span class="number">1</span>).f_lineno)</span><br></pre></td></tr></table></figure><h2 id="使用inspect-stack方法"><a href="#使用inspect-stack方法" class="headerlink" title="使用inspect.stack方法"></a>使用inspect.stack方法</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> inspect</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">print_caller_by_inspect</span>():</span><br><span class="line">    <span class="comment"># 获取被调用函数所在模块文件名</span></span><br><span class="line">    <span class="built_in">print</span>(inspect.stack()[<span class="number">1</span>][<span class="number">1</span>])</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取被调用函数名称</span></span><br><span class="line">    <span class="built_in">print</span>(inspect.stack()[<span class="number">1</span>][<span class="number">3</span>])</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取被调用函数在被调用时所处代码行数</span></span><br><span class="line">    <span class="built_in">print</span>(inspect.stack()[<span class="number">1</span>][<span class="number">2</span>])</span><br></pre></td></tr></table></figure><h2 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment">#coding:utf-8</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> inspect</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">print_caller_by_sys</span>():</span><br><span class="line">    <span class="comment"># 获取被调用函数所在模块文件名</span></span><br><span class="line">    <span class="built_in">print</span>(sys._getframe(<span class="number">1</span>).f_code.co_filename)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取被调用函数名称</span></span><br><span class="line">    <span class="built_in">print</span>(sys._getframe(<span class="number">1</span>).f_code.co_name)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取被调用函数在被调用时所处代码行数</span></span><br><span class="line">    <span class="built_in">print</span>(sys._getframe(<span class="number">1</span>).f_lineno)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">print_caller_by_inspect</span>():</span><br><span class="line">    <span class="comment"># 获取被调用函数所在模块文件名</span></span><br><span class="line">    <span class="built_in">print</span>(inspect.stack()[<span class="number">1</span>][<span class="number">1</span>])</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取被调用函数名称</span></span><br><span class="line">    <span class="built_in">print</span>(inspect.stack()[<span class="number">1</span>][<span class="number">3</span>])</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取被调用函数在被调用时所处代码行数</span></span><br><span class="line">    <span class="built_in">print</span>(inspect.stack()[<span class="number">1</span>][<span class="number">2</span>])</span><br><span class="line"></span><br><span class="line"><span class="comment"># 定义为注解，方便调试具体函数</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show_caller</span>(<span class="params">level=<span class="number">1</span></span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">func</span>):</span><br><span class="line">        <span class="keyword">def</span> <span class="title function_">wrapper</span>(<span class="params">*args, **kwargs</span>):</span><br><span class="line">            func(*args, **kwargs)</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&#x27;&#123;0.f_code.co_filename&#125;:&#123;0.f_code.co_name&#125;:&#123;0.f_lineno&#125;&#x27;</span>.<span class="built_in">format</span>(sys._getframe(level)))</span><br><span class="line">        <span class="keyword">return</span> wrapper</span><br><span class="line">    <span class="keyword">return</span> show</span><br><span class="line"></span><br><span class="line"><span class="meta">@show_caller(<span class="params"><span class="number">1</span></span>)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">main</span>():</span><br><span class="line">    print_caller_by_sys()</span><br><span class="line">    print_caller_by_inspect()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    main()</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/get-caller-info-in-python/python-logo.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;在Python中，获取调用者信息对于调试、打印日志等非常有帮助，本文将介绍获取调用者信息的两种方法。&lt;/p&gt;
    
    </summary>
    
      <category term="技术" scheme="http://supercoder.xyz/categories/technology/"/>
    
    
      <category term="Python" scheme="http://supercoder.xyz/tags/Python/"/>
    
  </entry>
  
  <entry>
    <title>Vim键盘图</title>
    <link href="http://supercoder.xyz/2017/01/14/vim-keyboard/"/>
    <id>http://supercoder.xyz/2017/01/14/vim-keyboard/</id>
    <published>2017-01-14T14:26:00.000Z</published>
    <updated>2024-04-17T08:28:41.922Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/vim-keyboard/keyboard.png" class="img-topic" /><p>vi/vim是各Linux发行版默认安装的文本编辑工具，熟练使用它对文本操作效率的提升有很大帮助。但掌握vim并非易事，尤其是数不胜数的快捷键有时会令人抓狂。还好有大牛将快捷键在键盘中的位置标记出来了，生成了一张“键盘图”（类似学习五笔打字时的字根图），我们可以将其打印出来贴在电脑旁边或者设置为桌面，忘记了就瞄一眼，时间长了定能孰能生巧。</p><span id="more"></span><h2 id="键盘图"><a href="#键盘图" class="headerlink" title="键盘图"></a>键盘图</h2><p><img src="/img/vim-keyboard/vim-keyboard-en.jpg" alt="英文版"><br>该图来源于<a href="http://www.viemu.com/">官网</a>，该网站上还有vim的使用教程，内容非常详细，建议学习下。</p><p>中文版如下<br><img src="/img/vim-keyboard/vim-keyboard.jpg" alt="中文版"></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="http://www.viemu.com/">viemu官网</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/vim-keyboard/keyboard.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;vi/vim是各Linux发行版默认安装的文本编辑工具，熟练使用它对文本操作效率的提升有很大帮助。但掌握vim并非易事，尤其是数不胜数的快捷键有时会令人抓狂。还好有大牛将快捷键在键盘中的位置标记出来了，生成了一张“键盘图”（类似学习五笔打字时的字根图），我们可以将其打印出来贴在电脑旁边或者设置为桌面，忘记了就瞄一眼，时间长了定能孰能生巧。&lt;/p&gt;
    
    </summary>
    
      <category term="工具" scheme="http://supercoder.xyz/categories/tool/"/>
    
    
      <category term="Linux" scheme="http://supercoder.xyz/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>基于Web的终端模拟神器shellinabox简介</title>
    <link href="http://supercoder.xyz/2016/07/18/Introduce-to-shellinabox/"/>
    <id>http://supercoder.xyz/2016/07/18/Introduce-to-shellinabox/</id>
    <published>2016-07-18T08:21:00.000Z</published>
    <updated>2024-04-17T08:28:41.918Z</updated>
    
    <content type="html"><![CDATA[<img src="/img/Introduce-to-shellinabox/Terminal.png" class="img-topic" /><p>通常情况下，我们访问Linux服务器时会使用Putty或者Xshell等SSH客户端工具，但这些工具均需要安装后才能使用，在安全要求不高（如局域网）或者只是开放服务器给其他人体验某种功能时，客户端这种方式略显繁琐。本文将介绍一款开源神器shellinabox，只需要浏览器就可以进行远程访问，相信用过它后，定会爱不释手。</p><span id="more"></span><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>shellinabox使用AJAX技术，通过浏览器提供了原生Shell的外观，并且部署和使用都非常简单。由于shellinabox比较简单，在安全上不如SSH协议，建议不要在安全要求高的场景下使用。</p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>主流的发行版均提供shellinabox包，当然也可以自行编译、安装，具体步骤参考<a href="https://github.com/shellinabox/shellinabox">官网</a>。<br>在Ubuntu上，你可以使用如下命令安装它：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">sudo apt-get install shellinabox</span></span><br></pre></td></tr></table></figure><p>安装后的可执行程序是shellinaboxd，其配置文件为/etc/default/shellinabox，可以按需更改，如修改默认端口号。或者也可以在启动时，通过参数传入配置。</p><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><p>在浏览器中输入<code>https://your-ip:4200</code>，忽略证书错误，输入用户名、密码就可以使用了，是不是很简单！<br><img src="/img/Introduce-to-shellinabox/login-screen.png" alt="login-screen"></p><p>在浏览器窗口中单击右键，会弹出一个菜单，前面有对号的表示生效的配置<br><img src="/img/Introduce-to-shellinabox/menu.png" alt="menu"></p><p>其中，<br><code>Copy</code>复制选中的文字<br><code>Paste</code>粘贴通过Copy复制的文字<br><code>Paste from browser</code>允许你从浏览器外部粘贴内容到终端<br><code>Reset</code>清屏<br><code>Unicode</code>字符集，根据情况选择<br><code>Visual Bell</code>虚拟蜂鸣器，在输入异常时，屏幕闪烁<br><code>Onscreen Keyboard</code>屏幕键盘<br><code>Blinking Cursor</code>光标闪烁<br><code>Secure</code>是否安全模式，即是否采用https，下次登录有效<br><code>Black on White</code>白底黑字<br><code>White on Black</code>黑底白字<br><code>Color Terminal</code>彩色<br><code>Monochrome</code>黑白<br><code>About</code>一些版权信息</p><p>输入exit退出系统后，窗口并不会关闭，而是弹出一个“Connect”按钮，点击按钮再次登录。<br><img src="/img/Introduce-to-shellinabox/exit.png" alt="exit"></p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>shellinaboxd会启动一个web服务器，当请求到达时会调用login程序进行认证，认证通过后调用bash。多次登录，会启动多个login程序，通过pstree命令可以清晰的看到调用关系。<br><img src="/img/Introduce-to-shellinabox/theory.png" alt="theory"></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://github.com/shellinabox/shellinabox">shellinabox官网</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;img src=&quot;/img/Introduce-to-shellinabox/Terminal.png&quot; class=&quot;img-topic&quot; /&gt;

&lt;p&gt;通常情况下，我们访问Linux服务器时会使用Putty或者Xshell等SSH客户端工具，但这些工具均需要安装后才能使用，在安全要求不高（如局域网）或者只是开放服务器给其他人体验某种功能时，客户端这种方式略显繁琐。本文将介绍一款开源神器shellinabox，只需要浏览器就可以进行远程访问，相信用过它后，定会爱不释手。&lt;/p&gt;
    
    </summary>
    
      <category term="工具" scheme="http://supercoder.xyz/categories/tool/"/>
    
    
      <category term="Linux" scheme="http://supercoder.xyz/tags/Linux/"/>
    
      <category term="Web" scheme="http://supercoder.xyz/tags/Web/"/>
    
  </entry>
  
</feed>
