精华内容
下载资源
问答
  • 我为什么放弃Go语言

    万次阅读 多人点赞 2014-04-14 19:24:19
    我为什么放弃Go语言?有好几次,当我想起来的时候,总是会问自己:这个决定是正确的吗?是明智和理性的吗?其实我一直在认真思考这个问题。开门见山地说,我当初放弃Go语言,就是因为两个“不爽”:第一,对Go语言...

    我为什么放弃Go语言

    作者:庄晓立(Liigo)

    日期:2014年3月

    原创链接:http://blog.csdn.net/liigo/article/details/23699459

    转载请注明出处:http://blog.csdn.net/liigo

    有好几次,当我想起来的时候,总是会问自己:我为什么要放弃Go语言?这个决定是正确的吗?是明智和理性的吗?其实我一直在认真思考这个问题。

    开门见山地说,我当初放弃Go语言(golang),就是因为两个“不爽”:第一,对Go语言本身不爽;第二,对Go语言社区里的某些人不爽。毫无疑问,这是非常主观的结论。但是我有足够详实的客观的论据,用以支撑这个看似主观的结论。

    第-1节:更新日志(倒叙)

    Liigo 2021-07-13 补记14:今日HN热帖上大伙普遍吐槽channel,要用好真的很难。judofyr: "Channels are extremely subtle in my experience". laumars: "It took me a loooong time to fully wrap my head around channels. They’re definitely not explicit and full of subtle yet devastating bugs when used inappropriately (which is all to easy to do too)." 💡 另将本文更新日志从文末移至文首作为第-1节,并改为按日期倒叙排列。

    Liigo 2020-2-19 补记13:本文末尾增加Golang 2.0泛型相关信息。

    Liigo 2016-5-15 补记12:文中第2节(我为什么对Go社区的人不爽)增加netroby和D语言联合创始人的现身说法。补充说明Go 1.5后不再使用C语言开发。

    Liigo 2016-3-3 补记11:文中1.5节(垃圾回收器/GC)末尾增加一段,再次提示开发者重视Go语言GC的潜在问题。

    Liigo 2015-7-17 补记10:文中1.11节(泛型)增加来自HN的延伸阅读链接,开发者们抱怨Go欠缺泛型支持。

    Liigo 2015-7-3 补记9:文中1.5节(垃圾回收器/GC)增加 “Stop the world” 相关的三个链接。

    Liigo 2015-7-2 补记8:前两天网上出现了一篇本文的驳文,《驳狗屎文 "我为什么放弃Go语言"》,作者是chai2010,请读者们参照阅读,顺便领略一下本文后半部分描述过的Go粉的"风采"。(这篇驳文至少有两个好处:1 它全文引用了本文(便于读者参照);2 使用了本文当时的最新版(包含了补记7)。)

    Liigo 2015-6-2 补记7:补充两篇英文:Why Go Is Not Good(作者Will Yager重点批评了Go语言的设计不佳甚至是倒退),Leaving Go(作者Danny Gratzer放弃Go语言的原因主要是:没有泛型,充满黑魔法)。这两篇文章都是针对具体问题做具体分析的,与本文写作精神一致,务实不务虚。其中提到的对Go语言不满的地方,本文也多有涉及,结论类似。

    Liigo 2015-5-29 补记6:补充说明Go语言直到2015年下半年1.5发布后才将GOMAXPROCS设置为大于1的默认值(HN),他们文中承认之前一直默认设置为1是因为调度器不完善(与我此文最初发表时的猜测一致)。

    Liigo 2015-4-1 补记5:文中1.10(黑魔法)和1.12(接口)章节增加了两处“延伸阅读”链接,被引用的链接后面均有大量网友评论。此举主要是为了说明本文观点并非一家之言。

    Liigo 2015-1-31 补记4:全世界认为Go语言不好的可不只是我Liigo一个人。国外著名的问答网站Quora上面有个人气很高的提问,“为什么不要用Go语言”(英文网页),看看那排名最前的两个答案,以及广大程序员们给这两个答案的数百个“赞”,都足以说明Go语言自身的问题是客观存在的。人民群众的眼睛是雪亮的。

    Liigo 2014-4-29 补记3:Go语言的拥护者们,似乎连Go语言的“核心优势”都说不出几条。知乎上很有人气的一条问答《为什么要使用 Go 语言,Go 语言的优势在哪里》,连静态编译、GC、跨平台都拿出来说了(无视C/C++/Java),甚至连简单易学(无视Python/易语言)、“丰富的”标准库(跟谁比?敢跟Java/C#/Python比么?)、好用的工具链(gofmt)都扯出来了,可见除了“并发、网络”之外,他们也讲不出另外的什么核心优势了,只能靠一些周边的东西凑数。

    Liigo 2014-4-29 补记2:著名的编程语言研究专家王垠写了一篇《对 Go 语言的综合评价》(晚于本博文发表约三五天),也是总体上持批判态度,看衰Go语言。读者们可以对照阅读。

    Liigo 2014-4-29 补记1:Go语言社区还有一个很奇特的现象,就是中国社区独大,国外社区要小的多。有外国网友还专门写了一篇文章研究《为什么Golang中国社区独大》这个问题(文中也提到了我这篇博文)。通常来说,在IT和软件领域,向来都是国外先进国家引领技术潮流,然后国内缓慢跟进。而到了Go语言这里,恰恰反过来了,似乎暗示着在国外的主流软件开发技术人员并不怎么待见Go语言,Go只是在国内受到一帮人的盲目推崇而已,至于这帮人的眼光如何,反正我不看好。

    第0节:我的Go语言经历

    先说说我的经历吧,以避免被无缘无故地当作Go语言的低级黑。

    2009年底,Go语言(golang)第一个公开版本发布,笼罩着“Google公司制造”的光环,吸引了许多慕名而来的尝鲜者,我(Liigo)也身居其中,笼统的看了一些Go语言的资料,学习了基础的教程,因对其语法中的分号和花括号不满,很快就遗忘掉了,没拿它当一回事。

    两年之后,2011年底,Go语言发布1.0的计划被提上日程,相关的报道又多起来,我再次关注它,[重新评估][1]之后决定深入参与Go语言。我订阅了其users、nuts、dev、commits等官方邮件组,坚持每天阅读其中的电子邮件,以及开发者提交的每一次源代码更新,给Go提交了许多改进意见,甚至包括[修改Go语言编译器源代码][2]直接参与开发任务。如此持续了数月时间。

    到2012年初,Go 1.0发布,语言和标准库都已经基本定型,不可能再有大幅改进,我对Go语言未能在1.0定型之前更上一个台阶、实现自我突破,甚至带着诸多明显缺陷走向1.0,感到非常失望,因而逐渐疏远了它(所以Go 1.0之后的事情我很少关心)。后来看到即将发布的Go 1.1的Release Note,发现语言层面没有太大改变,只是在库和工具层面有所修补和改进,感到它尚在幼年就失去成长的动力,越发失望。外加Go语言社区里的某些人,其中也包括Google公司负责开发Go语言的某些人,其态度、言行,让我极度厌恶,促使我决绝地离弃Go语言。

    在上一个10年,我(Liigo)在我所属的公司里,深度参与了两个编程语言项目的开发。我想,对于如何判断某个编程语言的优劣,或者说至少对于如何判断某个编程语言是否适合于我自己,我应该还是有一点发言权的。

    [1]: https://plus.google.com/+LiigoZhuang/posts/CpRNPeDXUDW

    [2]: http://blog.csdn.net/liigo/article/details/7467309

    第1节:我为什么对Go语言不爽?

    Go语言有很多让我不爽之处,这里列出我现在还能记起的其中一部分,排名基本上不分先后。读者们耐心地看完之后,还能淡定地说一句“我不在乎”吗?

    1.1 不允许左花括号另起一行

    关于对花括号的摆放,在C语言、C++、Java、C#等社区中,十余年来存在持续争议,从未形成一致意见。在我看来,这本来就是主观倾向很重的抉择,不违反原则不涉及是非的情况下,不应该搞一刀切,让程序员或团队自己选择就足够了。编程语言本身强行限制,把自己的喜好强加给别人,得不偿失。无论倾向于其中任意一种,必然得罪与其对立的一群人。虽然我现在已经习惯了把左花括号放在行尾,但一想到被禁止其他选择,就感到十分不爽。Go语言这这个问题上,没有做到“团结一切可以团结的力量”不说,还有意给自己树敌,太失败了。

    1.2 编译器莫名其妙地给行尾加上分号

    对Go语言本身而言,行尾的分号是可以省略的。但是在其编译器(gc)的实现中,为了方便编译器开发者,却在词法分析阶段强行添加了行尾的分号,反过来又影响到语言规范,对“怎样添加分号”做出特殊规定。这种变态做法前无古人。在左花括号被意外放到下一行行首的情况下,它自动在上一行行尾添加的分号,会导致莫名其妙的编译错误(Go 1.0之前),连它自己都解释不明白。如果实在处理不好分号,干脆不要省略分号得了;或者,Scala和JavaScript的编译器是开源的,跟它们学学怎么处理省略行尾分号可以吗?

    1.3 极度强调编译速度,不惜放弃本应提供的功能

    程序员是人不是神,编码过程中免不了因为大意或疏忽犯一些错。其中有一些,是大家集体性的很容易就中招的错误(Go语言里的例子我暂时想不起来,C++里的例子有“基类析构函数不是虚函数”)。这时候编译器应该站出来,多做一些检查、约束、核对性工作,尽量阻止常规错误的发生,尽量不让有潜在错误的代码编译通过,必要时给出一些警告或提示,让程序员留意。编译器不就是机器么,不就是应该多做脏活累活杂活、减少人的心智负担么?编译器多做一项检查,可能会避免数十万程序员今后多年内无数次犯同样的错误,节省的时间不计其数,这是功德无量的好事。但是Go编译器的作者们可不这么想,他们不愿意自己多花几个小时给编译器增加新功能,觉得那是亏本,反而减慢了编译速度。他们以影响编译速度为由,拒绝了很多对编译器改进的要求。典型的因噎废食。强调编译速度固然值得赞赏,但如果因此放弃应有的功能,我不赞成。

    1.4 错误处理机制太原始

    在Go语言中处理错误的基本模式是:函数通常返回多个值,其中最后一个值是error类型,用于表示错误类型极其描述;调用者每次调用完一个函数,都需要检查这个error并进行相应的错误处理:if err != nil { /*这种代码写多了不想吐么*/ }。此模式跟C语言那种很原始的错误处理相比如出一辙,并无实质性改进。实际应用中很容易形成多层嵌套的if else语句,可以想一想这个编码场景:先判断文件是否存在,如果存在则打开文件,如果打开成功则读取文件,如果读取成功再写入一段数据,最后关闭文件,别忘了还要处理每一步骤中出现错误的情况,这代码写出来得有多变态、多丑陋?实践中普遍的做法是,判断操作出错后提前return,以避免多层花括号嵌套,但这么做的后果是,许多错误处理代码被放在前面突出的位置,常规的处理逻辑反而被掩埋到后面去了,代码可读性极差。而且,error对象的标准接口只能返回一个错误文本,有时候调用者为了区分不同的错误类型,甚至需要解析该文本。除此之外,你只能手工强制转换error类型到特定子类型(静态类型的优势没了)。至于panic - recover机制,致命的缺陷是不能跨越库的边界使用,注定是一个半成品,最多只能在自己的pkg里面玩一玩。Java的异常处理虽然也有自身的问题(比如Checked Exceptions),但总体上还是比Go的错误处理高明很多。

    1.5 垃圾回收器(GC)不完善、有重大缺陷

    在Go 1.0前夕,其垃圾回收器在32位环境下有内存泄漏,一直拖着不肯改进,这且不说。Go语言垃圾回收器真正致命的缺陷是,会导致整个进程不可预知的间歇性停顿(Stop the World)。像某些大型后台服务程序,如游戏服务器、APP容器等,由于占用内存巨大,其内存对象数量极多,GC完成一次回收周期,可能需要数秒甚至更长时间,这段时间内,整个服务进程是阻塞的、停顿的,在外界看来就是服务中断、无响应,再牛逼的并发机制到了这里统统失效。垃圾回收器定期启动,每次启动就导致短暂的服务中断,这样下去,还有人敢用吗?这可是后台服务器进程,是Go语言的重点应用领域。以上现象可不是我假设出来的,而是事实存在的现实问题,受其严重困扰的也不是一家两家了(2013年底ECUG Con 2013京东的刘奇提到了Go语言的GC、defer、标准库实现是性能杀手,最大的痛苦是GC;美团的沈锋也提到Go语言的GC导致后台服务间隔性停顿是最大的问题。更早的网络游戏仙侠道开发团队也曾受Go垃圾回收的沉重打击)。在实践中,你必须努力减少进程中的对象数量,以便把GC导致的间歇性停顿控制在可接受范围内。除此之外你别无选择(难道你还想自己更换GC算法、甚至砍掉GC?那还是Go语言吗?)。跳出圈外,我近期一直在思考,一定需要垃圾回收器吗?没有垃圾回收器就一定是历史的倒退吗?(可能会新写一篇博客文章专题探讨。)

    2016年3月3日Liigo补记:直到2015年底,Go 1.5新GC发布后数月,仍获知有大陆圈内知名团队因为GC的原因考虑换掉Go语言,颇有感触。当软件系统逐步发展到更庞大更复杂的时候,Go语言的垃圾回收器(GC)就变成了指不定啥时候会出现的拦路虎,让人进退两难。进,暂时没有确切有效的技术手段对付响应延迟和内存暴涨;退,多年开发付出的心血付之东流损失惨重。语言选型之前多做调查分析,如果一定要用Go语言开发,控制系统规模和复杂度,避开底层的核心业务,可能是比较明智的选择。

    1.6 禁止未使用变量和多余import

    Go编译器不允许存在被未被使用的变量和多余的import,如果存在,必然导致编译错误。但是现实情况是,在代码编写、重构、调试过程中,例如,临时性的注释掉一行代码,很容易就会导致同时出现未使用的变量和多余的import,直接编译错误了,你必须相应的把变量定义注释掉,再翻页回到文件首部把多余的import也注释掉,……等事情办完了,想把刚才注释的代码找回来,又要好几个麻烦的步骤。还有一个让人蛋疼的问题,编写数据库相关的代码时,如果你import某数据库驱动的pkg,它编译给你报错,说不需要import这个未被使用的pkg;但如果你听信编译器的话删掉该import,编译是通过了,运行时必然报错,说找不到数据库驱动;你看看程序员被折腾的两边不是人,最后不得不请出大神:`import _`。对待这种问题,一个比较好的解决方案是,视其为编译警告而非编译错误。但是Go语言开发者很固执,不容许这种折中方案。

    1.7 创建对象的方式太多令人纠结

    创建对象的方式,调用new函数、调用make函数、调用New方法、使用花括号语法直接初始化结构体,你选哪一种?不好选择,因为没有一个固定的模式。从实践中看,如果要创建一个语言内置类型(如channel、map)的对象,通常用make函数创建;如果要创建标准库或第三方库定义的类型的对象,首先要去文档里找一下有没有New方法,如果有就最好调用New方法创建对象,如果没有New方法,则退而求其次,用初始化结构体的方式创建其对象。这个过程颇为周折,不像C++、Java、C#那样直接new就行了。

    1.8 对象没有构造函数和析构函数

    没有构造函数还好说,毕竟还有自定义的New方法,大致也算是构造函数了。没有析构函数就比较难受了,没法实现RAII。额外的人工处理资源清理工作,无疑加重了程序员的心智负担。没人性啊,还嫌我们程序员加班还少吗?C++里有析构函数,Java里虽然没有析构函数但是有人家finally语句啊,Go呢,什么都没有。没错,你有个defer,可是那个defer问题更大,详见下文吧。

    1.9 defer语句的语义设定不甚合理

    Go语言设计defer语句的出发点是好的,把释放资源的“代码”放在靠近创建资源的地方,但把释放资源的“动作”推迟(defer)到函数返回前执行。遗憾的是其执行时机的设置似乎有些不甚合理。设想有一个需要长期运行的函数,其中有无限循环语句,在循环体内不断的创建资源(或分配内存),并用defer语句确保释放。由于函数一直运行没有返回,所有defer语句都得不到执行,循环过程中创建的大量短暂性资源一直积累着,得不到回收。而且,系统为了存储defer列表还要额外占用资源,也是持续增加的。这样下去,过不了多久,整个系统就要因为资源耗尽而崩溃。像这类长期运行的函数,http.ListenAndServe()就是典型的例子。在Go语言重点应用领域,可以说几乎每一个后台服务程序都必然有这么一类函数,往往还都是程序的核心部分。如果程序员不小心在这些函数中使用了defer语句,可以说后患无穷。如果语言设计者把defer的语义设定为在所属代码块结束时(而非函数返回时)执行,是不是更好一点呢?可是Go 1.0早已发布定型,为了保持向后兼容性,已经不可能改变了。小心使用defer语句!一不小心就中招。

    1.10 许多语言内置设施不支持用户定义的类型

    for in、make、range、channel、map等都仅支持语言内置类型,不支持用户定义的类型(?)。用户定义的类型没法支持for in循环,用户不能编写像make、range那样“参数类型和个数”甚至“返回值类型和个数”都可变的函数,不能编写像channel、map那样类似泛型的数据类型。语言内置的那些东西,处处充斥着斧凿的痕迹。这体现了语言设计的局限性、封闭性、不完善,可扩展性差,像是新手作品——且不论其设计者和实现者如何权威。延伸阅读:Go语言是30年前的陈旧设计思想,用户定义的东西几乎都是二等公民(Tikhon Jelvis)。

    1.11 没有泛型支持,常见数据类型接口丑陋

    没有泛型的话,List、Set、Tree这些常见的基础性数据类型的接口就只能很丑陋:放进去的对象是一个具体的类型,取出来之后成了无类型的interface{}(可以视为所有类型的基础类型),还得强制类型转换之后才能继续使用,令人无语。Go语言缺少min、max这类函数,求数值绝对值的函数abs只接收/返回双精度小数类型,排序接口只能借助sort.Interface无奈的回避了被比较对象的类型,等等等等,都是没有泛型导致的结果。没有泛型,接口很难优雅起来。Go开发者没有明确拒绝泛型,只是说还没有找到很好的方法实现泛型(能不能学学已经开源的语言呀)。现实是,Go 1.0已经定型,泛型还没有,那些丑陋的接口为了保持向后兼容必须长期存在着。延伸阅读:HN网友抱怨Go没有泛型

    1.12 实现接口不需要明确声明

    这一条通常是被当作Go语言的优点来宣传的。但是也有人不赞同,比如我。如果一个类型用Go语言的方式默默的实现了某个接口,使用者和代码维护者都很难发现这一点(除非仔细核对该类型的每一个方法的函数签名,并跟所有可能的接口定义相互对照),自然也想不到与该接口有关的应用,显得十分隐晦,不直观。支持者可能会辩解说,我可以在文档中注明它实现了哪些接口。问题是,写在文档中,还不如直接写到类型定义上呢,至少还能得到编译器的静态类型检查。缺少了编译器的支持,当接口类型的函数签名被改变时,当实现该接口的类型方法被无意中改变时,实现者可能很难意识到,该类型实现该接口的隐含约束事实上已经被打破了。又有人辩解说,我可以通过单元测试确保类型正确实现了接口呀。我想说的是,明明可以通过明确声明实现接口,享受编译器提供的类型检查,你却要自己找麻烦,去写原本多余的单元测试,找虐很爽吗?Go语言的这种做法,除了减少一些对接口所在库的依赖之外,没有其他好处,得不偿失。延伸阅读:为什么我不喜欢Go语言式的接口(老赵)。

    1.13 省掉小括号却省不掉花括号

    Go语言里面的if语句,其条件表达式不需要用小括号扩起来,这被作为“代码比较简洁”的证据来宣传。可是,你省掉了小括号,却不能省掉大括号啊,一条完整的if语句至少还得三行吧,人家C、C++、Java都可以在一行之内搞定的(可以省掉花括号)。人家还有x?a:b表达式呢,也是一行搞定,你Go语言用if else写至少得五行吧?哪里简洁了?

    1.14 编译生成的可执行文件尺寸非常大

    记得当年我写了一个很简单的程序,把所有系统环境变量的名称和值输出到控制台,核心代码也就那么三五行,结果编译出来把我吓坏了:EXE文件的大小超过4MB。如果是C语言写的同样功能的程序,0.04MB都是多的。我把这个信息反馈到官方社区,结果人家不在乎。是,我知道现在的硬盘容量都数百GB、上TB了……可您这种优化程度……怎么让我相信您在其他地方也能做到不错呢。(再次强调一遍,我所有的经验和数据都来自Go 1.0发布前夕。)

    1.15 不支持动态加载类库

    静态编译的程序当然是很好的,没有额外的运行时依赖,部署时很方便。但是之前我们说了,静态编译的文件尺寸很大。如果一个软件系统由多个可执行程序构成,累加起来就很可观。如果用动态编译,发布时带同一套动态库,可以节省很多容量。更关键的是,动态库可以运行时加载和卸载,这是静态库做不到的。还有那些LGPL等协议的第三方C库受版权限制是不允许静态编译的。至于动态库的版本管理难题,可以通过给动态库内的所有符号添加版本号解决。无论如何,应该给予程序员选择权,让他们自己决定使用静态库还是动态库。一刀切的拒绝动态编译是不合适的。

    1.16 其他

    • 不支持方法和函数重载(overload)
    • 导入pkg的import语句后边部分竟然是文本(import ”fmt”)
    • 没有enum类型,全局性常量难以分类,iota把简单的事情复杂化
    • 定义对象方法时,receiver类型应该选用指针还是非指针让人纠结
    • 定义结构体和接口的语法稍繁,interface XXX{} struct YYY{} 不是更简洁吗?前面加上type关键字显得罗嗦。
    • 测试类库testing里面没有AssertEqual函数,标准库的单元测试代码中充斥着if a != b { t.Fatal(...) }
    • 语言太简单,以至于不得不放弃很多有用的特性,“保持语言简单”往往成为拒绝改进的理由。
    • 标准库的实现总体来说不甚理想,其代码质量大概处于“基本可用”的程度,真正到企业级应用领域,往往就会暴露出诸多不足之处。
    • 版本都发展到1.2了,goroutine调度器依旧默认仅使用一个系统线程。GOMAXPROCS的长期存在似乎暗示着官方从来没有足够的信心,让调度器正确安全地运行在多核环境中。这跟Go语言自身以并发为核心的定位有致命的矛盾。(直到2015年下半年1.5发布后才有改观
    • 官方发行版中包含了一个叫oracle的辅助程序,与Oracle数据库毫无关系,却完全无视两者之间的名称混淆。

    上面列出的是我目前还能想到的对Go语言的不爽之处,毕竟时间过去两年多,还有一些早就遗忘了。其中一部分固然是小不爽,可能忍一忍就过去了,但是很多不爽积累起来,总会时不时地让人难受,时间久了有自虐的感觉。程序员的工作生活本来就够枯燥的,何必呢。

    必须要说的是,对于其中大多数不爽之处,我(Liigo)都曾经试图改变过它们:在Go 1.0版本发布之前,我在其官方邮件组提过很多意见和建议(甚至包括提交代码CL),极力据理力争,可以说付出很大努力,目的就是希望定型后的Go语言是一个相对完善的、没有明显缺陷的编程语言。结果是令人失望的,我人微言轻、势单力薄,不可能影响整个语言的发展走向。1.0之前,最佳的否定自我、超越自我的机会,就这么遗憾地错过了。我最终发现,很多时候不是技术问题,而是技术人员的问题。

    第2节:我为什么对Go语言的某些人不爽?

    这里提到的“某些人”主要是两类:一、负责专职开发Go语言的Google公司员工;二、Go语言的推崇者和脑残粉丝。我跟这两类人打过很多交道,不胜其烦。再次强调一遍,我指的是“某些”人,而不是所有人,请不要对号入座。

    Google公司内部负责专职开发Go语言的核心开发组某些成员,他们倾向于闭门造车,固执己见,对第三方提出的建议不重视。他们常常挂在嘴边的口头禅是:现有的做法很好、不需要那个功能、我们开发Go语言是给Google自己用的、Google不需要那个功能、如果你一定要改请fork之后自己改、别干提意见请提交代码。很多言行都是“反开源”的。通过一些具体的例子,还能更形象的看清这一层。就留下作为课后作业吧。

    我最不能接受的就是他们对1.0版本的散漫处理。那时候Go还没到1.0,初出茅庐的小学生,有很大的改进空间,是全面翻新的最佳时机,彼时不改更待何时?1.0是打地基的版本,基础不牢靠,等1.0定型之后,处处受到向后兼容性的牵制,束手缚脚,每前进一步都阻力重重。急于发布1.0,过早定型,留下诸多遗憾,彰显了开发者的功利性强,在技术上不追求尽善尽美。

    Go语言的核心开发成员,他们日常的开发工作是使用C语言——Go语言的编译器和运行时库,包括语言核心数据结构和算法map、channel、scheduler,都是C开发的——真正用自己开发的Go语言进行实际的大型应用开发的机会并不多。虽然标准库是用Go语言自己写的,但他们却没有大范围使用标准库的经历。实际上,他们缺少使用Go语言的实战开发经验,往往不知道处于开发第一线的用户真正需要什么,无法做到设身处地为程序员着想。缺少使用Go语言的亲身经历,也意味着他们不能在日常开发中,及时发现和改进Go语言的不足。这也是他们往往自我感觉良好的原因。(2016年5月15日补记:2015年8月Go 1.5版本之后不再使用C语言开发。)

    Go语言社区里,有一大批Go语言的推崇者和脑残粉丝,他们满足于现状,不思进取,处处维护心中的“神”,容不得批评意见,不支持对语言的改进要求。当年我对Go语言的很多批评和改进意见,极少得到他们的支持,他们不但不支持还给予打击,我就纳闷了,他们难道不希望Go语言更完善、更优秀吗?我后来才意识到,他们跟乔帮主的苹果脑残粉丝们,言行一脉相承,具有极端宗教倾向,神化主子、打击异己真是不遗余力呀。简简单单的技术问题,就能被他们上升到意识形态之争。现实的例子是蛮多的,有兴趣的到网上去找吧。正是因为他们的存在,导致更多理智、清醒的Go语言用户无法真正融入整个社区。

    如果一个项目、团队、社区,到处充斥着赞美、孤芳自赏、自我满足、不思进取,排斥不同意见,拒绝接纳新方案,我想不到它还有什么前进的动力。逆水行舟,是不进反退的。

    2016年5月15日补记:@netroby:“Golang社区的神经病和固执,我深有体会。我曾经发过Issue,请求Golang官方,能为doc加上高亮,这样浏览器阅读文档的时候,能快速阅读代码参考。但是被各种拒绝. 他们的理由是很多开发者不喜欢高亮。” https://github.com/golang/go/issues/13178

    2016年5月15日补记:C++天才人物、D语言联合创始人Andrei Alexandrescu:“Go所走的路线在一些问题上持有极其强硬和死板态度,这些问题有大有小。在比较大的方面,泛型编程被严格控制,甚至贬低到只有"N"个字;有关泛型编程的讨论都是试图去劝阻任何有意义的尝试,这已经足够让人觉得耻辱。从长远来看,技术问题的政治化是一种极其有害的模式,所以希望Go社区能够找到修正它的方法。”  http://www.csdn.net/article/2015-12-20/2826517

    第3节:还有比Go语言更好的选择吗?

    我始终坚持一个颇有辩证法意味的哲学观点:在更好的替代品出现之前,现有的就是最好的。失望是没有用的,抱怨是没有用的,要么接受,要么逃离。我曾经努力尝试过接受Go语言,失败之后,注定要逃离。发现更好的替代品之后,无疑加速了逃离过程。还有比Go语言更好的替代品吗?当然有。作为一个屌丝程序员,我应该告诉你它是什么,但是我不说。现在还不是时候。我现在不想把这两门编程语言对立起来,引发另一场潜在的语言战争。这不是此文的本意。如果你非要从现有信息中推测它是什么,那完全是你自己的事。如果你原意等,它或许很快会浮出水面,也未可知。

    第4节:写在最后

    我不原意被别人代表,也不愿意代表别人。这篇文章写的是我,一个叫Liigo的80后屌丝程序员,自己的观点。你完全可以主观地认为它是主观的,也完全可以客观地以为它是客观的,无论如何,那是你的观点。

    这篇文字是从记忆里收拾出来的。有些细节虽可考,而不值得考。——我早已逃离,不愿再回到当年的场景。文中涉及的某些细节,可能会因为些许偏差,影响其准确性;也可能会因为缺少出处,影响其客观性。如果有人较真,非要去核实,我相信那些东西应该还在那里。

    Go语言也非上文所述一无是处,它当然有它的优势和特色。读者们判断一件事物,应该是优劣并陈,做综合分析,不能单听我一家负面之言。但是它的那些不爽之处,始终让我不爽,且不能从其优秀处得以完全中和,这是我不得不放弃它的原因。


    关于对作者倾向性质疑的声明

    读者看到本文全都是Go语言负面性的内容,没有涉及一点Go语言好的地方,因而质疑作者的盲目倾向。出现这种结果完全是因为文章主题所限。此前本文末尾也简单提到过,评估一件事物,应当优劣并陈,优势项加分,劣势项减分,做综合评估分析。如果有突出的重大优势,则可以容忍一些较大的劣势;但如果有致命的劣势或多项大劣势,则再大的优势也无法与之中和。中国乒乓球界讲领军人物必须做到“技术全面,特长突出,没有明显弱点”,我甚为赞同。用这句话套用Go语言,可以说“技术不全面(人家自己说成简洁),有一点特长(并发),有明显的弱点(包括但不限于本文列出的这些)”。如此一来,优势都被劣势中和了,劣势还是那么突出,自然是得负分,自然是弃用,自然是没有好印象。我在这里可以说观点鲜明、态度明确,不和稀泥。与其看那些盲目推崇Go语言的人和文章,笼统的说“好”,不如也顺便看看本文,具体到细节地说“不好”。凡是具体到细节的东西,都是容易证实或证伪的,比笼统的东西(无论是"黑"还是"粉")可信性更高一些。

    关于对作者阴谋论的声明

    有某些阴谋论者(例如谢某),说我因一个Pull Request被Go开发者拒绝而“怀恨至今”,暗示此文是故意报复、抹黑Go语言。我对Golang有恨吗?当然是有的,那是一个不爽接一个不爽(如本文一一罗列的那些),逐步累积,由量变形成质变的结果,是我对Golang综合客观评估之后的主观态度,并非由哪一个单独的事件所主导。要说Pull Request被拒绝,Rust开发者拒绝我的PR次数还少吗?比如 https://github.com/mozilla/rust/pull/13014 和 https://github.com/liigo/rust/tree/xp (https://github.com/rust-lang/rust/issues/12842),要是再算上被拒的Issues,那就多的数不清了。我显然不可能因为某些个别的事件,影响到我对某个事物的综合评估(参见前文)。那本文是“故意抹黑”Go语言吗?我觉得不是,理由有二:1、这是作者的主观感受,2、这些感受是以许多客观事实为基础的。如果本文一一列出的那些现象,是不存在的,是虚构出来的,是凭空生成的,那么作者一定是“低级黑”。问题是,那些都是客观存在的事实。把事实说出来,怎么能叫“黑”呢?欢迎读者客观而详细的指正本文中的所有错误。

    关于Golang 2.0的泛型

    今天(2020年2月19日)看到HN的一篇关于 Go2 Generics 的讨论。有网友说到:

    Ken Thompson and Rob Pike are mostly out not at all involved with Go anymore. They are 2/3 of the original creators. It’s different people making the decisions now.

    我找到如下两个链接基本证实了Rob Pike确实已经淡出Golang的核心开发组:

    Rob Pike最近两年仅提交了4k行无关紧要的代码;Ken Thompson就更不用说了,许多年前就已经淡出;Russ Cox似乎也不太参与Go2相关的决策。如此看来,对于Go2的泛型而言,非技术方面的障碍已不存在,剩下只是技术性障碍。

    Ian Lance Taylor 上周(2020年2月13日)说到

    We're working on it. Some things take time.

    展开全文
  • 形象化的表达数据

    千次阅读 2009-09-26 15:00:00
    在实际数据应用中,涉及的范围比较大,特别是许多的实验,其目的和实验环境各不相同,为了能形象化的表达这些实验数据,增强实验数据的可视化程度和渲染力,总是希望能用接近实物的方式来表达这些数据。采用计算机...

        在实际数据应用中,涉及的范围比较大,特别是许多的实验,其目的和实验环境各不相同,为了能形象化的表达这些实验数据,增强实验数据的可视化程度和渲染力,总是希望能用接近实物的方式来表达这些数据。采用计算机数据图形软件活图(中文版活图ver8.1现在是常州微识自动化科技有限公司产品之一http://www.microverify.com/col.jsp?id=114可以很好的完成这一工作。但要想选择一个和实验物相似的图形来显示相关的实验数据并不是很容易的,虽然已经发展了这么多年。笔者在过去的应用开发过程中,对某些可以按照实验环境归类的数据的表现方式,开发了相应的数据可视化应用图,即按照陆地、空中和水中的实验参照物以简单的汽车、飞机和艇类来代表之,形象地将其表现出来。所开发的是一组简单的二维图形,不管是汽车还是飞机或艇类,根据实验的要求,可以用实验物的首尾坐标作为数据输入,也可以以实验物的中心坐标和倾角作为数据输入,由自己选择数据表达方式。用首尾数据方式的用应用图动轨迹1,用中心坐标和倾角的,用应用图动轨迹2。每个应用图中,用一个参数来切换陆﹑海﹑空。除了静态表现实验数据外,可以动态表现实验数据,可以选择动态表演的次数和速度,可以缺省表现数据间隔数。这种表现方式,在应用中,一般情况下,无须编程,只要把实验数据组的数据输入到数值窗口内,然后调整图形表达参数就行。

        图1(陆),图2(海)和图3(空)是首尾表现的动轨迹1的界面,图4(陆),图5(海)和图6(空)是中心坐标和倾角表现的动轨迹2的界面。自然的,在数式窗口内可以对实验数据进行各种计算,然后再表达之。

     

                           图1

     

     

                               图2

     

     

                        图3

     

                          图4

     

                                    图5

     

     

                                              图6

     

    展开全文
  • 自然语言处理中的Attention Model:是什么及为什么

    万次阅读 多人点赞 2016-01-20 18:26:02
    让我们来直观地体会一下什么是人脑中的注意力模型。首先,请您睁开眼并确认自己处于意识清醒状态;第二步,请找到本文最近出现的一个“Attention Model”字眼(就是“字眼”前面的两个英文单词,…^@@^)并盯住看三...

     

    /* 版权声明:可以任意转载,转载时请标明文章原始出处和作者信息 .*/

     

                                                         author: 张俊林      

     

                                             (想更系统地学习深度学习知识?请参考:深度学习枕边书

    要是关注深度学习在自然语言处理方面的研究进展,我相信你一定听说过Attention Model(后文有时会简称AM模型)这个词。AM模型应该说是过去一年来NLP领域中的重要进展之一,在很多场景被证明有效。听起来AM很高大上,其实它的基本思想是相当直观简洁的。本文作者可以对灯发誓:在你读完这篇啰里啰嗦的文章及其后续文章后,一定可以透彻了解AM到底是什么,以及轻易看懂任何有关论文看上去复杂的数学公式部分。怎么样,这广告打的挺有吸引力吧,尤其是对那些患有数学公式帕金森病的患者。

     

    在正戏开演前,我们先来点题外话。

     

    |引言及废话

     

    你应该常常听到被捉奸在床的男性经常感叹地说一句话:女性的第六感通常都很准,当然这里的女性一般是特指这位男性的老婆或者女友,当然也可能是他的某位具有女性气质的男友。要我说,男人的第六感其实也不差(这里的“男人”特指本文作者本人,当然非上文所引用的“男性”,为避免混淆特做声明)。当我第一次看到机器学习领域中的Attention Model这个名字的时候,我的第一直觉就是:这是从认知心理学里面的人脑注意力模型引入的概念。若干年前,也就是在我年轻不懂事的花样年华里,曾有一阵子沉迷于人脑的工作机制,大量阅读了认知心理学方面的书籍和论文,而一般注意力模型会作为书籍的单独一章来讲。下面请允许我显摆一下鄙人渊博的知识。

     

    注意力这东西其实挺有意思,但是很容易被人忽略。让我们来直观地体会一下什么是人脑中的注意力模型。首先,请您睁开眼并确认自己处于意识清醒状态;第二步,请找到本文最近出现的一个“Attention Model”字眼(就是“字眼”前面的两个英文单词,…^@@^)并盯住看三秒钟。好,假设此刻时间停止,在这三秒钟你眼中和脑中看到的是什么?对了,就是“Attention Model”这两个词,但是你应该意识到,其实你眼中是有除了这两个单词外的整个一副画面的,但是在你盯着看的这三秒钟,时间静止,万物无息,仿佛这个世界只有我和你…..对不起,串景了,仿佛这个世界只有“Attention Model”这两个单词。这是什么?这就是人脑的注意力模型,就是说你看到了整幅画面,但在特定的时刻t,你的意识和注意力的焦点是集中在画面中的某一个部分上,其它部分虽然还在你的眼中,但是你分配给它们的注意力资源是很少的。其实,只要你睁着眼,注意力模型就无时不刻在你身上发挥作用,比如你过马路,其实你的注意力会被更多地分配给红绿灯和来往的车辆上,虽然此时你看到了整个世界;比如你很精心地偶遇到了你心仪的异性,此刻你的注意力会更多的分配在此时神光四射的异性身上,虽然此刻你看到了整个世界,但是它们对你来说跟不存在是一样的…..

     

    这就是人脑的注意力模型,说到底是一种资源分配模型,在某个特定时刻,你的注意力总是集中在画面中的某个焦点部分,而对其它部分视而不见。

     

    其实吧,深度学习里面的注意力模型工作机制啊,它跟你看见心动异性时荷尔蒙驱动的注意力分配机制是一样一样的。

     

    好,前戏结束,正戏开场。


    |Encoder-Decoder框架

     

    本文只谈谈文本处理领域的AM模型,在图片处理或者(图片-图片标题)生成等任务中也有很多场景会应用AM模型,但是我们此处只谈文本领域的AM模型,其实图片领域AM的机制也是相同的。

     

     

    要提文本处理领域的AM模型,就不得不先谈Encoder-Decoder框架,因为目前绝大多数文献中出现的AM模型是附着在Encoder-Decoder框架下的,当然,其实AM模型可以看作一种通用的思想,本身并不依赖于Encoder-Decoder模型,这点需要注意。

     

     

    Encoder-Decoder框架可以看作是一种文本处理领域的研究模式,应用场景异常广泛,本身就值得非常细致地谈一下,但是因为本文的注意力焦点在AM模型,所以此处我们就只谈一些不得不谈的内容,详细的Encoder-Decoder模型以后考虑专文介绍。下图是文本处理领域里常用的Encoder-Decoder框架最抽象的一种表示:

                                                             

    图1. 抽象的Encoder-Decoder框架

     

    Encoder-Decoder框架可以这么直观地去理解:可以把它看作适合处理由一个句子(或篇章)生成另外一个句子(或篇章)的通用处理模型。对于句子对<X,Y>,我们的目标是给定输入句子X,期待通过Encoder-Decoder框架来生成目标句子Y。X和Y可以是同一种语言,也可以是两种不同的语言。而X和Y分别由各自的单词序列构成:

     

    Encoder顾名思义就是对输入句子X进行编码,将输入句子通过非线性变换转化为中间语义表示C

     

                                                               

     

    对于解码器Decoder来说,其任务是根据句子X的中间语义表示C和之前已经生成的历史信息y1,y2….yi-1来生成i时刻要生成的单词yi 

                                                                  

     

     

    每个yi都依次这么产生,那么看起来就是整个系统根据输入句子X生成了目标句子Y。

     

    Encoder-Decoder是个非常通用的计算框架,至于Encoder和Decoder具体使用什么模型都是由研究者自己定的,常见的比如CNN/RNN/BiRNN/GRU/LSTM/Deep LSTM等,这里的变化组合非常多,而很可能一种新的组合就能攒篇论文,所以有时候科研里的创新就是这么简单。比如我用CNN作为Encoder,用RNN作为Decoder,你用BiRNN做为Encoder,用深层LSTM作为Decoder,那么就是一个创新。所以正准备跳楼的憋着劲想攒论文毕业的同学可以从天台下来了,当然是走下来,不是让你跳下来,你可以好好琢磨一下这个模型,把各种排列组合都试试,只要你能提出一种新的组合并被证明有效,那恭喜你:施主,你可以毕业了。

     

    扯远了,再拉回来。

     

    Encoder-Decoder是个创新游戏大杀器,一方面如上所述,可以搞各种不同的模型组合,另外一方面它的应用场景多得不得了,比如对于机器翻译来说,<X,Y>就是对应不同语言的句子,比如X是英语句子,Y是对应的中文句子翻译。再比如对于文本摘要来说,X就是一篇文章,Y就是对应的摘要;再比如对于对话机器人来说,X就是某人的一句话,Y就是对话机器人的应答;再比如……总之,太多了。哎,那位施主,听老衲的话,赶紧从天台下来吧,无数创新在等着你发掘呢。

     

    |Attention Model

     

    图1中展示的Encoder-Decoder模型是没有体现出“注意力模型”的,所以可以把它看作是注意力不集中的分心模型。为什么说它注意力不集中呢?请观察下目标句子Y中每个单词的生成过程如下:

                                              

     

     

    其中f是decoder的非线性变换函数。从这里可以看出,在生成目标句子的单词时,不论生成哪个单词,是y1,y2也好,还是y3也好,他们使用的句子X的语义编码C都是一样的,没有任何区别。而语义编码C是由句子X的每个单词经过Encoder 编码产生的,这意味着不论是生成哪个单词,y1,y2还是y3,其实句子X中任意单词对生成某个目标单词yi来说影响力都是相同的,没有任何区别(其实如果Encoder是RNN的话,理论上越是后输入的单词影响越大,并非等权的,估计这也是为何Google提出Sequence to Sequence模型时发现把输入句子逆序输入做翻译效果会更好的小Trick的原因)。这就是为何说这个模型没有体现出注意力的缘由。这类似于你看到眼前的画面,但是没有注意焦点一样。如果拿机器翻译来解释这个分心模型的Encoder-Decoder框架更好理解,比如输入的是英文句子:Tom chase Jerry,Encoder-Decoder框架逐步生成中文单词:“汤姆”,“追逐”,“杰瑞”。在翻译“杰瑞”这个中文单词的时候,分心模型里面的每个英文单词对于翻译目标单词“杰瑞”贡献是相同的,很明显这里不太合理,显然“Jerry”对于翻译成“杰瑞”更重要,但是分心模型是无法体现这一点的,这就是为何说它没有引入注意力的原因。没有引入注意力的模型在输入句子比较短的时候估计问题不大,但是如果输入句子比较长,此时所有语义完全通过一个中间语义向量来表示,单词自身的信息已经消失,可想而知会丢失很多细节信息,这也是为何要引入注意力模型的重要原因。

     

    上面的例子中,如果引入AM模型的话,应该在翻译“杰瑞”的时候,体现出英文单词对于翻译当前中文单词不同的影响程度,比如给出类似下面一个概率分布值:

     

    (Tom,0.3)(Chase,0.2)(Jerry,0.5)

     

    每个英文单词的概率代表了翻译当前单词“杰瑞”时,注意力分配模型分配给不同英文单词的注意力大小。这对于正确翻译目标语单词肯定是有帮助的,因为引入了新的信息。同理,目标句子中的每个单词都应该学会其对应的源语句子中单词的注意力分配概率信息。这意味着在生成每个单词Yi的时候,原先都是相同的中间语义表示C会替换成根据当前生成单词而不断变化的Ci。理解AM模型的关键就是这里,即由固定的中间语义表示C换成了根据当前输出单词来调整成加入注意力模型的变化的Ci。增加了AM模型的Encoder-Decoder框架理解起来如图2所示。

      

                                                 2 引入AM模型的Encoder-Decoder框架

    即生成目标句子单词的过程成了下面的形式:

                                                  

     

    而每个Ci可能对应着不同的源语句子单词的注意力分配概率分布,比如对于上面的英汉翻译来说,其对应的信息可能如下:

                         

     

    其中,f2函数代表Encoder对输入英文单词的某种变换函数,比如如果Encoder是用的RNN模型的话,这个f2函数的结果往往是某个时刻输入xi后隐层节点的状态值;g代表Encoder根据单词的中间表示合成整个句子中间语义表示的变换函数,一般的做法中,g函数就是对构成元素加权求和,也就是常常在论文里看到的下列公式:

     

                                              

     

    假设Ci中那个i就是上面的“汤姆”,那么Tx就是3,代表输入句子的长度,h1=f(“Tom”)h2=f(“Chase”),h3=f(“Jerry”),对应的注意力模型权值分别是0.6,0.2,0.2,所以g函数就是个加权求和函数。如果形象表示的话,翻译中文单词“汤姆”的时候,数学公式对应的中间语义表示Ci的形成过程类似下图:

             

                                           

                                                                             3 Ci的形成过程

     

     

    这里还有一个问题:生成目标句子某个单词,比如“汤姆”的时候,你怎么知道AM模型所需要的输入句子单词注意力分配概率分布值呢?就是说“汤姆”对应的概率分布:

     

    (Tom,0.6)(Chase,0.2)(Jerry,0.2)

     

    是如何得到的呢?

     

    为了便于说明,我们假设对图1的非AM模型的Encoder-Decoder框架进行细化,Encoder采用RNN模型,Decoder也采用RNN模型,这是比较常见的一种模型配置,则图1的图转换为下图:

                                                                           4 RNN作为具体模型的Encoder-Decoder框架

     

    那么用下图可以较为便捷地说明注意力分配概率分布值的通用计算过程:

     

                                        

                                                                                    5 AM注意力分配概率计算

     

     

    对于采用RNN的Decoder来说,如果要生成yi单词,在时刻i,我们是可以知道在生成Yi之前的隐层节点i时刻的输出值Hi的,而我们的目的是要计算生成Yi时的输入句子单词“Tom”、“Chase”、“Jerry”对Yi来说的注意力分配概率分布,那么可以用i时刻的隐层节点状态Hi去一一和输入句子中每个单词对应的RNN隐层节点状态hj进行对比,即通过函数F(hj,Hi)来获得目标单词Yi和每个输入单词对应的对齐可能性,这个F函数在不同论文里可能会采取不同的方法,然后函数F的输出经过Softmax进行归一化就得到了符合概率分布取值区间的注意力分配概率分布数值。图5显示的是当输出单词为“汤姆”时刻对应的输入句子单词的对齐概率。绝大多数AM模型都是采取上述的计算框架来计算注意力分配概率分布信息,区别只是在F的定义上可能有所不同。

     

    上述内容就是论文里面常常提到的Soft Attention Model的基本思想,你能在文献里面看到的大多数AM模型基本就是这个模型,区别很可能只是把这个模型用来解决不同的应用问题。那么怎么理解AM模型的物理含义呢?一般文献里会把AM模型看作是单词对齐模型,这是非常有道理的。目标句子生成的每个单词对应输入句子单词的概率分布可以理解为输入句子单词和这个目标生成单词的对齐概率,这在机器翻译语境下是非常直观的:传统的统计机器翻译一般在做的过程中会专门有一个短语对齐的步骤,而注意力模型其实起的是相同的作用。在其他应用里面把AM模型理解成输入句子和目标句子单词之间的对齐概率也是很顺畅的想法。

     

    当然,我觉得从概念上理解的话,把AM模型理解成影响力模型也是合理的,就是说生成目标单词的时候,输入句子每个单词对于生成这个单词有多大的影响程度。这种想法也是比较好理解AM模型物理意义的一种思维方式。

     

    图6是论文“A Neural Attention Model for Sentence Summarization”中,Rush用AM模型来做生成式摘要给出的一个AM的一个非常直观的例子。

                               

                                                               6 句子生成式摘要例子

     

     

    这个例子中,Encoder-Decoder框架的输入句子是:“russian defense minister ivanov called sunday for the creation of a joint front for combating global terrorism”。对应图中纵坐标的句子。系统生成的摘要句子是:“russia calls for joint front against terrorism”,对应图中横坐标的句子。可以看出模型已经把句子主体部分正确地抽出来了。矩阵中每一列代表生成的目标单词对应输入句子每个单词的AM分配概率,颜色越深代表分配到的概率越大。这个例子对于直观理解AM是很有帮助作用的。

    最后是广告:关于AM,我们除了本文,下周还会有续集:从AM来谈谈两种科研创新模式,请不要转台,继续关注,谢谢。

    这是2017年的新版本,抽象出了attention的本质及介绍了self attention等新模式:深度学习中的注意力机制(2017版)

     

     

    扫一扫关注微信号:“布洛卡区” ,深度学习在自然语言处理等智能应用的技术研讨与科普公众号。

     

    展开全文
  • STP协议的形象化理解-一点感慨

    千次阅读 2012-10-27 21:56:26
     如果能把一个技术问题完全用通俗的文字表述出来,那就再好不过了,我一直都很崇拜那些科普书籍的作者,他们能把最深奥的问题用通俗的语言表述。于是我也试试。  STP是一个很烦人的协议 ,Cisco的 RSTP也一样,...
    公司近期针对新员工以及对主题感兴趣的员工有针对性地进行了一系列的技术培训,我有幸成为了一名讲师,这也是太抬举我了,仅仅因为我年龄稍微有些老(虽然还不到而立之年),另外进公司时间也有些历史(虽然也仅仅3年不到)...我技术上不是最牛的,对待工作的态度也不是最优的,拥有的仅仅是对事情刨根问底的态度以及对任何事情背后背景的兴趣,这也许正是一名研究者和讲师所必须具备的,我真的有点后悔自己为何没有向老婆看齐,去做一名人民教师...
        培训进行了有几次了,我的主题大多集中在我比较精通的领域,无非就是网络和VPN了,我听说这些事在很多专业研发眼里仅仅是二流网管的活儿,可是我们这确实是重中之重,我们这身为研发却必须扮演网管的角色,除了不用做网线(最近搬进了自己的房子,这种综合布线的事在公司虽然没机会,在家却做了不少,翻了个底朝天),其它的你必须都得理解其所以然。本人做过网线,当过网吧网管,写过Java,写过C,做过破解,也搞安防,被开除过,也有过不辞而别,没有学历,却有热忱...这种经历使得我在做培训的时候可以多说很多话,虽不善言谈,可是讲起技术,却能滔滔不绝(当然讲起历史,更是滔滔不绝,古希腊,罗马,帕提亚,博斯普鲁斯,张居正,除了三国[这个已经被讲了很多次了])...
        既然要讲,那就不能忽悠别人,要把自己的东西与别人分享,我当然是这么想的。在部门例会时,同事也都提了意见,要么说讲的太专业,比如cookie的概念--虽然这不是我讲的但是仍然是个好建议,要么没有背景,上去就是专业概念,这些概念在我们讲的人眼里已经是无可厚非的常识了,可是我们没有顾及听者的感受。我觉得表达非常重要,这并不是说你在讲话时要抑扬顿挫,表现得自信十足,更重要的是要言之有内容,语气和语调固然重要,然而更重要的是内容,难道不是么?我见过一些过于自信的人,身边就有很多,他们很善言谈,虽然术业不精也能让人觉得这个人所说的都是真理,只因为这些人言语中过多的自信,过多的抑扬顿挫,过多的使用反问句,将你不知不觉的带入他们的思路,我承认自己没这本事。我看过一本书,叫做《乌合之众》,作者是法国的古斯塔夫.勒庞,书里面讲的就是这种可以烘托众人心术的演讲之术,而听者不管什么背景,在他的言语之下就是乌合之众之一员,我也看到过这般场面,我也痛恨这种忽悠(只因为我知道的太多?),因此我希望用这种反面来鞭策我自己,在培训时不能用言语和语气来代替内容,任何东西都代替不了内容本身!
        如果能把一个技术问题完全用通俗的文字表述出来,那就再好不过了,我一直都很崇拜那些科普书籍的作者,他们能把最深奥的问题用通俗的语言表述。于是我也试试。
        STP是一个很烦人的协议,Cisco的RSTP也一样,Vrrp很常见但是细节很难缠,更别说Cisco HSRP了,它们本质上是一回事,我该怎么讲述呢?这是一个问题。因此我决定以一篇完全文字性的描述来说明STP。

    展开全文
  • 使用 graphviz 形象化有向图

    千次阅读 2007-10-11 15:06:00
    将有向图数字,可以用一个邻接矩阵表示。计算机对这个图进行一系列的处理后(比如求闭包),如果要看看处理后的图,可以借助于 graphviz 这个强大的开源工具。1. Graphviz 简介Graphviz 是 AT&T Labs-Research ...
  • R语言可视——画脸谱图

    千次阅读 2020-05-05 10:30:18
    目录0引言1、脸谱图的各个指标2、参数介绍2.1 xy2.2 ...将各个维度的数据转化为人们熟知的面部表情来展示,这样的可视化图能够使人快速去获取各个维度的信息,使得数据更加形象化。R语言画脸谱图的包不只一个,本节...
  • 编程达到一个高的境界就是自制脚本语言,通过这可以精通编程里面的高深的技术,如编译原理、语言处理器、编译器与解释器,这些都是代表一个程序员实力的技术。   每个程序员都有实现属于自己编程语言的梦想,说其...
  • XML完整教程和什么是XML语言

    千次阅读 2011-07-23 17:50:59
    利用这些标记可以使文档规范格式 以便于信息的整理与交流。 这些标记语言的发展经历了一个过程。 首先产生了SGML,正是由于 SGML 的应用随后产生了 WEB 和 HTML 语言, 由于 HTML 语言满足不了日益
  • R语言|关联规则挖掘|可视

    万次阅读 2016-07-26 20:28:52
    为了进一步巩固R语言的基本用法及实践场景,这里尝试利用R做一些在关联规则上的挖掘实践,这里首要感谢博主gjwang1983的文章,这里仅记录下学习的一些基本应用命令: 1.工具包的选取 规则挖掘包arules 规则可视...
  • 关于 GraphQL 图形查询语言

    千次阅读 2018-10-03 08:12:08
    GraphQL 图形查询语言  声明:我是在自己学的过程中搜索到原文作者的内容。  以下内容全部出自作者:大转转FE。  我转载只是好奇了解到GraphQL想了解更多,分享到这里,方便学习。 前言 GraphQL is a ...
  • 程序语言拟人 (转)

    千次阅读 2015-05-27 14:17:09
    在网上看到一篇很有趣的程序语言拟人的介绍,遂转上来: 這系列文章的原始出處,是日本的「リクナビ NEXT」這家日本的人力公司的《Java、C++、Python…プログラミング言語擬人計画! 》和《Perl、C、...
  • 原文链接:http://tecdat.cn/?p=18770 原文出处:拓端数据部落公众号 为了用R来处理网络数据,我们使用婚礼数据集。...情感语义网络:游记数据感知旅游目的地形象 9.用关联规则数据挖掘探索药物配伍中的规律
  • 头疼 因此我写下这篇文章打算用一种形象生动的方法 首先你需要接受这么一个设定 View:你 Presenter:王大妈 Model:工具人 这么设定只是为了帮助理解,不要问为什么是王大妈而不是张大妈,这只是一个虚的东西。...
  • 结语 不论是近期的“天猫618”还是“京东618节”,众多电商巨头及品牌齐聚,正如马爸爸提出的,我们都处在一个全新的零售时代,正在逐步预见着消费需求的变化,在同质严重的当下,如何走进消费者并赢得关注是每个...
  • 人口金字塔是进行人口数据可视时常用的一种统计图形,可以形象地描述人口年龄和性别的分布情况。最近工作上经常处理人口数据,于是试着使用ggplot2绘制了一下。在这里记录一下,顺便也熟悉一下ggplot2的用法。 ...
  • 女程序员是最好的语言 | 3·8特辑

    万次阅读 多人点赞 2021-03-09 00:20:14
    今天是3月8日女神节,Php和Java算什么,女程序员才是最美最好的语言! 祝所有的程序媛,所有的女孩子们节日快乐,永远美丽!???? ????橙子说 留言区写下你对程序媛们的祝福,点赞前8的朋友们,将送出淘系技术定制...
  • 什么是 “内卷效应” ?

    千次阅读 2020-07-18 10:49:00
    最近网上流行着一个概念,叫做“内卷效应”。到底什么是内卷呢?让我们先来讲一个故事:不安分的观众在一个剧场里,本来每一位观众都在安安静静坐在位子上着看剧。忽然,有一个身材矮小的观众站了...
  • 程序员眼中的编程语言和操作系统

    千次阅读 2014-06-24 07:47:21
      《程序员眼中的编程语言》 ...中间的各个小图片则是,粉丝眼中的编程语言形象。 比如说, 第一行第一列,是Java程序员看Java语言的样子,一幢现代的大厦。第一行第二列,是Java程序员
  • 什么俺推荐Python[2]:作为动态语言的Python

    千次阅读 热门讨论 2009-08-21 23:42:00
    上次的帖子介绍了脚本语言的优缺点,然后又拿Python和其它脚本语言PK了一下。今天主要是忽悠一下动态语言,捎带忽悠一下Python。如果你看完本贴,觉得动态语言不错,那俺建议你从Python开始入手。 ★动态语言...
  • 都有哪些语言是跨平台的?

    千次阅读 2017-09-14 10:08:47
    那么跨平台语言最大特点是不编译机器码,不使用系统API。 1. 不编译机器码,因为不同环境CPU不同,虽然PC都是x86,但如果不是PC而是手机,那么CPU的指令集就不是x86,那么你的机器码就全废,不能跨平台。 2. 不使用...
  • 大数据时代,数据是非常重要的,怎样把它的重要之处就展示出来是我们需要掌握的,这就是大讲台老师本文要讲的重点数据可视。 通过观察数字和统计数据的转换以获得清晰的结论并不是一件容易的事。必须用一个合乎...
  • R语言 生存分析

    千次阅读 2018-10-05 19:36:41
    R语言对生存分析的处理 用R语言,对生存分析数据进行整理,按照相应格式进行输出 题目要求:
  • HTML标签的语义的作用 【单选题】(2.0分) 【简答题】文档类型的作用 【单选题】医药伦理的核心思想是什么? 【单选题】以下关于分支结构的描述中,错误的是()(1.0分) 【简答题】13-1.docx 【单选题】(2.0分) 【单选...
  • 驳狗屎文 "我为什么放弃Go语言

    千次阅读 2015-12-13 17:55:20
    驳狗屎文 "我为什么放弃Go语言" 此篇文章流传甚广, 其实里面没啥干货, 而且里面很多观点是有问题的. 这个文章在 golang-china 很早就讨论过了. 最近因为 Rust 1.0 和 1.1 的发布, 导致这个文章又出来毒害...
  • 菜鸟学R语言(PCA)

    千次阅读 2020-06-17 21:40:43
    在探索性数据分析中应用广泛,能更好地可视在具有许多变量的数据集中出现的变化。这在“宽”数据集的情况下特别有用,在这种情况下,每个样本有许多变量。主成分分析的目的是在于降维,其结果是把多个指标归约为...
  • 自然语言处理面试基础

    千次阅读 2020-01-01 23:30:03
    因为本课程是关于深度学习在自然语言处理中的应用,所以课程开始部分我们会概括性地介绍什么是深度学习项目的一般流程和所需基本概念,深度学习在自然语言处理领域主要有哪些热门应用,还会介绍本课程项目所需的 ...
  • 自然语言处理综述

    千次阅读 2018-08-15 22:01:30
    把熵作为测量信道的信息能力或者语言的信息量的一种方法,用概率测定;噪声信道与解码模型; 信息:文字和语言/数字和信息;信息冗余是信息安全的保障/语料对翻译至关重要。 信息的度量:信息熵是对一个信息系统不...
  • Go语言缺陷

    千次阅读 2016-04-29 10:21:12
    我为什么放弃Go语言 目录(?)[+] 我为什么放弃Go语言 有好几次,当我想起来的时候,总是会问自己:我为什么要放弃Go语言?这个决定是正确的吗?是明智和理性的吗?其实我一直在认真思考这...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 54,541
精华内容 21,816
关键字:

形象化的语言是什么