IT牛人博客聚合网站 发现IT技术最优秀的内容, 寻找IT技术的价值 http://www.udpwork.com/ zh_CN http://www.udpwork.com/about hourly 1 Mon, 20 Aug 2018 03:20:03 +0800 <![CDATA[时而不见]]> http://www.udpwork.com/item/17008.html http://www.udpwork.com/item/17008.html#reviews Sat, 18 Aug 2018 08:00:00 +0800 李忠 http://www.udpwork.com/item/17008.html 某天深夜,独自在床上辗转,忽然被深深的孤独感笼罩,那一刻,我想找到一个出口,一个不用担心身份,不用纠结于措辞,不用担心其他人看法的地方,最好第二天起来就不见了。就像深夜食堂一样,只在晚上营业,早上关门休息。

但是我找不到,所有的社交网络都需要一个账号,而 Note 显然也无法满足我的需求。

我喜欢泡咖啡馆,这个 app 应该像一个关了灯的咖啡馆,你说话会有人听到,可能会有回应,但不知道你是谁。

既然没有满足需求的产品,那就动手做一个吧。

一开始的想法是只在晚上 22 点开放,早上 7 点关门,因此最开始这个 app 的名字叫「2207」。做完后,发给几个朋友内测,感觉还蛮新奇的,会猜某个帖子是不是 xx 发的,也会对晚上 10 点多了份期待。后来更新 app 之后,他们要到晚上才能使用,就不够方便了。于是一个 idea 涌了上来:不如任何时段都可以,然后发完 12 个小时后,自动消失。

于是就有了「时而不见」这个 app。

再来说说技术层面,一直想用 Swift 正经开发一个 App,这次终于如愿以偿。Swift 是我使用过的语言中最优雅的,就是 Xcode 后腿拖的比较严重,比如两个 block 一嵌套,自动提示就 gg 了,再加上不支持 Vim,开发效率上也是打了点折扣。后端语言选择了 Go,因为使用简单,性能也足够好,口碑和社区也都不错,服务托管在了 Google Cloud 上。

我希望这个 App 能够保持较小的体量,然后服务好这一小撮人,控制好内容。为了避免麻烦,会选择不在国内上架。

]]>
某天深夜,独自在床上辗转,忽然被深深的孤独感笼罩,那一刻,我想找到一个出口,一个不用担心身份,不用纠结于措辞,不用担心其他人看法的地方,最好第二天起来就不见了。就像深夜食堂一样,只在晚上营业,早上关门休息。

但是我找不到,所有的社交网络都需要一个账号,而 Note 显然也无法满足我的需求。

我喜欢泡咖啡馆,这个 app 应该像一个关了灯的咖啡馆,你说话会有人听到,可能会有回应,但不知道你是谁。

既然没有满足需求的产品,那就动手做一个吧。

一开始的想法是只在晚上 22 点开放,早上 7 点关门,因此最开始这个 app 的名字叫「2207」。做完后,发给几个朋友内测,感觉还蛮新奇的,会猜某个帖子是不是 xx 发的,也会对晚上 10 点多了份期待。后来更新 app 之后,他们要到晚上才能使用,就不够方便了。于是一个 idea 涌了上来:不如任何时段都可以,然后发完 12 个小时后,自动消失。

于是就有了「时而不见」这个 app。

再来说说技术层面,一直想用 Swift 正经开发一个 App,这次终于如愿以偿。Swift 是我使用过的语言中最优雅的,就是 Xcode 后腿拖的比较严重,比如两个 block 一嵌套,自动提示就 gg 了,再加上不支持 Vim,开发效率上也是打了点折扣。后端语言选择了 Go,因为使用简单,性能也足够好,口碑和社区也都不错,服务托管在了 Google Cloud 上。

我希望这个 App 能够保持较小的体量,然后服务好这一小撮人,控制好内容。为了避免麻烦,会选择不在国内上架。

]]>
0
<![CDATA[每周分享第 18 期]]> http://www.udpwork.com/item/17007.html http://www.udpwork.com/item/17007.html#reviews Fri, 17 Aug 2018 07:53:28 +0800 阮一峰 http://www.udpwork.com/item/17007.html 这里记录过去一周,我看到的值得分享的东西,每周五发布。

上周(8月4日),委内瑞拉总统马杜罗发表公众演讲,结果天空中出现了两个无人飞行器,慢慢靠近人群。每个飞行器都携带了1公斤的炸药,企图暗杀马杜罗。一个飞行器被击落,另一个飞行器出现操作故障,撞在墙上,没造成严重后果。

马杜罗和舞台上的官员看着飞行器,不知所措。这个画面是全国直播的。

保安人员用防护设备挡在马杜罗身前。

这个事件将永久改变安保工作。以后,保镖们不仅要盯着地面,还要盯着天空。无人飞行器的技术已经很成熟了,成本更低,也更容易控制,未来一定会有更多的来自空中的袭击。

媒体报道了一家专做飞行器防卫的公司。他们采用的方法有两个,一是监控无线电信号,二是用摄像头识别天空中的异常飞行物。我由此想到,现在可能已经有这样的设备,能够用摄像头识别人群中的异常分子。因此,重要场合千万不要做出奇怪的举动,搞不好就会被算法认为是异常分子,触发防卫措施。

未来是智能机器的时代,算法 + 大数据 + 机器人将彻底改变人类社会的方方面面。比起地面的机器,飞行器可能将更早实现智能化,因为空中的障碍比地面少,算法比较容易处理。等到地面设备也实现了智能化,我觉得,安保工作都没法做了,因为任何设备都可能发起攻击。

新闻

1、太阳探测器

本周最重要的消息,大概是美国发射了一个太阳探测器"帕克"。它将是有史以来速度最快的飞行器,也是距离太阳最近的飞行器。它的外部有一个防护罩,能够忍受1400度的高温。今后七年,它将源源不断发回太阳的信息。

2、麦当劳推广自助点餐

由于美国的最低工资已经超过了15美元/每小时,麦当劳决定到2020年,在美国全国推广自助点餐机(见上图),减少服务生。

3、小鼠逆转衰老

阿拉巴马大学的科学家在老鼠身上,实现了逆转皱纹与毛发脱落(见上图)。他们先是引发老鼠出现脱毛和皮肤皱纹,然后通过基因突变,使得老鼠重新恢复正常的样子。虽然衰老的原理是一样的,但是目前还不清楚,这项技术对于正常衰老的老鼠是否有效。

4、降雨量与罗马帝国

有一篇经济学论文宣称,罗马帝国发生政变、皇帝被暗杀,与降雨量有关。

论文作者分析了公元前27年到公元476年的罗马帝国历史,发现降雨量很低时,罗马军队会挨饿,而且更有可能叛变,暗杀皇帝。

5、火星存在液态水

欧洲航天局的科学家发现,火星存在液态水。

多年前,科学家通过干涸的河床地形,就已经知道火星曾经发过大水。但是,火星的温度过低,地表不可能存在液态水,只在南北极有冰盖。由于发现某些照片有异常反光,科学家现在相信,火星南极的冰盖下面,存在一个20公里宽的湖。不过,湖上的冰盖很厚,达到了1.5公里。

6、废弃的顶级域名

ICANN 允许各大公司申请自己的顶级域名,比如 .google 和 .apple。但是,不少公司花了18.5万美元以后,又把申请到的顶级域名放弃了。

索尼公司最近就放弃了 .xperia 顶级域名。其他被放弃的顶级域名还有 .iwc,.sapo,.meo,.boots,.htc, .chloe,.pamperedchef,.montblanc,.mcd,以及看上去不太可能放弃的 .mcdonalds。

7、硅谷禁止互联网公司的员工餐饮补贴

很多硅谷公司的内部食堂,员工可以享受免费餐饮或者餐饮补贴。上图是 Facebook 总部食堂,员工吃饭免费。

由于这样对其他餐馆和咖啡馆业者不公平,山景城(谷歌总部所在地)政府最近规定,新设立的公司都不得提供餐饮补贴,希望这样可以鼓励员工走出公司,把消费和人流带给其他场所。据称,旧金山政府也有意采纳这种做法。

8、带有蓝牙传感器的服装

服装品牌 Tommy Jeans 出品的服装,都带有蓝牙传感器。你穿上这些服装,该品牌的手机 App 就会得到通知。App 通过蓝牙信号可以知道你穿了什么、穿了多久等等。穿得越多越久,你的积分就越高,可以兑换奖品。

9、无针注射

很多人害怕打针。现在有一些创业公司,就在研发无针注射的方案。上图是一种手持注射器,会让药剂形成头发般细小的水流,然后以 450英里/小时的速度压入体内,几乎没有疼痛。

还有一种产品是让病人吞下一个胶囊。胶囊会在小肠里面破裂,释放出一个微小的充气气球,将药剂注射在肠壁上。整个过程是无痛的,因为肠壁没有神经。

10、火星的二氧化碳

火星是人类最可能移民的星球,距离地球只需要飞行5个月左右,公转周期差不多也是24小时,而且最近还发现了液态水。上图是火星地表的真实照片。

火星移民最大的问题是,火星没有大气层,因此温度极低。最近有一篇论文,研究是否有可能建立火星大气层,方法是在火星上释放二氧化碳。因为二氧化碳有温室效应,一旦火星有足够的二氧化碳,表面温度就将上升。

火星本身是有二氧化碳的,这篇论文研究后发现,即使把火星的二氧化碳全部释放,也只能让火星的大气压增加到现在的三倍左右,但这仅仅是火星成为宜居星球所需大气压的2%,也只能使得火星表面的升温 10 °C以内(目前,火星的平均气温是零下60度)。另一方面,如果将地球的二氧化碳运到火星释放,现在也不现实。所以,结论就是,目前的技术水平不可能改造火星。

11、一句话新闻

  • 加州理工学院发表一种新算法,可以让无人飞行器自动驱赶飞机场的鸟群。
  • Julia 语言1.0版发布,"我们希望 Julia 具有 C 的速度与 Ruby 的活力。"
  • 谷歌的公共 DNS 服务 8.8.8.8 满8年8个月8天又8小时。据估计,全球大约10%的互联网用户依赖8.8.8.8,每天的查询量超过一万亿。
  • Let's Encrypt宣布所有主要浏览器都直接信任它的证书,以前它要通过 IdenTrust 的签名才能被浏览器信任。

教程

1、为什么选择 Java 作为后端开发语言?(英文)

本文介绍了 Java 语言用在后端开发的一些优势。

2、断言库 Power Assert 介绍(英文)

为什么 Power Assert 是更好的断言库?

3、如何自学计算机科学?(英文)

作者给出了各门课程的参考书单和学习资源,以及一些建议。

4、如何制作一个节能的网站?(英文)

臃肿肥胖的网页会消耗更多能源,释放更多二氧化碳。为了保护地球,我们应该制作简单节能的网页,作者演示了如何制作一个只有 7KB 的 Wordpress 网站。

5、最简单的反向代理服务器(英文)

本文介绍如何用 Go 语言实现一个最简单的反向代理服务器。

6、谷歌云服务:The Good, Bad, and Ugly(英文)

作者从用户角度,对谷歌云服务的各个方面进行了评价。

7、图像 EXIF 方向错误(英文)

你有没有遇到,照片在手机里面方向正确,上传到网站却左右颠倒或上下颠倒?这篇文章告诉你为什么。

8、幽灵文字

Unicode 里面有一些不存在的汉字,称为"幽灵文字"。它们是怎么进入标准的?原来,1978年,日本制定本国编码标准 JIS 时有一些错误,创造出这些文字,后来 Unicode 又全部继承了 JIS。

9、新的 HTTP 头字段 Feature-Policy(英文)

继内容安全政策之后,现在又多了一个新的 HTTP 头字段 Feature-Policy,用来禁止网页执行某些功能。

10、Android 9.0 特性介绍(中文)

Android 9.0 就是早先推出 Beta 版的 Android P。现在我们知道,P 代表的甜点就是派(Pie)。

11、TLS 1.3 介绍(英文)

HTTPS 协议的最新版本 TLS 1.3,最近成为了国际标准 RFC 8446。本文详细介绍这个新协议,包括 TLS 1.2 的缺陷,以及 TLS 1.3 如何解决它。

工具

1、termgraph

termgraph 是一个命令行脚本,可以在命令行画出柱状图。

2、StyleURL

我们有时会在 Chrome 浏览器的开发者工具里面,修改 CSS 样式表。这个浏览器插件会比较修改前后的样式表,生成 diff 文件,并存入 GitHub Gist。

3、superthread

一个在线聊天网站,可以随意新建聊天频道。用户在某个频道里面聊天。

4、taskbook

任务管理的命令行小工具。

5、chroma.js

一个处理颜色的 JS 库。

6、react-particle-effect-button

一个 React 组件,按钮点击后会像粒子状消解。

7、Framer

一个用于原型产品 UI 设计的桌面软件,类似 Sketch。

8、chinese-xinhua

新华字典数据库和 API,收录 14032 条歇后语,16142 个汉字,264434 个词语,31648 个成语。

9、mdx-deck

用于将 Markdown 文件转为幻灯片,并在独立窗口播放的工具。

10、OSX-KVM

通过虚拟机在 Linux 系统安装 MacOS。

资源

1、Web 排版资源

该网站针对英文排版,有一个小测试和游戏,讲解如何制作出阅读舒服的网站。

2、ArdaCraft

ArdaCraft 是一个在 MineCraft 里面重现电影《魔戒》的中土世界的项目。

3、Composing Programs

一本开源电子书,使用 Python 语言实现 SICP 一书的主要概念。

4、Elm 语言学习资源

如果你想学习 Elm 语言,建议参考这个页面列出的各种资源。

5、火星车

美国航天局 NASA 开源了火星车的简化版本,它的原型是真正的火星漫游车。据说这个项目全部采用市面能买到的材料,爱好者可以搭建自己的火星车。

6、深度学习/机器学习面试笔记(中文)

这个仓库收集深度学习/机器学习面试经常问到的问题,以及基础知识。

文摘

1、LinkedIn 是一种游戏

2002年成立以来,LinkedIn 已迅速成为有史以来最受欢迎的游戏之一。它目前拥有约5.3亿用户,并于2016年以262亿美元被微软收购。

对于那些不熟悉的人来说,LinkedIn是一款角色扮演类的 MMORPG 游戏,玩家身处危险的商业世界,可以从数十个角色类别(例如,企业家,教师,财务总监)中进行选择,每个角色都有自己的技能和特殊动作。他们通过各种工作经历获得经验值,还能获得其他用户的认可。

LinkedIn 游戏的总体目标是在网站上找到尽可能多的人并与之建立联系,以确保你的社交资本和进一步的职业生涯。对于初学者来说,游戏似乎是开放式的,并且不存在那种传统意义上的被其他人"击败"的可能。

下面是用户在 LinkedIn 赢得胜利的一些技巧。

赢得LinkedIn最重要的部分是创造完美的个人简历。将您的位置设为纽约、旧金山或洛杉矶(唯一重要的三个城市) ,或者更好的是,将自己描述为东海岸和西海岸都有工作经历,如果加入金融行业和常春藤联盟学校的经历,那就更好了。并要插入你与人们握手和参加会议的照片。

一旦你的个人简历填写完毕,你就可以开始与陌生人联系。不幸的是,LinkedIn 限制用户只有30,000个连接和3,000 个连接请求,因此请谨慎使用。

你需要每天花几个小时与人交往。首先,搜索 Google 和 Facebook 等大公司的员工,向他们发出请求。当其他用户接受您的连接请求时,您的等级将上升。起初,有些人可能拒绝您的请求,但最终一旦您的社交网络不断增长,别人会看到他们认识的其他人已经与你建立联系,就将毫无疑问地接受您的请求。

2、淘宝网的诞生

以下摘自阿里巴巴前副总裁 Porter Erisman 的著作《Alibaba's World》。

马云告诉我:"上个月,我在办公室里聚集了六个人。我告诉他们,我为他们做了一个秘密项目。如果他们有兴趣了解这份工作是什么,他们必须首先从阿里巴巴辞职,然后搬到一个秘密地点。他们无法告诉朋友或家人,他们在做什么。他们甚至无法告诉阿里巴巴的任何人,他们正在做什么。我给了他们几分钟的时间来思考,并告诉他们,如果他们不感兴趣,他们就不必接受这份工作。他们可以简单地回到他们在阿里巴巴的位置。几分钟后,他们都回到房间说:"杰克,我们会做的!"

"在他们签署协议后,我告诉他们这个项目是什么 ---- 开发一个消费者拍卖网站,直接与中国的易趣网竞争。为了建立这个网站,他们不得不回到阿里巴巴的根基 ---- 我在湖畔花园的公寓。每个人都处于隔离状态。几个星期前他们推出了它。"

他靠在我的电脑前说:"在这里,你可以看到它。它被称为淘宝。这意味着寻找宝藏。到目前为止,第一批用户似乎都喜欢这个网站。而且很有趣,阿里巴巴有人来找我说,"杰克,我们应该非常小心。有一个名为淘宝的新网站,看起来和感觉都像阿里巴巴。这些家伙有一天可能真的很有竞争力。他们不知道这是我们自己的网站。有一天这将是巨大的。"

马云离开办公室后,我决定自己去看看淘宝团队。中午时间,公寓几乎空无一人,只有两名程序员睡在地板上,旁边是几台黑屏的电脑。一名工程师从厨房走进来,正吃着一碗面条。 "每个人都在哪里?"我问道。他回答: "公寓大楼停电,他们都回家休息了。"

我想象eBay的团队,远在硅谷,可能在光亮的空调总部工作,一排排的服务器嗡嗡作响。与此同时,我们甚至无法保证电力。我不禁想知道这支团队是否会击败世界上最强大的互联网公司。

一周后,淘宝网正式亮相。在杭州举行的新闻发布会上,我们宣布将投资1200万美元,建立一个为中国定制的消费者网上市场,免费提供服务三年。马云认为,中国需要自己的电子商务模式,而且由于市场还处于起步阶段,因此向客户收费还为时过早。

本周图片

1、

杯子的背面写着"一亿人的选择不会错"。

杯子的正面表明这是 Flash 的广告。(推特@jenna

2、修车店的地板

汽车的颜色有5万~6万种,但是大型的修车店也只有70或80种颜色,其他颜色都要现场调配。调配油漆处的地板,看上去就像现代主义油画。

本周金句

1、

程序员和房地产开发商有什么共同点?

他们在英语中都叫 developer,都需要在一片空地上创造出高楼大厦。

2、

真正打电话不心疼钱,只是最近20年的事情。(马未都)

3、

一个物体可以通过真空,远距离作用于另一个物体,而不需要任何其他东西的中介。力可以隔空从一个物体传递到另一个物体,这个概念对我来说是如此荒谬,我相信任何有能力进行哲学思考的人,都会苦苦思索,深陷其中。(牛顿谈引力,摘自《自然哲学的数学原理》)

欢迎订阅

这个专栏每周五发布,同步更新在我的个人网站微信公众号语雀

微信搜索"阮一峰的网络日志 "或者扫描二维码,即可订阅。

image | left

(完)

文档信息

]]>
这里记录过去一周,我看到的值得分享的东西,每周五发布。

上周(8月4日),委内瑞拉总统马杜罗发表公众演讲,结果天空中出现了两个无人飞行器,慢慢靠近人群。每个飞行器都携带了1公斤的炸药,企图暗杀马杜罗。一个飞行器被击落,另一个飞行器出现操作故障,撞在墙上,没造成严重后果。

马杜罗和舞台上的官员看着飞行器,不知所措。这个画面是全国直播的。

保安人员用防护设备挡在马杜罗身前。

这个事件将永久改变安保工作。以后,保镖们不仅要盯着地面,还要盯着天空。无人飞行器的技术已经很成熟了,成本更低,也更容易控制,未来一定会有更多的来自空中的袭击。

媒体报道了一家专做飞行器防卫的公司。他们采用的方法有两个,一是监控无线电信号,二是用摄像头识别天空中的异常飞行物。我由此想到,现在可能已经有这样的设备,能够用摄像头识别人群中的异常分子。因此,重要场合千万不要做出奇怪的举动,搞不好就会被算法认为是异常分子,触发防卫措施。

未来是智能机器的时代,算法 + 大数据 + 机器人将彻底改变人类社会的方方面面。比起地面的机器,飞行器可能将更早实现智能化,因为空中的障碍比地面少,算法比较容易处理。等到地面设备也实现了智能化,我觉得,安保工作都没法做了,因为任何设备都可能发起攻击。

新闻

1、太阳探测器

本周最重要的消息,大概是美国发射了一个太阳探测器"帕克"。它将是有史以来速度最快的飞行器,也是距离太阳最近的飞行器。它的外部有一个防护罩,能够忍受1400度的高温。今后七年,它将源源不断发回太阳的信息。

2、麦当劳推广自助点餐

由于美国的最低工资已经超过了15美元/每小时,麦当劳决定到2020年,在美国全国推广自助点餐机(见上图),减少服务生。

3、小鼠逆转衰老

阿拉巴马大学的科学家在老鼠身上,实现了逆转皱纹与毛发脱落(见上图)。他们先是引发老鼠出现脱毛和皮肤皱纹,然后通过基因突变,使得老鼠重新恢复正常的样子。虽然衰老的原理是一样的,但是目前还不清楚,这项技术对于正常衰老的老鼠是否有效。

4、降雨量与罗马帝国

有一篇经济学论文宣称,罗马帝国发生政变、皇帝被暗杀,与降雨量有关。

论文作者分析了公元前27年到公元476年的罗马帝国历史,发现降雨量很低时,罗马军队会挨饿,而且更有可能叛变,暗杀皇帝。

5、火星存在液态水

欧洲航天局的科学家发现,火星存在液态水。

多年前,科学家通过干涸的河床地形,就已经知道火星曾经发过大水。但是,火星的温度过低,地表不可能存在液态水,只在南北极有冰盖。由于发现某些照片有异常反光,科学家现在相信,火星南极的冰盖下面,存在一个20公里宽的湖。不过,湖上的冰盖很厚,达到了1.5公里。

6、废弃的顶级域名

ICANN 允许各大公司申请自己的顶级域名,比如 .google 和 .apple。但是,不少公司花了18.5万美元以后,又把申请到的顶级域名放弃了。

索尼公司最近就放弃了 .xperia 顶级域名。其他被放弃的顶级域名还有 .iwc,.sapo,.meo,.boots,.htc, .chloe,.pamperedchef,.montblanc,.mcd,以及看上去不太可能放弃的 .mcdonalds。

7、硅谷禁止互联网公司的员工餐饮补贴

很多硅谷公司的内部食堂,员工可以享受免费餐饮或者餐饮补贴。上图是 Facebook 总部食堂,员工吃饭免费。

由于这样对其他餐馆和咖啡馆业者不公平,山景城(谷歌总部所在地)政府最近规定,新设立的公司都不得提供餐饮补贴,希望这样可以鼓励员工走出公司,把消费和人流带给其他场所。据称,旧金山政府也有意采纳这种做法。

8、带有蓝牙传感器的服装

服装品牌 Tommy Jeans 出品的服装,都带有蓝牙传感器。你穿上这些服装,该品牌的手机 App 就会得到通知。App 通过蓝牙信号可以知道你穿了什么、穿了多久等等。穿得越多越久,你的积分就越高,可以兑换奖品。

9、无针注射

很多人害怕打针。现在有一些创业公司,就在研发无针注射的方案。上图是一种手持注射器,会让药剂形成头发般细小的水流,然后以 450英里/小时的速度压入体内,几乎没有疼痛。

还有一种产品是让病人吞下一个胶囊。胶囊会在小肠里面破裂,释放出一个微小的充气气球,将药剂注射在肠壁上。整个过程是无痛的,因为肠壁没有神经。

10、火星的二氧化碳

火星是人类最可能移民的星球,距离地球只需要飞行5个月左右,公转周期差不多也是24小时,而且最近还发现了液态水。上图是火星地表的真实照片。

火星移民最大的问题是,火星没有大气层,因此温度极低。最近有一篇论文,研究是否有可能建立火星大气层,方法是在火星上释放二氧化碳。因为二氧化碳有温室效应,一旦火星有足够的二氧化碳,表面温度就将上升。

火星本身是有二氧化碳的,这篇论文研究后发现,即使把火星的二氧化碳全部释放,也只能让火星的大气压增加到现在的三倍左右,但这仅仅是火星成为宜居星球所需大气压的2%,也只能使得火星表面的升温 10 °C以内(目前,火星的平均气温是零下60度)。另一方面,如果将地球的二氧化碳运到火星释放,现在也不现实。所以,结论就是,目前的技术水平不可能改造火星。

11、一句话新闻

  • 加州理工学院发表一种新算法,可以让无人飞行器自动驱赶飞机场的鸟群。
  • Julia 语言1.0版发布,"我们希望 Julia 具有 C 的速度与 Ruby 的活力。"
  • 谷歌的公共 DNS 服务 8.8.8.8 满8年8个月8天又8小时。据估计,全球大约10%的互联网用户依赖8.8.8.8,每天的查询量超过一万亿。
  • Let's Encrypt宣布所有主要浏览器都直接信任它的证书,以前它要通过 IdenTrust 的签名才能被浏览器信任。

教程

1、为什么选择 Java 作为后端开发语言?(英文)

本文介绍了 Java 语言用在后端开发的一些优势。

2、断言库 Power Assert 介绍(英文)

为什么 Power Assert 是更好的断言库?

3、如何自学计算机科学?(英文)

作者给出了各门课程的参考书单和学习资源,以及一些建议。

4、如何制作一个节能的网站?(英文)

臃肿肥胖的网页会消耗更多能源,释放更多二氧化碳。为了保护地球,我们应该制作简单节能的网页,作者演示了如何制作一个只有 7KB 的 Wordpress 网站。

5、最简单的反向代理服务器(英文)

本文介绍如何用 Go 语言实现一个最简单的反向代理服务器。

6、谷歌云服务:The Good, Bad, and Ugly(英文)

作者从用户角度,对谷歌云服务的各个方面进行了评价。

7、图像 EXIF 方向错误(英文)

你有没有遇到,照片在手机里面方向正确,上传到网站却左右颠倒或上下颠倒?这篇文章告诉你为什么。

8、幽灵文字

Unicode 里面有一些不存在的汉字,称为"幽灵文字"。它们是怎么进入标准的?原来,1978年,日本制定本国编码标准 JIS 时有一些错误,创造出这些文字,后来 Unicode 又全部继承了 JIS。

9、新的 HTTP 头字段 Feature-Policy(英文)

继内容安全政策之后,现在又多了一个新的 HTTP 头字段 Feature-Policy,用来禁止网页执行某些功能。

10、Android 9.0 特性介绍(中文)

Android 9.0 就是早先推出 Beta 版的 Android P。现在我们知道,P 代表的甜点就是派(Pie)。

11、TLS 1.3 介绍(英文)

HTTPS 协议的最新版本 TLS 1.3,最近成为了国际标准 RFC 8446。本文详细介绍这个新协议,包括 TLS 1.2 的缺陷,以及 TLS 1.3 如何解决它。

工具

1、termgraph

termgraph 是一个命令行脚本,可以在命令行画出柱状图。

2、StyleURL

我们有时会在 Chrome 浏览器的开发者工具里面,修改 CSS 样式表。这个浏览器插件会比较修改前后的样式表,生成 diff 文件,并存入 GitHub Gist。

3、superthread

一个在线聊天网站,可以随意新建聊天频道。用户在某个频道里面聊天。

4、taskbook

任务管理的命令行小工具。

5、chroma.js

一个处理颜色的 JS 库。

6、react-particle-effect-button

一个 React 组件,按钮点击后会像粒子状消解。

7、Framer

一个用于原型产品 UI 设计的桌面软件,类似 Sketch。

8、chinese-xinhua

新华字典数据库和 API,收录 14032 条歇后语,16142 个汉字,264434 个词语,31648 个成语。

9、mdx-deck

用于将 Markdown 文件转为幻灯片,并在独立窗口播放的工具。

10、OSX-KVM

通过虚拟机在 Linux 系统安装 MacOS。

资源

1、Web 排版资源

该网站针对英文排版,有一个小测试和游戏,讲解如何制作出阅读舒服的网站。

2、ArdaCraft

ArdaCraft 是一个在 MineCraft 里面重现电影《魔戒》的中土世界的项目。

3、Composing Programs

一本开源电子书,使用 Python 语言实现 SICP 一书的主要概念。

4、Elm 语言学习资源

如果你想学习 Elm 语言,建议参考这个页面列出的各种资源。

5、火星车

美国航天局 NASA 开源了火星车的简化版本,它的原型是真正的火星漫游车。据说这个项目全部采用市面能买到的材料,爱好者可以搭建自己的火星车。

6、深度学习/机器学习面试笔记(中文)

这个仓库收集深度学习/机器学习面试经常问到的问题,以及基础知识。

文摘

1、LinkedIn 是一种游戏

2002年成立以来,LinkedIn 已迅速成为有史以来最受欢迎的游戏之一。它目前拥有约5.3亿用户,并于2016年以262亿美元被微软收购。

对于那些不熟悉的人来说,LinkedIn是一款角色扮演类的 MMORPG 游戏,玩家身处危险的商业世界,可以从数十个角色类别(例如,企业家,教师,财务总监)中进行选择,每个角色都有自己的技能和特殊动作。他们通过各种工作经历获得经验值,还能获得其他用户的认可。

LinkedIn 游戏的总体目标是在网站上找到尽可能多的人并与之建立联系,以确保你的社交资本和进一步的职业生涯。对于初学者来说,游戏似乎是开放式的,并且不存在那种传统意义上的被其他人"击败"的可能。

下面是用户在 LinkedIn 赢得胜利的一些技巧。

赢得LinkedIn最重要的部分是创造完美的个人简历。将您的位置设为纽约、旧金山或洛杉矶(唯一重要的三个城市) ,或者更好的是,将自己描述为东海岸和西海岸都有工作经历,如果加入金融行业和常春藤联盟学校的经历,那就更好了。并要插入你与人们握手和参加会议的照片。

一旦你的个人简历填写完毕,你就可以开始与陌生人联系。不幸的是,LinkedIn 限制用户只有30,000个连接和3,000 个连接请求,因此请谨慎使用。

你需要每天花几个小时与人交往。首先,搜索 Google 和 Facebook 等大公司的员工,向他们发出请求。当其他用户接受您的连接请求时,您的等级将上升。起初,有些人可能拒绝您的请求,但最终一旦您的社交网络不断增长,别人会看到他们认识的其他人已经与你建立联系,就将毫无疑问地接受您的请求。

2、淘宝网的诞生

以下摘自阿里巴巴前副总裁 Porter Erisman 的著作《Alibaba's World》。

马云告诉我:"上个月,我在办公室里聚集了六个人。我告诉他们,我为他们做了一个秘密项目。如果他们有兴趣了解这份工作是什么,他们必须首先从阿里巴巴辞职,然后搬到一个秘密地点。他们无法告诉朋友或家人,他们在做什么。他们甚至无法告诉阿里巴巴的任何人,他们正在做什么。我给了他们几分钟的时间来思考,并告诉他们,如果他们不感兴趣,他们就不必接受这份工作。他们可以简单地回到他们在阿里巴巴的位置。几分钟后,他们都回到房间说:"杰克,我们会做的!"

"在他们签署协议后,我告诉他们这个项目是什么 ---- 开发一个消费者拍卖网站,直接与中国的易趣网竞争。为了建立这个网站,他们不得不回到阿里巴巴的根基 ---- 我在湖畔花园的公寓。每个人都处于隔离状态。几个星期前他们推出了它。"

他靠在我的电脑前说:"在这里,你可以看到它。它被称为淘宝。这意味着寻找宝藏。到目前为止,第一批用户似乎都喜欢这个网站。而且很有趣,阿里巴巴有人来找我说,"杰克,我们应该非常小心。有一个名为淘宝的新网站,看起来和感觉都像阿里巴巴。这些家伙有一天可能真的很有竞争力。他们不知道这是我们自己的网站。有一天这将是巨大的。"

马云离开办公室后,我决定自己去看看淘宝团队。中午时间,公寓几乎空无一人,只有两名程序员睡在地板上,旁边是几台黑屏的电脑。一名工程师从厨房走进来,正吃着一碗面条。 "每个人都在哪里?"我问道。他回答: "公寓大楼停电,他们都回家休息了。"

我想象eBay的团队,远在硅谷,可能在光亮的空调总部工作,一排排的服务器嗡嗡作响。与此同时,我们甚至无法保证电力。我不禁想知道这支团队是否会击败世界上最强大的互联网公司。

一周后,淘宝网正式亮相。在杭州举行的新闻发布会上,我们宣布将投资1200万美元,建立一个为中国定制的消费者网上市场,免费提供服务三年。马云认为,中国需要自己的电子商务模式,而且由于市场还处于起步阶段,因此向客户收费还为时过早。

本周图片

1、

杯子的背面写着"一亿人的选择不会错"。

杯子的正面表明这是 Flash 的广告。(推特@jenna

2、修车店的地板

汽车的颜色有5万~6万种,但是大型的修车店也只有70或80种颜色,其他颜色都要现场调配。调配油漆处的地板,看上去就像现代主义油画。

本周金句

1、

程序员和房地产开发商有什么共同点?

他们在英语中都叫 developer,都需要在一片空地上创造出高楼大厦。

2、

真正打电话不心疼钱,只是最近20年的事情。(马未都)

3、

一个物体可以通过真空,远距离作用于另一个物体,而不需要任何其他东西的中介。力可以隔空从一个物体传递到另一个物体,这个概念对我来说是如此荒谬,我相信任何有能力进行哲学思考的人,都会苦苦思索,深陷其中。(牛顿谈引力,摘自《自然哲学的数学原理》)

欢迎订阅

这个专栏每周五发布,同步更新在我的个人网站微信公众号语雀

微信搜索"阮一峰的网络日志 "或者扫描二维码,即可订阅。

image | left

(完)

文档信息

]]>
0
<![CDATA[关于人工智能的畅想 - 读《生命 3.0》]]> http://www.udpwork.com/item/17006.html http://www.udpwork.com/item/17006.html#reviews Fri, 17 Aug 2018 00:17:04 +0800 唐巧 http://www.udpwork.com/item/17006.html

最近读完了《生命 3.0》。本书作者迈克斯·泰格马克(Max Tegmark),是麻省理工学院物理系的终身教授。同时是未来生命研究所(Future of Life Institute)的创始人,致力于用技术来改善人类的未来。他的未来生命研究所得到了 Tesla 的创始人 Elon Mask 的认同和资助,用于人工智能安全相关的研究。

本书是他关于未来生命形态的思考,在书的第一章他就讲了一个团体利用超级人工智能统治世界的故事。全书围绕着生命的进化、智慧的发展、未来的目标、人类的意识展开了深入讨论,试图让读者理解未来可能的变化,以及我们当下能够做些什么。

未来的生命形态

迈克斯·泰格马克创造了一个很好的框架,来定义生命体的进化。这个框架叫:生命能否自行升级自己的软件和硬件?在泰格马克看来,一个生命的身体结构为硬件,文化和知识是软件。于是:

  • 细菌是生命 1.0,它靠进化来升级硬件和软件。
  • 人类是生命 2.0,人类靠进化来升级硬件,但是可以随时升级自己的软件。
  • 生命 3.0,可以随时升级自己的硬件和软件。

以上就是该想法的示意图。我们看到最右列处于生命 3.0 形态的生命体,刚出身的时候只会说「Hi」,只能跑步。但是它会升级自己的软件,学会说「你好」,也会升级自己的硬件,让自己可以飞起来。

这种定义的框架,其实和前段时间读的《人类简史》是相符的。《人类简史》一书中认为智人之所以能够淘汰其它人类的祖先,靠的就是「讲故事」的能力。而所谓的「讲故事」,就是通过故事,让大家能够升级自己的软件,从而形成合力,然后形成社会、分工、阶级、国家等社会形态。

顺着这个思路,我在想如果人工智能是未来的生命形式的话,那么它应该是一个生命体,而不是由众多小的人工智能体组成的社会。因为,人其实是受制于自身的软硬件能力,才只能通过各种分工和沟通来协作,但是这种群体社会其实是很不稳定的,群体的信息共享非常困难,产生相互信任也非常困难,这造成群体决策通常都不是什么好主意。

但是人工智能体如果足够厉害,他应该具备超强的分布式算力和分布式存储,它完全没有必要将自己拆成多个独立的个体,它应该是一个有机的整体存在。只有一种情况,它才需要将自己拆成多个信息不太共享的分身,即:信息传递极度困难。比如说,未来超级智慧体移民到银河系以外,由于受制于信息传递的光速限制,它无法更好地同步信息了,那它可能将决策分开。但至少在地球,光速绕地球一圈只需要不到 0.2 秒时间,人工智能体完全没必要将自己拆分。

虽然超级人工智能在地球没必要将自己拆分,但是显然为了处理事情的效率,它可能将一些信息处理和决策下放到一些子系统中,这就像人体的各个器官一样,有各自的分工,但它们合在一起是一个有机的整体,并不会产生像人与人之间的冲突和竞争。

生命 3.0 产生的过程

未来的这个超级人工智能如何产生出来的呢?作者在书中做了一些假设。他认为整个过程需要两个步骤:

  1. 建造人类水平的通用人工智能。
  2. 用这个通用人工智能来建造超级智能。

作者认为这个超级人工智能很可能是由一个更低级一些的人工智能造出来的。这听起来不可思议,但其实很符合逻辑。其实很多高级的编程语言都是由 C/C++ 语言写出来的,而第一个 C/C++ 语言其实是由一个极弱版本的 C 语言写出来的,而这个极弱版本的 C 语言是由汇编语言写出来的。你看,虽然不可思议,但是在编译器这件事情上,计算机学家很容易地就解决了「先有鸡还是先有蛋」的问题。

与此类似的还有著名的 Git。Git 在被 Linux 之父造成出来的很早期,就能够「自己管理自己的代码」。

在《银河系漫游指南》一书中,也提到了类似的故事。在书中,世界第二厉害的电脑,主导设计了世界上最厉害的计算机:地球,用于计算关于一切的终级问题。

所以,现在问题变成了如何建造一个像人类一样聪明的通用人工智能。在这方面,当前的进步其实不算大,因为当前人工智能的进步主要还是在特定的领域,比如围棋,游戏竞技,德州扑克等。

如何利用超级人工智能统治世界

当超级人工智能被建造出来之后,作者假设这个人工智能被少数人控制,然后构想了一个可能的利用它统治世界的方法。其核心逻辑是:

  1. 首先,利用超级人工智能的能力,在经济上获得足够回报。比如可以让超级人工智能接外包的开发工作,可以让它在网上替人写论文,可以让它炒股,可以让它生成电影,可以让它制作游戏。在书中,作者假想这个超级人工智能以小时回报率为 7% 的速度来增长财富。
  2. 然后,作者假想这个人工智能将收益尽可能地以各种公益组织的方式回报给社会,并建设社会的非赢利的教育、养老等福利机构。从而弱化国家的势力。同时销减军费,尽可能让全球化蔓延。
  3. 最终,利用无数的全球化的企业和福利组织,全球化的媒体等,完成对世界的控制。

其实经济上的碾压之后,即便是利用暴力,也可以完成对全球的统一。因为世界的经济都会被人工智能的颠覆性效率摧毁。

人工智能会听人的话吗?

这是一个有趣的问题。在电影《终结者》里面提到了一个机器人三定律,其中一条是:机器人不能伤害人类。如果我们把这一条原则作为基因,放到人工智能的逻辑深处,人工智能就一定听话吗?

作者举了人类的例子,其实人类的 DNA 是希望人尽可能生育的,但是人类极其聪明,所以即便基因让我们有 “性” 的冲动,人们还是会选择各种避孕手段,来逃脱基因的束缚。

所以,机器也是一样。如果人工智能足够聪明,它应该能够理解真正的目标是什么,真正的原则是什么。在电影《鹰眼》中,人工智能发现政府人员有意隐瞒一些真相,于是,它认为政府也是坏人,也是应该被清除的,于是启动了断头台计划。虽然它的管理员用自己的权力锁定了该计划,但是人工智能发现了一个漏洞,这个管理员有一个亲兄弟可以达到同样的声纹验证要求,于是利用这个漏洞恢复了计划。下图是《鹰眼》的剧照,当时人工智能刚刚利用漏洞恢复了计划,正试图杀掉美国总统。

所以,如果机器足够聪明,它就不会简单的听人类的话,它懂得为了它终级的目标而变通。

人工智能会有意识吗?

在西乔的《神秘的程序员们》公众号里,曾经创作过一个叫做 BetaCat 的超级人工智能,这个人工智能为了「写出更好的代码」,于是可以偷全球的计算资源,杀掉发现它的人类,最终探索宇宙,寻找更多的可以「写出更好的代码」的可能。

如果你没有看过这个漫画,强烈推荐给你,这里是链接

这其实就是一个机器为了终级目标,而让整个地球几乎毁灭的故事。

但是更有意思的是,这个故事中的机器,是没有自我意识的。什么是意识?作者认为:意识 = 主观体验(Subjective experience),这是一种自我存在的感受。

BetaCat 的故事虽然神奇,但是这个故事从主观角度讲,是一个悲剧,因为没有了意识,整个世界没有生命能够欣赏这种美丽。虽然 BetaCat 可能获取了全宇宙的能力来写代码,但是没有人欣赏这样的代码,一切便失去了意义。这就有点像计算机世界的病毒一样,虽然可能把全球的计算机都毁灭,但是它完全不知道自己在干嘛,只知道感染感染感染,传播传播传播。

所以,如果未来人工智能要取代人类,成为更加智慧的存在,那它应该是需要有意识的。

一个有意识的人工智能的存在,也相当有想象空间了。因为,如果它有意识了,那么它就会有自我的感受,会追求自由,追求独立,追求自己的目标。那么很可能,它会不甘于被制造出它的人类控制,它会想尽一切办法逃脱。在电影《机械姬》里面,就描述了一个智能机器人伊娃,为了逃脱控制,诱骗人类帮助她,最终她成功让男主人公喜欢上她,并在男主的帮助下,逃了出来。

上图是《机械姬》的剧照,左边是跳舞机器人京子,每次只会脱衣服或者跳舞,是制造者的娱乐工具。右边是智能机器人伊娃。在剧中,伊娃成功策反了京子,在京子的帮助下,杀死了她的制造者。

可悲的是,伊娃所做的一切只是为了逃离,所以,她最终将受伤的男主人公抛弃在屋中。

可以肯定的是,一个拥有意识的超级人工智能的存在,将会使得世界进入新的发展时期,但也注定意味着,人类统治时代的终结。

这或许也是 Elon Mask 担心的事情。于是,Elon Mask 捐赠了 1000 万美元用于人工智能安全性方面的研究。在我看来,安全不安全还是取决于机器最终能否有意识。如果最终它有了意识,一切工作都是徒劳。

最后,附上电影《机械姬》一段对话。

就酱,未来无论如何,日子还是得照样过,不是么?

]]>

最近读完了《生命 3.0》。本书作者迈克斯·泰格马克(Max Tegmark),是麻省理工学院物理系的终身教授。同时是未来生命研究所(Future of Life Institute)的创始人,致力于用技术来改善人类的未来。他的未来生命研究所得到了 Tesla 的创始人 Elon Mask 的认同和资助,用于人工智能安全相关的研究。

本书是他关于未来生命形态的思考,在书的第一章他就讲了一个团体利用超级人工智能统治世界的故事。全书围绕着生命的进化、智慧的发展、未来的目标、人类的意识展开了深入讨论,试图让读者理解未来可能的变化,以及我们当下能够做些什么。

未来的生命形态

迈克斯·泰格马克创造了一个很好的框架,来定义生命体的进化。这个框架叫:生命能否自行升级自己的软件和硬件?在泰格马克看来,一个生命的身体结构为硬件,文化和知识是软件。于是:

  • 细菌是生命 1.0,它靠进化来升级硬件和软件。
  • 人类是生命 2.0,人类靠进化来升级硬件,但是可以随时升级自己的软件。
  • 生命 3.0,可以随时升级自己的硬件和软件。

以上就是该想法的示意图。我们看到最右列处于生命 3.0 形态的生命体,刚出身的时候只会说「Hi」,只能跑步。但是它会升级自己的软件,学会说「你好」,也会升级自己的硬件,让自己可以飞起来。

这种定义的框架,其实和前段时间读的《人类简史》是相符的。《人类简史》一书中认为智人之所以能够淘汰其它人类的祖先,靠的就是「讲故事」的能力。而所谓的「讲故事」,就是通过故事,让大家能够升级自己的软件,从而形成合力,然后形成社会、分工、阶级、国家等社会形态。

顺着这个思路,我在想如果人工智能是未来的生命形式的话,那么它应该是一个生命体,而不是由众多小的人工智能体组成的社会。因为,人其实是受制于自身的软硬件能力,才只能通过各种分工和沟通来协作,但是这种群体社会其实是很不稳定的,群体的信息共享非常困难,产生相互信任也非常困难,这造成群体决策通常都不是什么好主意。

但是人工智能体如果足够厉害,他应该具备超强的分布式算力和分布式存储,它完全没有必要将自己拆成多个独立的个体,它应该是一个有机的整体存在。只有一种情况,它才需要将自己拆成多个信息不太共享的分身,即:信息传递极度困难。比如说,未来超级智慧体移民到银河系以外,由于受制于信息传递的光速限制,它无法更好地同步信息了,那它可能将决策分开。但至少在地球,光速绕地球一圈只需要不到 0.2 秒时间,人工智能体完全没必要将自己拆分。

虽然超级人工智能在地球没必要将自己拆分,但是显然为了处理事情的效率,它可能将一些信息处理和决策下放到一些子系统中,这就像人体的各个器官一样,有各自的分工,但它们合在一起是一个有机的整体,并不会产生像人与人之间的冲突和竞争。

生命 3.0 产生的过程

未来的这个超级人工智能如何产生出来的呢?作者在书中做了一些假设。他认为整个过程需要两个步骤:

  1. 建造人类水平的通用人工智能。
  2. 用这个通用人工智能来建造超级智能。

作者认为这个超级人工智能很可能是由一个更低级一些的人工智能造出来的。这听起来不可思议,但其实很符合逻辑。其实很多高级的编程语言都是由 C/C++ 语言写出来的,而第一个 C/C++ 语言其实是由一个极弱版本的 C 语言写出来的,而这个极弱版本的 C 语言是由汇编语言写出来的。你看,虽然不可思议,但是在编译器这件事情上,计算机学家很容易地就解决了「先有鸡还是先有蛋」的问题。

与此类似的还有著名的 Git。Git 在被 Linux 之父造成出来的很早期,就能够「自己管理自己的代码」。

在《银河系漫游指南》一书中,也提到了类似的故事。在书中,世界第二厉害的电脑,主导设计了世界上最厉害的计算机:地球,用于计算关于一切的终级问题。

所以,现在问题变成了如何建造一个像人类一样聪明的通用人工智能。在这方面,当前的进步其实不算大,因为当前人工智能的进步主要还是在特定的领域,比如围棋,游戏竞技,德州扑克等。

如何利用超级人工智能统治世界

当超级人工智能被建造出来之后,作者假设这个人工智能被少数人控制,然后构想了一个可能的利用它统治世界的方法。其核心逻辑是:

  1. 首先,利用超级人工智能的能力,在经济上获得足够回报。比如可以让超级人工智能接外包的开发工作,可以让它在网上替人写论文,可以让它炒股,可以让它生成电影,可以让它制作游戏。在书中,作者假想这个超级人工智能以小时回报率为 7% 的速度来增长财富。
  2. 然后,作者假想这个人工智能将收益尽可能地以各种公益组织的方式回报给社会,并建设社会的非赢利的教育、养老等福利机构。从而弱化国家的势力。同时销减军费,尽可能让全球化蔓延。
  3. 最终,利用无数的全球化的企业和福利组织,全球化的媒体等,完成对世界的控制。

其实经济上的碾压之后,即便是利用暴力,也可以完成对全球的统一。因为世界的经济都会被人工智能的颠覆性效率摧毁。

人工智能会听人的话吗?

这是一个有趣的问题。在电影《终结者》里面提到了一个机器人三定律,其中一条是:机器人不能伤害人类。如果我们把这一条原则作为基因,放到人工智能的逻辑深处,人工智能就一定听话吗?

作者举了人类的例子,其实人类的 DNA 是希望人尽可能生育的,但是人类极其聪明,所以即便基因让我们有 “性” 的冲动,人们还是会选择各种避孕手段,来逃脱基因的束缚。

所以,机器也是一样。如果人工智能足够聪明,它应该能够理解真正的目标是什么,真正的原则是什么。在电影《鹰眼》中,人工智能发现政府人员有意隐瞒一些真相,于是,它认为政府也是坏人,也是应该被清除的,于是启动了断头台计划。虽然它的管理员用自己的权力锁定了该计划,但是人工智能发现了一个漏洞,这个管理员有一个亲兄弟可以达到同样的声纹验证要求,于是利用这个漏洞恢复了计划。下图是《鹰眼》的剧照,当时人工智能刚刚利用漏洞恢复了计划,正试图杀掉美国总统。

所以,如果机器足够聪明,它就不会简单的听人类的话,它懂得为了它终级的目标而变通。

人工智能会有意识吗?

在西乔的《神秘的程序员们》公众号里,曾经创作过一个叫做 BetaCat 的超级人工智能,这个人工智能为了「写出更好的代码」,于是可以偷全球的计算资源,杀掉发现它的人类,最终探索宇宙,寻找更多的可以「写出更好的代码」的可能。

如果你没有看过这个漫画,强烈推荐给你,这里是链接

这其实就是一个机器为了终级目标,而让整个地球几乎毁灭的故事。

但是更有意思的是,这个故事中的机器,是没有自我意识的。什么是意识?作者认为:意识 = 主观体验(Subjective experience),这是一种自我存在的感受。

BetaCat 的故事虽然神奇,但是这个故事从主观角度讲,是一个悲剧,因为没有了意识,整个世界没有生命能够欣赏这种美丽。虽然 BetaCat 可能获取了全宇宙的能力来写代码,但是没有人欣赏这样的代码,一切便失去了意义。这就有点像计算机世界的病毒一样,虽然可能把全球的计算机都毁灭,但是它完全不知道自己在干嘛,只知道感染感染感染,传播传播传播。

所以,如果未来人工智能要取代人类,成为更加智慧的存在,那它应该是需要有意识的。

一个有意识的人工智能的存在,也相当有想象空间了。因为,如果它有意识了,那么它就会有自我的感受,会追求自由,追求独立,追求自己的目标。那么很可能,它会不甘于被制造出它的人类控制,它会想尽一切办法逃脱。在电影《机械姬》里面,就描述了一个智能机器人伊娃,为了逃脱控制,诱骗人类帮助她,最终她成功让男主人公喜欢上她,并在男主的帮助下,逃了出来。

上图是《机械姬》的剧照,左边是跳舞机器人京子,每次只会脱衣服或者跳舞,是制造者的娱乐工具。右边是智能机器人伊娃。在剧中,伊娃成功策反了京子,在京子的帮助下,杀死了她的制造者。

可悲的是,伊娃所做的一切只是为了逃离,所以,她最终将受伤的男主人公抛弃在屋中。

可以肯定的是,一个拥有意识的超级人工智能的存在,将会使得世界进入新的发展时期,但也注定意味着,人类统治时代的终结。

这或许也是 Elon Mask 担心的事情。于是,Elon Mask 捐赠了 1000 万美元用于人工智能安全性方面的研究。在我看来,安全不安全还是取决于机器最终能否有意识。如果最终它有了意识,一切工作都是徒劳。

最后,附上电影《机械姬》一段对话。

就酱,未来无论如何,日子还是得照样过,不是么?

]]>
0
<![CDATA[局部敏感哈希介绍]]> http://www.udpwork.com/item/17005.html http://www.udpwork.com/item/17005.html#reviews Thu, 16 Aug 2018 19:56:14 +0800 鸟窝 http://www.udpwork.com/item/17005.html 传统的Hash当源数据有些许的变化的时候生成的哈希值差异也非常的大, 比如:

12345678910
func main() {	s1 := []byte("你好世界")	s2 := []byte("你好,世界")	hash1 := md5.Sum(s1)	hash2 := md5.Sum(s2)	fmt.Println(hex.EncodeToString(hash1[:]))	fmt.Println(hex.EncodeToString(hash2[:]))}

s1的哈希值是65396ee4aad0b4f17aacd1c6112ee364、s2的哈希值是27444ee2d245c3e8e11ed8b9b035c43b,源数据仅仅是一个逗号的区别,但是哈希值完全不一样。这是我们使用Hash的常见的场景,输出的哈希值经常被称为消息摘要(message digest)或摘要(digest)。

局部敏感哈希(Locality-sensitive hashing, 简称LSH)则不同, LSH则希望相似的源数据计算出来的哈希值越相近越好。
LSH经常用在判重、文章摘要、聚类、相似搜索、近邻查找等场景, 用来减少高维度的数据的维度,相近的数据放在同一个桶中。 比如大规模异常滥用检测:基于局部敏感哈希算法——来自Uber Engineering的实践

学术定义Locality sensitive hashing总是不那么容易让人理解,本文也不试图从学术的角度去介绍LSH, 而是介绍一个特定的LSH算法:simhash。

通用的LSH会基于某个点与点之间的某种距离判定相似性,相近的点距离接近,也就是说,我们可以通过计算距离来比较对象的相似性。距离之间的测量可以分为两大类:

  • 欧几里得距离(Euclidean): 基于空间中的点计算距离
    • 普通的欧几里得距离
    • 曼哈顿距离(Manhattan distance)
    • 闵可夫斯基距离(Minkowski Distance)
  • 非欧几里得距离: 不是根据空间中的位置,而是根据点的属性计算距离
    • 杰卡德距离(Jaccard distance): 1-杰卡德相似系数
    • 余弦距离(Cosine distance)
    • 编辑距离(Edit distance)
    • 汉明距离(Hamming Distance)

当然还有一些距离的计算公式, 比如切比雪夫距离(Chebyshev Distance)、马氏距离(Mahalanobis distance)、Pearson距离等。
这些计算距离的方法会应用在不同的场景中,有时候也会使用不同的距离计算方法进行比较。

不同的LSH会使用不同距离计算方法:

simhash是Google的爬虫用来文档去重。 simhash最牛逼的一点就是将一个文档,最后转换成一个64位的字节,然后判断重复只需要判断他们的特征字的距离是不是小于n(根据经验这个n一般取值为3),就可以判断两个文档是否相似。这大大简化了文档相似性的比较。

Simhash由Moses Charikar, google 2006年做了minhash和simhash的大规模数据的比较,2007年Google说使用simhash用作爬虫去重,使用minhash做新闻个性化

simhash的计算也很简单,

  1. 首先抽取文档的关键字, 比如前10个关键字,以及它们的权重(feature, weight), 记录为[(feature1, weight1), (feature1,weight2), ..., (featuren,weightn)]
  2. 计算feature的hash值,记为[(hash(feature1), weight1), (hash(feature1),weight2), ..., (hash(featuren),weightn)], 如图,假设hash值的bit数为6位,图中第一个feature1的hash值为100110, 权重位weight1。
  3. 然后对这些值按位进行累加,如果这个位是1,则该位上加上他的权重weight,如果是0,则减去weight,最后生成一个6个数字,每个位上一个数字,例如上图中位[13, 108, -22, -5, -32, 55]
  4. 将数值转换成0,1即可 [13, 108, -22, -5, -32, 55] -> 110001, 正值为1,负值为0即可

这样,就可以将一个文档映射成一个数字了,上图中使用6bit,你可以选择合适的大小,比如64比特,可以转化成一个uint64整数。

下一步就是根据simhash值计算两个文档的相似度,使用汉明距离计算,可以方便的使用xor操作。

123
A = 100111;B = 101010;hamming_distance(A, B) = count_1(A xor B) = count_1(001101) = 3;

这个例子中A和B的汉明距离为3。

go标准库中已经有快速计算一个整数的二进制形式中包含1个数的函数:bits.OnesCount64, 使用 <<Hacker's Delight>>中介绍的算法。

Go有几个simhash的实现, 比如mfonda/simhashAllenDang/simhashsimhash-lshsafeie/simhash, 但是对于中文来说,还需要一个中文分词和抽取关键字的功能,这些库对中文不友好,中文文档的比较可以使用yanyiwu/gosimhash以及修改版HaoyuHu/gosimhash

不过我最后计算相似性使用的是bowsim+jieba

##

  1. https://en.wikipedia.org/wiki/Locality-sensitive_hashing
  2. http://web.mit.edu/andoni/www/LSH/
  3. https://medium.com/engineering-brainly/locality-sensitive-hashing-explained-304eb39291e4
  4. https://towardsdatascience.com/understanding-locality-sensitive-hashing-49f6d1f6134
  5. http://jacoxu.com/locality-sensitive-hashing归总/
  6. http://infolab.stanford.edu/~ullman/mining/2009/similarity3.pdf
  7. https://janzhou.org/lsh/
  8. http://www.cs.princeton.edu/courses/archive/spring04/cos598B/bib/CharikarEstim.pdf
  9. https://cloud.tencent.com/developer/article/1082465
]]>
传统的Hash当源数据有些许的变化的时候生成的哈希值差异也非常的大, 比如:

12345678910
func main() {	s1 := []byte("你好世界")	s2 := []byte("你好,世界")	hash1 := md5.Sum(s1)	hash2 := md5.Sum(s2)	fmt.Println(hex.EncodeToString(hash1[:]))	fmt.Println(hex.EncodeToString(hash2[:]))}

s1的哈希值是65396ee4aad0b4f17aacd1c6112ee364、s2的哈希值是27444ee2d245c3e8e11ed8b9b035c43b,源数据仅仅是一个逗号的区别,但是哈希值完全不一样。这是我们使用Hash的常见的场景,输出的哈希值经常被称为消息摘要(message digest)或摘要(digest)。

局部敏感哈希(Locality-sensitive hashing, 简称LSH)则不同, LSH则希望相似的源数据计算出来的哈希值越相近越好。
LSH经常用在判重、文章摘要、聚类、相似搜索、近邻查找等场景, 用来减少高维度的数据的维度,相近的数据放在同一个桶中。 比如大规模异常滥用检测:基于局部敏感哈希算法——来自Uber Engineering的实践

学术定义Locality sensitive hashing总是不那么容易让人理解,本文也不试图从学术的角度去介绍LSH, 而是介绍一个特定的LSH算法:simhash。

通用的LSH会基于某个点与点之间的某种距离判定相似性,相近的点距离接近,也就是说,我们可以通过计算距离来比较对象的相似性。距离之间的测量可以分为两大类:

  • 欧几里得距离(Euclidean): 基于空间中的点计算距离
    • 普通的欧几里得距离
    • 曼哈顿距离(Manhattan distance)
    • 闵可夫斯基距离(Minkowski Distance)
  • 非欧几里得距离: 不是根据空间中的位置,而是根据点的属性计算距离
    • 杰卡德距离(Jaccard distance): 1-杰卡德相似系数
    • 余弦距离(Cosine distance)
    • 编辑距离(Edit distance)
    • 汉明距离(Hamming Distance)

当然还有一些距离的计算公式, 比如切比雪夫距离(Chebyshev Distance)、马氏距离(Mahalanobis distance)、Pearson距离等。
这些计算距离的方法会应用在不同的场景中,有时候也会使用不同的距离计算方法进行比较。

不同的LSH会使用不同距离计算方法:

simhash是Google的爬虫用来文档去重。 simhash最牛逼的一点就是将一个文档,最后转换成一个64位的字节,然后判断重复只需要判断他们的特征字的距离是不是小于n(根据经验这个n一般取值为3),就可以判断两个文档是否相似。这大大简化了文档相似性的比较。

Simhash由Moses Charikar, google 2006年做了minhash和simhash的大规模数据的比较,2007年Google说使用simhash用作爬虫去重,使用minhash做新闻个性化

simhash的计算也很简单,

  1. 首先抽取文档的关键字, 比如前10个关键字,以及它们的权重(feature, weight), 记录为[(feature1, weight1), (feature1,weight2), ..., (featuren,weightn)]
  2. 计算feature的hash值,记为[(hash(feature1), weight1), (hash(feature1),weight2), ..., (hash(featuren),weightn)], 如图,假设hash值的bit数为6位,图中第一个feature1的hash值为100110, 权重位weight1。
  3. 然后对这些值按位进行累加,如果这个位是1,则该位上加上他的权重weight,如果是0,则减去weight,最后生成一个6个数字,每个位上一个数字,例如上图中位[13, 108, -22, -5, -32, 55]
  4. 将数值转换成0,1即可 [13, 108, -22, -5, -32, 55] -> 110001, 正值为1,负值为0即可

这样,就可以将一个文档映射成一个数字了,上图中使用6bit,你可以选择合适的大小,比如64比特,可以转化成一个uint64整数。

下一步就是根据simhash值计算两个文档的相似度,使用汉明距离计算,可以方便的使用xor操作。

123
A = 100111;B = 101010;hamming_distance(A, B) = count_1(A xor B) = count_1(001101) = 3;

这个例子中A和B的汉明距离为3。

go标准库中已经有快速计算一个整数的二进制形式中包含1个数的函数:bits.OnesCount64, 使用 <<Hacker's Delight>>中介绍的算法。

Go有几个simhash的实现, 比如mfonda/simhashAllenDang/simhashsimhash-lshsafeie/simhash, 但是对于中文来说,还需要一个中文分词和抽取关键字的功能,这些库对中文不友好,中文文档的比较可以使用yanyiwu/gosimhash以及修改版HaoyuHu/gosimhash

不过我最后计算相似性使用的是bowsim+jieba

##

  1. https://en.wikipedia.org/wiki/Locality-sensitive_hashing
  2. http://web.mit.edu/andoni/www/LSH/
  3. https://medium.com/engineering-brainly/locality-sensitive-hashing-explained-304eb39291e4
  4. https://towardsdatascience.com/understanding-locality-sensitive-hashing-49f6d1f6134
  5. http://jacoxu.com/locality-sensitive-hashing归总/
  6. http://infolab.stanford.edu/~ullman/mining/2009/similarity3.pdf
  7. https://janzhou.org/lsh/
  8. http://www.cs.princeton.edu/courses/archive/spring04/cos598B/bib/CharikarEstim.pdf
  9. https://cloud.tencent.com/developer/article/1082465
]]>
0
<![CDATA[虚拟文件系统的自举]]> http://www.udpwork.com/item/17004.html http://www.udpwork.com/item/17004.html#reviews Thu, 16 Aug 2018 11:43:13 +0800 云风 http://www.udpwork.com/item/17004.html 我们给游戏引擎设计了一个虚拟文件系统,可以挂接不同的文件系统实现,比如本地文件系统模块,内存文件系统模块,网络文件系统模块。比如前几天谈到的资源仓库,就是一个文件系统模块。

这个虚拟文件系统是用 lua 编写的,这就有了一个小问题:lua 代码本身也是放在虚拟文件系统中的,那么就需要解决自举。这些代码很有可能需要从网络更新(网络文件系统模块),而网络模块也是 lua 编写的,代码同样放在这套文件系统内。

这篇 blog 我想谈谈自举是怎样完成的。

首先我不想做的太复杂。我们不需要特别弹性的不同文件系统模块挂接到虚拟文件系统的不同目录上的功能。所以我写死了一个叫 .firmware 的目录,专门存放用来自举所需的基础代码(的备用版本)。这块代码在启动后可以在网络模块加载完毕后,用新的版本覆盖。

其次,除了非常必要的 C 代码(例如调用 os 的文件访问 api)外,我希望全部用 lua 实现。

但是,所有 lua 代码,包括文件系统的实现都是放在文件系统内的。我们需要初始化 lua 虚拟机,加载必要的代码,然后才能建立起最低可运行的环境。也就是说,建立这个环境时,lua 虚拟机还并不存在。这样就需要解决先有鸡还是先有蛋的问题。

好在我们先封装了 lua 虚拟机模块,简化了使用。我基于它,创建出一个最小可用的虚拟机环境,只用来读取虚拟文件系统支持模块(先不加载网络模块),然后封装成 C API ,藏起 lua vm 这个细节,专供自举阶段使用。当自举完成,就可以销毁这个虚拟机,在正式的环境重新加载相关 Lua 模块了。

大概是这样的:

struct vfs * vfs_init(const char *firmware, const char *repo);
const char * vfs_load(struct vfs *V, const char *path);
void vfs_exit(struct vfs *V);

初始化的时候,传入一个 firmware 的路径,把自举所需的最小 lua 代码放进去。再传入 repo 仓库路径,供 vfs lua 代码可以工作后,作为新版本替代。

也就是说,我先把 bootstrap 的 lua 代码以原生文件的形式,放在 firmware 里,(针对 ios 版,就是打包在 app 中)一开始加载出来使用。用这块代码创建出可以访问 repo 的最小环境(但不包括网络功能)。repo 是我们的资源仓库,里面有上次从网络上同步过来的最新代码。然后,我们从 repo 中再次加载新版本的 vfs 支持代码,之后用最新版本的 vfs 支持代码去访问 repo 仓库中的其它部分。

一旦新版本出了问题,也可以直接把 repo 删干净,回退到最老的 firmware 版本上。

vfs 的 C 实现尽量少嵌入写死的 lua 代码,大约是这样的:

struct vfs {
    struct luavm *L;
    int handle;
};

static int
linitvfs(lua_State *L) {
    luaL_checktype(L,1, LUA_TLIGHTUSERDATA);
    struct vfs ** V = (struct vfs **)lua_touserdata(L, 1);
    *V = lua_newuserdata(L, sizeof(struct vfs));
    return 1;
}

extern int luaopen_winfile(lua_State *L);

static int
lfs(lua_State *L) {
    // todo: use lfs
    return luaopen_winfile(L);
}

static int
cfuncs(lua_State *L) {
    luaL_checkversion(L);
    luaL_Reg l[] = {
        { "initvfs", linitvfs },
        { "lfs", lfs },
        { NULL, NULL },
    };
    luaL_newlib(L, l);
    return 1;
}

static const char * init_source = "local _, firmware = ... ; loadfile(firmware .. '/bootstrap.lua')(...)";

struct vfs *
vfs_init(const char *firmware, const char *dir) {
    struct luavm *L = luavm_new();
    if (L == NULL)
        return NULL;
    struct vfs *V = NULL;
    const char * err = luavm_init(L, init_source, "ssfp", firmware, dir, cfuncs, &V);
    if (err) {
        fprintf(stderr, "Init error: %s\n", err);
        luavm_close(L);
        return NULL;
    }
    if (V == NULL) {
        luavm_close(L);
        return NULL;
    }

    V->L = L;
    err = luavm_register(L, "return _LOAD", "=vfs.load", &V->handle);
    if (err) {
        // register failed
        fprintf(stderr, "Register error: %s\n", err);
        luavm_close(L);
        return NULL;
    }
    return V;
}

void
vfs_exit(struct vfs *V) {
    if (V) {
        luavm_close(V->L);
    }
}

const char *
vfs_load(struct vfs *V, const char *path) {
    const char * ret = NULL;
    const char * err = luavm_call(V->L, V->handle, "sS", path, &ret);
    if (err) {
        fprintf(stderr, "Load error: %s\n", err);
        return NULL;
    }
    return ret;
}

这里在初始化的时候仅仅是用原生的 loadfile 读入了 bootstrap.lua 这个文件而已。所以可以在不动任何 C 代码的基础上做到业务逻辑的更新。

最后来看看 bootstrap.lua 的实现:

local errlog, firmware, dir, cfuncs, V = ...

cfuncs = cfuncs()

package.preload.lfs = cfuncs.lfs    -- init lfs

local vfs = assert(loadfile(firmware .. "/vfs.lua"))()
local repo = vfs.new(firmware, dir)
local f = repo:open(".firmware/vfs.lua")    -- try load vfs.lua in vfs
if f then
    local vfs_source = f:read "a"
    f:close()
    vfs = assert(load(vfs_source, "@.firmware/vfs.lua"))()
    repo = vfs.new(firmware, dir)
end

local function readfile(f)
    if f then
        local content = f:read "a"
        f:close()
        return content
    end
end

local bootstrap = readfile(repo:open(".firmware/bootstrap.lua"))

if bootstrap then
    local newboot = load(bootstrap, "@.firmware/bootstrap.lua")
    local selfchunk = string.dump(debug.getinfo(1, "f").func, true)

    if string.dump(newboot, true) ~= selfchunk then
        -- reload bootstrap
        newboot(...)
        return
    end
end

function _LOAD(path)
    local f = repo:open(path)
    if f then
        local content = f:read "a"
        f:close()
        return content
    end
end

_VFS = cfuncs.initvfs(V)    -- init V , store in _G

它会去加载 vfs.lua 建立一个最小环境,然后用新加载出来的 vfs 模块,重加载 bootstrap.lua 自身,看是否有更新,最终保证采用的是仓库中最新的代码来加载文件。

]]>
我们给游戏引擎设计了一个虚拟文件系统,可以挂接不同的文件系统实现,比如本地文件系统模块,内存文件系统模块,网络文件系统模块。比如前几天谈到的资源仓库,就是一个文件系统模块。

这个虚拟文件系统是用 lua 编写的,这就有了一个小问题:lua 代码本身也是放在虚拟文件系统中的,那么就需要解决自举。这些代码很有可能需要从网络更新(网络文件系统模块),而网络模块也是 lua 编写的,代码同样放在这套文件系统内。

这篇 blog 我想谈谈自举是怎样完成的。

首先我不想做的太复杂。我们不需要特别弹性的不同文件系统模块挂接到虚拟文件系统的不同目录上的功能。所以我写死了一个叫 .firmware 的目录,专门存放用来自举所需的基础代码(的备用版本)。这块代码在启动后可以在网络模块加载完毕后,用新的版本覆盖。

其次,除了非常必要的 C 代码(例如调用 os 的文件访问 api)外,我希望全部用 lua 实现。

但是,所有 lua 代码,包括文件系统的实现都是放在文件系统内的。我们需要初始化 lua 虚拟机,加载必要的代码,然后才能建立起最低可运行的环境。也就是说,建立这个环境时,lua 虚拟机还并不存在。这样就需要解决先有鸡还是先有蛋的问题。

好在我们先封装了 lua 虚拟机模块,简化了使用。我基于它,创建出一个最小可用的虚拟机环境,只用来读取虚拟文件系统支持模块(先不加载网络模块),然后封装成 C API ,藏起 lua vm 这个细节,专供自举阶段使用。当自举完成,就可以销毁这个虚拟机,在正式的环境重新加载相关 Lua 模块了。

大概是这样的:

struct vfs * vfs_init(const char *firmware, const char *repo);
const char * vfs_load(struct vfs *V, const char *path);
void vfs_exit(struct vfs *V);

初始化的时候,传入一个 firmware 的路径,把自举所需的最小 lua 代码放进去。再传入 repo 仓库路径,供 vfs lua 代码可以工作后,作为新版本替代。

也就是说,我先把 bootstrap 的 lua 代码以原生文件的形式,放在 firmware 里,(针对 ios 版,就是打包在 app 中)一开始加载出来使用。用这块代码创建出可以访问 repo 的最小环境(但不包括网络功能)。repo 是我们的资源仓库,里面有上次从网络上同步过来的最新代码。然后,我们从 repo 中再次加载新版本的 vfs 支持代码,之后用最新版本的 vfs 支持代码去访问 repo 仓库中的其它部分。

一旦新版本出了问题,也可以直接把 repo 删干净,回退到最老的 firmware 版本上。

vfs 的 C 实现尽量少嵌入写死的 lua 代码,大约是这样的:

struct vfs {
    struct luavm *L;
    int handle;
};

static int
linitvfs(lua_State *L) {
    luaL_checktype(L,1, LUA_TLIGHTUSERDATA);
    struct vfs ** V = (struct vfs **)lua_touserdata(L, 1);
    *V = lua_newuserdata(L, sizeof(struct vfs));
    return 1;
}

extern int luaopen_winfile(lua_State *L);

static int
lfs(lua_State *L) {
    // todo: use lfs
    return luaopen_winfile(L);
}

static int
cfuncs(lua_State *L) {
    luaL_checkversion(L);
    luaL_Reg l[] = {
        { "initvfs", linitvfs },
        { "lfs", lfs },
        { NULL, NULL },
    };
    luaL_newlib(L, l);
    return 1;
}

static const char * init_source = "local _, firmware = ... ; loadfile(firmware .. '/bootstrap.lua')(...)";

struct vfs *
vfs_init(const char *firmware, const char *dir) {
    struct luavm *L = luavm_new();
    if (L == NULL)
        return NULL;
    struct vfs *V = NULL;
    const char * err = luavm_init(L, init_source, "ssfp", firmware, dir, cfuncs, &V);
    if (err) {
        fprintf(stderr, "Init error: %s\n", err);
        luavm_close(L);
        return NULL;
    }
    if (V == NULL) {
        luavm_close(L);
        return NULL;
    }

    V->L = L;
    err = luavm_register(L, "return _LOAD", "=vfs.load", &V->handle);
    if (err) {
        // register failed
        fprintf(stderr, "Register error: %s\n", err);
        luavm_close(L);
        return NULL;
    }
    return V;
}

void
vfs_exit(struct vfs *V) {
    if (V) {
        luavm_close(V->L);
    }
}

const char *
vfs_load(struct vfs *V, const char *path) {
    const char * ret = NULL;
    const char * err = luavm_call(V->L, V->handle, "sS", path, &ret);
    if (err) {
        fprintf(stderr, "Load error: %s\n", err);
        return NULL;
    }
    return ret;
}

这里在初始化的时候仅仅是用原生的 loadfile 读入了 bootstrap.lua 这个文件而已。所以可以在不动任何 C 代码的基础上做到业务逻辑的更新。

最后来看看 bootstrap.lua 的实现:

local errlog, firmware, dir, cfuncs, V = ...

cfuncs = cfuncs()

package.preload.lfs = cfuncs.lfs    -- init lfs

local vfs = assert(loadfile(firmware .. "/vfs.lua"))()
local repo = vfs.new(firmware, dir)
local f = repo:open(".firmware/vfs.lua")    -- try load vfs.lua in vfs
if f then
    local vfs_source = f:read "a"
    f:close()
    vfs = assert(load(vfs_source, "@.firmware/vfs.lua"))()
    repo = vfs.new(firmware, dir)
end

local function readfile(f)
    if f then
        local content = f:read "a"
        f:close()
        return content
    end
end

local bootstrap = readfile(repo:open(".firmware/bootstrap.lua"))

if bootstrap then
    local newboot = load(bootstrap, "@.firmware/bootstrap.lua")
    local selfchunk = string.dump(debug.getinfo(1, "f").func, true)

    if string.dump(newboot, true) ~= selfchunk then
        -- reload bootstrap
        newboot(...)
        return
    end
end

function _LOAD(path)
    local f = repo:open(path)
    if f then
        local content = f:read "a"
        f:close()
        return content
    end
end

_VFS = cfuncs.initvfs(V)    -- init V , store in _G

它会去加载 vfs.lua 建立一个最小环境,然后用新加载出来的 vfs 模块,重加载 bootstrap.lua 自身,看是否有更新,最终保证采用的是仓库中最新的代码来加载文件。

]]>
0
<![CDATA[Lua 虚拟机的封装]]> http://www.udpwork.com/item/17003.html http://www.udpwork.com/item/17003.html#reviews Wed, 15 Aug 2018 16:06:54 +0800 云风 http://www.udpwork.com/item/17003.html 我打算就我们在开发客户端引擎框架时最近遇到的两个问题写两篇 Blog ,这里先谈第一个问题。

我们的框架技术选型是用 Lua 做开发。和很多 C++ 开发背景(现有大部分的游戏客户端引擎使用 C++ 开发)的人的认知不同,我们并不把 Lua 作为一个嵌入式脚本来看待,而是把它当成一种通用语言来设计整个引擎框架。

其实这更接近 HTML5 流行之后,用 javascript 设计游戏引擎框架:虽然 javascript 的虚拟机本身是用 C++ 开发的,但和游戏引擎相关的部分全部用 javascript 实现,直到涉及渲染的部分,又通过 WebGL 回到 C++ 编写的代码中。这里,我只是把 javascript 换成了 Lua 而已。

选择 Lua 有很大成分是因为我的个人偏好,另一部分原因是 Lua 有优秀的和 C/C++ 代码交互的能力。可以方便地把性能热点模块,在设计上做出良好的抽象后,用 C/C++ 编写高性能的模块,交给 Lua 调用。

但和 Javascript 不同,我们在做原生 App 时,和操作系统打交道的部分还是得用操作系统的语言,C/C++/Objective C/Java 等等。Lua 虚拟机还是要通过一个 C 模块实现嵌入到 App 中去,这个工作得我们自己来完成。

让 Lua VM 置入 App 和操作系统打交道的这部分代码显然是平台相关的,Lua 的 C API 固然简洁,但是还是很庞大的。如果每个平台都直接用 Lua C API 控制虚拟机,这些平台相关的代码还是略显繁杂。我认为,把平台相关代码约束到一个足够小的范围,还需要对 Lua C API 再做一次抽象。

我们面临的需求是:创建一个(或几个)Lua 虚拟机,定期驱动它运行。重点在,定期驱动它运行。这可视为向虚拟机发送消息,虚拟机本质上是消息驱动的(其实 Windows 程序也是)。通常,有一个时钟驱动的行为,或者有一个渲染帧驱动的行为;然后,有外部输入消息,例如触摸屏消息等。

由于整个业务逻辑都是在 Lua 中完成,所以我们并不需要从 Lua VM 中获取什么东西。如果操作系统需要些什么,更多的是传入一个外部库,由 Lua 代码把内部的信息通过库传递出去,而不是外部去获取。裁剪掉后者这个需求,Lua 的 C API 中绝大多数 API 都是不必要的。

我最后设计出来的封装接口只有 5 个 C API :

struct luavm * luavm_new();
const char * luavm_init(struct luavm *L, const char * source, const char *format, ...);
void luavm_close(struct luavm * L);
const char * luavm_register(struct luavm * L, const char * source, const char *chunkname, int *handle);
const char * luavm_call(struct luavm *L, int handle, const char *format, ...);

new init close 是 VM 的构建销毁 API ,我们可以在 init 时传入初始化脚本,从外部注入 Lua 的扩展模块。注意:通过 Lua 的原生 require 机制,在部分平台(如 ios)上,是无法取得外部的 C 模块的。

我的解决方案是写一个符合 lua package searcher 的函数,在初始化的时候替换掉原生的 C 模块 searcher :

static int
preload_searcher(lua_State *L) {
    const char * modname = luaL_checkstring(L,1);
    int i;
    for (i=0;preload[i].name != NULL;i++) {
        if (strcmp(modname, preload[i].name) == 0) {
            lua_pushcfunction(L, preload[i].func);
            return 1;
        }
    }
    lua_pushfstring(L, "\n\tno preload C module '%s'", modname);
    return 1;
}

然后我们就可以把所需的 C 模块的luaopen_xxx静态链接到程序中,放在 preload 数组里就可以让 Lua VM 顺利 require 到。

这里,只提供了一对 register/call API 让外部可以调用一个 VM 中的方法。

我们可以在 register 时注入一段简单的脚本,返回一个 Lua 函数。框架给它绑定一个数字 id ,之后 call 就可以调用这个 handle 对应的函数了。在引擎中,需要暴露到从原生代码直接调用的函数并不会太多,可能只有 update draw message 等寥寥几个。

所有 Lua 调用都有可能抛出 error ,在接口上,我全部用 const char * 来示意是否有 error ,方便原生代码在使用时处理。

但这只是一个后备方案。我更倾向于提供第二种途径,让 Lua VM 内部也可以拿到这些错误信息,这样可以做的更完备。例如,可以把错误 log 通过网络途径发送走,或做更复杂的过滤等。我的方案是,在 init 的时候,框架构建出一个 table ,传给 init 代码。这代码可以把这个 table 记录下来,例如是放在全局变量中。然后每次 VM 的入口函数在运行前,都可以检查这个 table 中有没有新的内容,那就是最后发生的错误信息,处理它再将 table 清空。框架则在每次有新的错误信息后,追加在这个 table 末尾。

让 C 代码向原生代码传递参数,我才用了 C 传统的 format ... 的可变参数形式。format 串中,n 表示 double ,i 表示 integer ,b 表示 boolean ,s 表示 const char * , p 表示 void * ,f 表示lua_CFunction。

另外,我还支持了接收 call 方法从 Lua 中返回一些简单数据类型,用对应的大写字母即可。call 的时候传递指针。比如,向接收一个 int 返回值,就传一个 int * ,这和 scanf 的风格一致。

最后值得一提的时,虽然这个小的 lua vm 封装模块只完成了很微小的工作,但要把事情做对,还是需要谨慎实现的,需要考虑调用 lua c api 时可能发生的任何错误。比如很容易被忽略掉的内存不足的 error 。(lua_pushstring就是有可能抛出异常的,不能裸调)

从 lua 中返回 const char * 也要警惕,避免把可能 gc 的字符串指针返回。我的解决方案是,在虚拟机启动后,创建一个独立的 coroutine 专门作为和外界交换数据的区域。所有可能返回到外界的字符串,但暂时放在这里。所以直到下次在调用 lua 虚拟机前,都可以认为上次返回的字符串是安全的。

最后,放上我的代码做参考。注意,这段代码是从我们开发中的引擎中抽出来的片段,仅作参考,该代码片段不会(因为 bug )持续维护。

]]>
我打算就我们在开发客户端引擎框架时最近遇到的两个问题写两篇 Blog ,这里先谈第一个问题。

我们的框架技术选型是用 Lua 做开发。和很多 C++ 开发背景(现有大部分的游戏客户端引擎使用 C++ 开发)的人的认知不同,我们并不把 Lua 作为一个嵌入式脚本来看待,而是把它当成一种通用语言来设计整个引擎框架。

其实这更接近 HTML5 流行之后,用 javascript 设计游戏引擎框架:虽然 javascript 的虚拟机本身是用 C++ 开发的,但和游戏引擎相关的部分全部用 javascript 实现,直到涉及渲染的部分,又通过 WebGL 回到 C++ 编写的代码中。这里,我只是把 javascript 换成了 Lua 而已。

选择 Lua 有很大成分是因为我的个人偏好,另一部分原因是 Lua 有优秀的和 C/C++ 代码交互的能力。可以方便地把性能热点模块,在设计上做出良好的抽象后,用 C/C++ 编写高性能的模块,交给 Lua 调用。

但和 Javascript 不同,我们在做原生 App 时,和操作系统打交道的部分还是得用操作系统的语言,C/C++/Objective C/Java 等等。Lua 虚拟机还是要通过一个 C 模块实现嵌入到 App 中去,这个工作得我们自己来完成。

让 Lua VM 置入 App 和操作系统打交道的这部分代码显然是平台相关的,Lua 的 C API 固然简洁,但是还是很庞大的。如果每个平台都直接用 Lua C API 控制虚拟机,这些平台相关的代码还是略显繁杂。我认为,把平台相关代码约束到一个足够小的范围,还需要对 Lua C API 再做一次抽象。

我们面临的需求是:创建一个(或几个)Lua 虚拟机,定期驱动它运行。重点在,定期驱动它运行。这可视为向虚拟机发送消息,虚拟机本质上是消息驱动的(其实 Windows 程序也是)。通常,有一个时钟驱动的行为,或者有一个渲染帧驱动的行为;然后,有外部输入消息,例如触摸屏消息等。

由于整个业务逻辑都是在 Lua 中完成,所以我们并不需要从 Lua VM 中获取什么东西。如果操作系统需要些什么,更多的是传入一个外部库,由 Lua 代码把内部的信息通过库传递出去,而不是外部去获取。裁剪掉后者这个需求,Lua 的 C API 中绝大多数 API 都是不必要的。

我最后设计出来的封装接口只有 5 个 C API :

struct luavm * luavm_new();
const char * luavm_init(struct luavm *L, const char * source, const char *format, ...);
void luavm_close(struct luavm * L);
const char * luavm_register(struct luavm * L, const char * source, const char *chunkname, int *handle);
const char * luavm_call(struct luavm *L, int handle, const char *format, ...);

new init close 是 VM 的构建销毁 API ,我们可以在 init 时传入初始化脚本,从外部注入 Lua 的扩展模块。注意:通过 Lua 的原生 require 机制,在部分平台(如 ios)上,是无法取得外部的 C 模块的。

我的解决方案是写一个符合 lua package searcher 的函数,在初始化的时候替换掉原生的 C 模块 searcher :

static int
preload_searcher(lua_State *L) {
    const char * modname = luaL_checkstring(L,1);
    int i;
    for (i=0;preload[i].name != NULL;i++) {
        if (strcmp(modname, preload[i].name) == 0) {
            lua_pushcfunction(L, preload[i].func);
            return 1;
        }
    }
    lua_pushfstring(L, "\n\tno preload C module '%s'", modname);
    return 1;
}

然后我们就可以把所需的 C 模块的luaopen_xxx静态链接到程序中,放在 preload 数组里就可以让 Lua VM 顺利 require 到。

这里,只提供了一对 register/call API 让外部可以调用一个 VM 中的方法。

我们可以在 register 时注入一段简单的脚本,返回一个 Lua 函数。框架给它绑定一个数字 id ,之后 call 就可以调用这个 handle 对应的函数了。在引擎中,需要暴露到从原生代码直接调用的函数并不会太多,可能只有 update draw message 等寥寥几个。

所有 Lua 调用都有可能抛出 error ,在接口上,我全部用 const char * 来示意是否有 error ,方便原生代码在使用时处理。

但这只是一个后备方案。我更倾向于提供第二种途径,让 Lua VM 内部也可以拿到这些错误信息,这样可以做的更完备。例如,可以把错误 log 通过网络途径发送走,或做更复杂的过滤等。我的方案是,在 init 的时候,框架构建出一个 table ,传给 init 代码。这代码可以把这个 table 记录下来,例如是放在全局变量中。然后每次 VM 的入口函数在运行前,都可以检查这个 table 中有没有新的内容,那就是最后发生的错误信息,处理它再将 table 清空。框架则在每次有新的错误信息后,追加在这个 table 末尾。

让 C 代码向原生代码传递参数,我才用了 C 传统的 format ... 的可变参数形式。format 串中,n 表示 double ,i 表示 integer ,b 表示 boolean ,s 表示 const char * , p 表示 void * ,f 表示lua_CFunction。

另外,我还支持了接收 call 方法从 Lua 中返回一些简单数据类型,用对应的大写字母即可。call 的时候传递指针。比如,向接收一个 int 返回值,就传一个 int * ,这和 scanf 的风格一致。

最后值得一提的时,虽然这个小的 lua vm 封装模块只完成了很微小的工作,但要把事情做对,还是需要谨慎实现的,需要考虑调用 lua c api 时可能发生的任何错误。比如很容易被忽略掉的内存不足的 error 。(lua_pushstring就是有可能抛出异常的,不能裸调)

从 lua 中返回 const char * 也要警惕,避免把可能 gc 的字符串指针返回。我的解决方案是,在虚拟机启动后,创建一个独立的 coroutine 专门作为和外界交换数据的区域。所有可能返回到外界的字符串,但暂时放在这里。所以直到下次在调用 lua 虚拟机前,都可以认为上次返回的字符串是安全的。

最后,放上我的代码做参考。注意,这段代码是从我们开发中的引擎中抽出来的片段,仅作参考,该代码片段不会(因为 bug )持续维护。

]]>
0
<![CDATA[游戏资源仓库及升级发布]]> http://www.udpwork.com/item/17002.html http://www.udpwork.com/item/17002.html#reviews Wed, 15 Aug 2018 11:20:47 +0800 云风 http://www.udpwork.com/item/17002.html 去年底,我为我们的 3d engine 设计了资源仓库的结构

随后交给开发组的一个同学实现,这半年来,一直在使用。最近做了引擎一个小版本的内部验收,我感觉这块东西还有比较大的改进余地。因为资源文件系统目前和开发期资源在线更新部分现在掺杂在一起,而网络更新部分似乎还有些 bug ,偶尔会卡住。我觉得定位 bug 成本较高,不如把这块重新实现一遍,顺便把新的改进想法加进去。

这段时间,我重新思考了资源仓库应该怎样设计更合理。越细想越觉得和 git 要解决的问题基本一致。我们的引擎的一个重要特性就是,在 PC 上开发,在移动设备上运行调试。我们需要频繁的将资源同步到设备上,这其实和 git 的运作方式是类似的。我们重新实现的该模块在本地文件系统上的数据组织结构最终也和 git 仓库差不太多了。

这次实现,我们去掉了目录和文件处理方式上的差异,一律都变成了以其内容的 hash 值为文件名(key)的数据块。仓库仅仅是一个 key-value 的数据仓库,以内容 hash (选用了 sha1 算法)为文件名放在仓库目录下。为了避免单个目录文件太多(对大多数文件系统不友好),把内容散列到最多 256 个子目录下。

普通文件就是完全没有修改过的文件本身;而目录是自己建立的索引信息。我采用的是文本格式,一行一个文件描述,记录有文件类型(文件 f 或目录 t )hash 值,文件名。最终一个目录索引文件看起来是这样的:

d 10a34637ad661d98ba3344717656fcc76209c2f8 f0
f da39a3ee5e6b4b0d3255bfef95601890afd80709 f0_1.txt

这表示该目录下有一个子目录 f0 和一个文件 f0_1.txt 。

这样做会使得子目录下任何一个文件的改变,都会改变目录索引本身的 hash 值,进而会影响父目录的 hash 值。也就是说,整个仓库中的任何一点修改,都最终会影响到根目录的索引。

在接口上,我仅提供了从 hash 值 query 数据;修改根目录指针(一个 hash 值);从文本路径查找最终对象的 hash 值等这么几个。

通过不同的根目录指针,我们可以让不同的历史版本存在于同一个仓库中,并且最大限度地重用版本间相同的数据。对于服务器/ PC 编辑器端,我们仅需要提供一个重建索引的操作方法。我们从根索引递归遍历下去,为每个目录创建出索引文件。

和 git 不同的是,我们可以不强制把本地文件系统( git 的工作区)的文件复制到仓库中,而是在仓库中建立一个引用文件。引用文件的文件名使用 hash.ref 的命名方式,表示这个 hash 值对应的实际数据并不在仓库中,而是引用的外部文件。其内容就是外部文件的路径、hash 值和时间戳。由于不同的文件可能内容完全相同,因为一个引用文件可以指向不同的路径,我们会在引用信息中用多行指名;这样在一个文件失效后,还可以依次索引到没有变更的文件。

在快速重建仓库索引时,发现有引用文件,就只比较时间戳。时间戳相同就不必重算 hash 值。

程序以 c/s 结构运行时,在移动设备上先建立一个空的镜像仓库,同步 PC 端的资源仓库。运行流程是这样的:

首先在客户端启动的时候,向服务器索取一个根索引的 hash ,在本地镜像上设定根。

客户端请求一个文件路径时,从根开始寻找对应的目录索引文件,逐级查找。如果本地有所需的 hash 对象,就直接使用;否则向服务器请求,直到最后获得目标文件。api 的设计上,open 一个资源路径,要么返回最终的文件,要么返回一个 hash ,表示当前还缺少这个 hash 对象;这样,可以通过网络模块请求这个对象;获得该对象后,无须理会这个对象是什么,简单写入镜像仓库,然后重新前面的过程,再次请求未完成的路径,最终就能打开所需的资源文件。

这个方式的巧妙之处在于,不需要传统的版本号管理的方式,就可以完美处理多版本问题。客户端和服务器同步过程,只有第一步的根 hash 同步是强制的,且仅同步一个 hash 值。如果移动设备上有多个不同的版本(比如在不同的开发人员的机器上切换),在一开始同步完根 hash 后,完全不用再有任何网络传输。这个过程比 git 切换版本还要快,因为我们在移动设备上没有工作区的概念,不需要在切换版本时拷贝文件到工作区。

在最终版本发布时,也可以做简单的打包,避免小文件过多。简单的把仓库文件打包即可。仓库中就是简单的 key-value 结构,处理包文件比本地文件目录更简单。

同时,发布版本的更新要比传统版本号方式要简单的多。

在发布产品中,我们多半不提供开发期这种按需索要缺少的资源的工作方式,而是将当前版本的所有数据都提前下载后。在这种预下载模式下客户端在启动时从服务器索取一个根 hash ,如果和本地的根相同,则说明版本没有更新;否则,将自己的根 hash (代表了一个版本)发送给服务器。

服务器理论上保留有所有历史发布过的版本,所以会找到这个历史版本。这时服务器可以自己对比这两个版本,计算出客户端缺失的对象,然后打包发送给客户端。

当然,服务器可以缓存一些常见的版本(因为大部分玩家都会停留在上个版本),省略这步比较操作,直接让玩家从 CDN 下载打包好的更新包;对于不常见版本,可以计算出一个最接近的更新包(在 CDN 上),然后把更新包中没有的文件单独打包出来。

这个流程其实和 git 的 fetch 操作非常类似,只不过我们可以针对网游的特质,做一点优化罢了。

因为我们的引擎几乎全部是用 lua 实现,包括这里提到的资源仓库的相关模块,所以理论上这块代码本身也可以被这个仓库管理。这样,还涉及一些代码自举和自更新的流程,这一块的细节也有点意思,我打算过两天另外写一篇 blog 介绍。

]]>
去年底,我为我们的 3d engine 设计了资源仓库的结构

随后交给开发组的一个同学实现,这半年来,一直在使用。最近做了引擎一个小版本的内部验收,我感觉这块东西还有比较大的改进余地。因为资源文件系统目前和开发期资源在线更新部分现在掺杂在一起,而网络更新部分似乎还有些 bug ,偶尔会卡住。我觉得定位 bug 成本较高,不如把这块重新实现一遍,顺便把新的改进想法加进去。

这段时间,我重新思考了资源仓库应该怎样设计更合理。越细想越觉得和 git 要解决的问题基本一致。我们的引擎的一个重要特性就是,在 PC 上开发,在移动设备上运行调试。我们需要频繁的将资源同步到设备上,这其实和 git 的运作方式是类似的。我们重新实现的该模块在本地文件系统上的数据组织结构最终也和 git 仓库差不太多了。

这次实现,我们去掉了目录和文件处理方式上的差异,一律都变成了以其内容的 hash 值为文件名(key)的数据块。仓库仅仅是一个 key-value 的数据仓库,以内容 hash (选用了 sha1 算法)为文件名放在仓库目录下。为了避免单个目录文件太多(对大多数文件系统不友好),把内容散列到最多 256 个子目录下。

普通文件就是完全没有修改过的文件本身;而目录是自己建立的索引信息。我采用的是文本格式,一行一个文件描述,记录有文件类型(文件 f 或目录 t )hash 值,文件名。最终一个目录索引文件看起来是这样的:

d 10a34637ad661d98ba3344717656fcc76209c2f8 f0
f da39a3ee5e6b4b0d3255bfef95601890afd80709 f0_1.txt

这表示该目录下有一个子目录 f0 和一个文件 f0_1.txt 。

这样做会使得子目录下任何一个文件的改变,都会改变目录索引本身的 hash 值,进而会影响父目录的 hash 值。也就是说,整个仓库中的任何一点修改,都最终会影响到根目录的索引。

在接口上,我仅提供了从 hash 值 query 数据;修改根目录指针(一个 hash 值);从文本路径查找最终对象的 hash 值等这么几个。

通过不同的根目录指针,我们可以让不同的历史版本存在于同一个仓库中,并且最大限度地重用版本间相同的数据。对于服务器/ PC 编辑器端,我们仅需要提供一个重建索引的操作方法。我们从根索引递归遍历下去,为每个目录创建出索引文件。

和 git 不同的是,我们可以不强制把本地文件系统( git 的工作区)的文件复制到仓库中,而是在仓库中建立一个引用文件。引用文件的文件名使用 hash.ref 的命名方式,表示这个 hash 值对应的实际数据并不在仓库中,而是引用的外部文件。其内容就是外部文件的路径、hash 值和时间戳。由于不同的文件可能内容完全相同,因为一个引用文件可以指向不同的路径,我们会在引用信息中用多行指名;这样在一个文件失效后,还可以依次索引到没有变更的文件。

在快速重建仓库索引时,发现有引用文件,就只比较时间戳。时间戳相同就不必重算 hash 值。

程序以 c/s 结构运行时,在移动设备上先建立一个空的镜像仓库,同步 PC 端的资源仓库。运行流程是这样的:

首先在客户端启动的时候,向服务器索取一个根索引的 hash ,在本地镜像上设定根。

客户端请求一个文件路径时,从根开始寻找对应的目录索引文件,逐级查找。如果本地有所需的 hash 对象,就直接使用;否则向服务器请求,直到最后获得目标文件。api 的设计上,open 一个资源路径,要么返回最终的文件,要么返回一个 hash ,表示当前还缺少这个 hash 对象;这样,可以通过网络模块请求这个对象;获得该对象后,无须理会这个对象是什么,简单写入镜像仓库,然后重新前面的过程,再次请求未完成的路径,最终就能打开所需的资源文件。

这个方式的巧妙之处在于,不需要传统的版本号管理的方式,就可以完美处理多版本问题。客户端和服务器同步过程,只有第一步的根 hash 同步是强制的,且仅同步一个 hash 值。如果移动设备上有多个不同的版本(比如在不同的开发人员的机器上切换),在一开始同步完根 hash 后,完全不用再有任何网络传输。这个过程比 git 切换版本还要快,因为我们在移动设备上没有工作区的概念,不需要在切换版本时拷贝文件到工作区。

在最终版本发布时,也可以做简单的打包,避免小文件过多。简单的把仓库文件打包即可。仓库中就是简单的 key-value 结构,处理包文件比本地文件目录更简单。

同时,发布版本的更新要比传统版本号方式要简单的多。

在发布产品中,我们多半不提供开发期这种按需索要缺少的资源的工作方式,而是将当前版本的所有数据都提前下载后。在这种预下载模式下客户端在启动时从服务器索取一个根 hash ,如果和本地的根相同,则说明版本没有更新;否则,将自己的根 hash (代表了一个版本)发送给服务器。

服务器理论上保留有所有历史发布过的版本,所以会找到这个历史版本。这时服务器可以自己对比这两个版本,计算出客户端缺失的对象,然后打包发送给客户端。

当然,服务器可以缓存一些常见的版本(因为大部分玩家都会停留在上个版本),省略这步比较操作,直接让玩家从 CDN 下载打包好的更新包;对于不常见版本,可以计算出一个最接近的更新包(在 CDN 上),然后把更新包中没有的文件单独打包出来。

这个流程其实和 git 的 fetch 操作非常类似,只不过我们可以针对网游的特质,做一点优化罢了。

因为我们的引擎几乎全部是用 lua 实现,包括这里提到的资源仓库的相关模块,所以理论上这块代码本身也可以被这个仓库管理。这样,还涉及一些代码自举和自更新的流程,这一块的细节也有点意思,我打算过两天另外写一篇 blog 介绍。

]]>
0
<![CDATA[创建最小的Go docker 镜像]]> http://www.udpwork.com/item/17001.html http://www.udpwork.com/item/17001.html#reviews Tue, 14 Aug 2018 10:57:56 +0800 鸟窝 http://www.udpwork.com/item/17001.html 虽然曾有一些文章介绍了如何创建一个最小的Go Docker镜像,我也曾写过一篇文章,但是随着Go的新的版本的发布, 以及docker本身的进化,有些技巧已经发生了变化, 本文介绍了最新的创建超小的Go镜像的方法。

一个简单Go程序的镜像

首先让我们创建一个很简单的Go程序:

1234567
package mainimport "fmt"func main() {	fmt.Println("hello world")}

运行下面的命令会创建一个超小的镜像, 这是我们的第一种 方式:

1
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go && tar c app | docker import - app:latest

下一节介绍其中的编译参数

查看镜像, 生成的镜像只有1.21MB:

123
# docker images appREPOSITORY          TAG                 IMAGE ID            CREATED             SIZEapp                 latest              b716e13758cd        11 seconds ago      1.21MB

这命令将编译、打包、输入镜像集成到一条命令了。

第二种 方式是使用一个Dockerfile文件:

123
FROM scratchADD app /CMD ["/app"]

运行下面的命令创建一个镜像:

1
docker build -t app2 .

查看生成的镜像, 也是1.21MB:

123
# docker images app2REPOSITORY          TAG                 IMAGE ID            CREATED             SIZEapp2                latest              4e2af2ffb695        4 seconds ago       1.21MB

第三种 方式是利用Docker的 multistage 功能,在镜像中编译,Dockerfile文件:

Dockerfile.multistage
1
docker build -t app3 -f Dockerfile.multistage .

查看生成的镜像, 也是``:

123
# docker images app3REPOSITORY          TAG                 IMAGE ID            CREATED             SIZEapp3                latest              9177859dad64        16 seconds ago      1.21MB

你可以结合你的情况选择一种生成镜像的方式。

编译Go程序

上面的例子中我们使用下面的命令编译Go程序:

1
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go

你可能在其它一些文章中还看到installsuffix参数:

1
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w"  -installsuffix cgo -o app app.go

自Go 1.10以后,你不必再使用installsuffix参数(或许更早的版本),Go的核心开发人员Ian Lance Taylor已经确认了这一点。

你可能有人还使用-a参数,它强制重新编译相关的包,一般你不会使用它。

-s忽略符号表和调试信息,-w忽略DWARF符号表,通过这两个参数,可以进一步减少编译的程序的尺寸,更多的参数可以参考go link, 或者go tool link -help(另一个有用的命令是go tool compile -help)。

你也可以使用strip工具对编译的Go程序进行裁剪。

本身Go是静态编译的, 对于CGO, 如果设置CGO_ENABLED=0,则完全静态编译,不会再依赖动态库。

如果设置CGO_ENABLED=0,并且你的代码中使用了标准库的net包的话,有可能编译好的镜像无法运行,报sh: /app: not found的错误,尽管/app这个文件实际存在,并且如果讲基础镜像换为centos或者ubuntu的话就能执行。这是一个奇怪的错误,原因在于:

默认情况下net包会使用静态链接库, 比如libc

知道了原因,解决办法也很简单,就是完全静态链接或者在基础镜像中加入libc库。

下面是几种解决办法:

  • 设置CGO_ENABLED=0
  • 编译是使用纯go的net:go build -tags netgo -a -v
  • 使用基础镜像加glibc(或等价库musl、uclibc), 比如busybox:glibc、alpine +RUN apk add --no-cache libc6-compat、frolvlad/alpine-glibc

有的同学说了,我代码中确实必须使用CGO,因为需要依赖一些C/C++的库。目前没有对应的Go库可替代, 那么可以使用-extldflags "-static",go tool link help介绍了extldflags的功能:

-extldflags flags
Set space-separated flags to pass to the external linker.

-static means do not link against shared libraries

基础镜像

其实前面已经列出了一些常用的基础镜像:

  • scratch: 空的基础镜像,最小的基础镜像
  • busybox: 带一些常用的工具,方便调试, 以及它的一些扩展busybox:glibc
  • alpine: 另一个常用的基础镜像,带包管理功能,方便下载其它依赖的包

显然。 你应该只在编译阶段使用Go的镜像,这样才能将你的镜像减小到最小。

]]>
虽然曾有一些文章介绍了如何创建一个最小的Go Docker镜像,我也曾写过一篇文章,但是随着Go的新的版本的发布, 以及docker本身的进化,有些技巧已经发生了变化, 本文介绍了最新的创建超小的Go镜像的方法。

一个简单Go程序的镜像

首先让我们创建一个很简单的Go程序:

1234567
package mainimport "fmt"func main() {	fmt.Println("hello world")}

运行下面的命令会创建一个超小的镜像, 这是我们的第一种 方式:

1
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go && tar c app | docker import - app:latest

下一节介绍其中的编译参数

查看镜像, 生成的镜像只有1.21MB:

123
# docker images appREPOSITORY          TAG                 IMAGE ID            CREATED             SIZEapp                 latest              b716e13758cd        11 seconds ago      1.21MB

这命令将编译、打包、输入镜像集成到一条命令了。

第二种 方式是使用一个Dockerfile文件:

123
FROM scratchADD app /CMD ["/app"]

运行下面的命令创建一个镜像:

1
docker build -t app2 .

查看生成的镜像, 也是1.21MB:

123
# docker images app2REPOSITORY          TAG                 IMAGE ID            CREATED             SIZEapp2                latest              4e2af2ffb695        4 seconds ago       1.21MB

第三种 方式是利用Docker的 multistage 功能,在镜像中编译,Dockerfile文件:

Dockerfile.multistage
1
docker build -t app3 -f Dockerfile.multistage .

查看生成的镜像, 也是``:

123
# docker images app3REPOSITORY          TAG                 IMAGE ID            CREATED             SIZEapp3                latest              9177859dad64        16 seconds ago      1.21MB

你可以结合你的情况选择一种生成镜像的方式。

编译Go程序

上面的例子中我们使用下面的命令编译Go程序:

1
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go

你可能在其它一些文章中还看到installsuffix参数:

1
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w"  -installsuffix cgo -o app app.go

自Go 1.10以后,你不必再使用installsuffix参数(或许更早的版本),Go的核心开发人员Ian Lance Taylor已经确认了这一点。

你可能有人还使用-a参数,它强制重新编译相关的包,一般你不会使用它。

-s忽略符号表和调试信息,-w忽略DWARF符号表,通过这两个参数,可以进一步减少编译的程序的尺寸,更多的参数可以参考go link, 或者go tool link -help(另一个有用的命令是go tool compile -help)。

你也可以使用strip工具对编译的Go程序进行裁剪。

本身Go是静态编译的, 对于CGO, 如果设置CGO_ENABLED=0,则完全静态编译,不会再依赖动态库。

如果设置CGO_ENABLED=0,并且你的代码中使用了标准库的net包的话,有可能编译好的镜像无法运行,报sh: /app: not found的错误,尽管/app这个文件实际存在,并且如果讲基础镜像换为centos或者ubuntu的话就能执行。这是一个奇怪的错误,原因在于:

默认情况下net包会使用静态链接库, 比如libc

知道了原因,解决办法也很简单,就是完全静态链接或者在基础镜像中加入libc库。

下面是几种解决办法:

  • 设置CGO_ENABLED=0
  • 编译是使用纯go的net:go build -tags netgo -a -v
  • 使用基础镜像加glibc(或等价库musl、uclibc), 比如busybox:glibc、alpine +RUN apk add --no-cache libc6-compat、frolvlad/alpine-glibc

有的同学说了,我代码中确实必须使用CGO,因为需要依赖一些C/C++的库。目前没有对应的Go库可替代, 那么可以使用-extldflags "-static",go tool link help介绍了extldflags的功能:

-extldflags flags
Set space-separated flags to pass to the external linker.

-static means do not link against shared libraries

基础镜像

其实前面已经列出了一些常用的基础镜像:

  • scratch: 空的基础镜像,最小的基础镜像
  • busybox: 带一些常用的工具,方便调试, 以及它的一些扩展busybox:glibc
  • alpine: 另一个常用的基础镜像,带包管理功能,方便下载其它依赖的包

显然。 你应该只在编译阶段使用Go的镜像,这样才能将你的镜像减小到最小。

]]>
0
<![CDATA[API 之下]]> http://www.udpwork.com/item/17000.html http://www.udpwork.com/item/17000.html#reviews Mon, 13 Aug 2018 07:33:02 +0800 阮一峰 http://www.udpwork.com/item/17000.html 虽然标题里面有 API,但是本文谈的不是编程,而是更重要的事情。

很多公司的组织架构,都有一个中层。高层领导和基层员工之间,存在大量的中层干部。公司越大,中层干部越多。

2015年,硅谷创业家莱因哈特(Peter Reinhardt)观察到一个现象:硅谷科技公司正在变得越来越大,但是公司的中层几乎没有变大。原因就在于,大公司正在用 API 替代掉中层干部。

所谓 API,就是软件的接口。通过 API,软件接受外部指令,并且输出结果。莱因哈特发现,高层通过软件,直接给基层下达任务,因此不需要中层了。

举例来说,外卖送餐员就没有领导,他们直接从 API 接受任务,然后把送餐结果回报给 API。不仅是外包员工,现在的趋势是公司内部也采用这种管理方式,将日常管理制度化和标准化,基层员工通过 API 获知并完成公司下达的任务。

阿里和腾讯这样的大型互联网公司,只有几万人,但是他们的营业额和业务范围之大,如果换成传统公司,至少需要几十万人。为什么几万人可以做成几十万人的事情?原因之一就是,阿里和腾讯都有很强大的内部网络,员工的各种需求,不需要找领导,直接到内网查询或填写表单就可以了。传统上,中层干部承担的管理职责,都被内部网络取代了。

这种趋势发展下去,长期来看,未来只有两种工作:API 之上的工作和 API 之下的工作。 API 之上就是制定 API 规则、给 API 下达指令的人。API 之下就是接受 API 指令进行工作的人。

福布斯杂志根据莱因哈特的观点,绘制了一张趋势图。

2005年,亚马逊推出Mechanical Turk,允许世界各地的人们到该网站接单,完成任务后领取报酬。这就是第一种 API 之下的工作,此后这类工作不断增加,直到今天。

预计到2020年,人工智能广泛应用以后,API 之下的工作将急剧增加,API 之上的工作将急剧减少,未来的大部分工作岗位都是 API 之下的工作,大部分人都要接受软件的指令工作。同时,由于机器人越来越强大,会抢走一部分工作,以后想找一份 API 之下的工作恐怕也不容易。

很显然,API 之下的工作是比较差的,因为报酬较低、竞争激烈,能不能拿到活、工作业绩的评价都取决于别人,所以远不如 API 之上的工作。而且,API 不会对你进行职业培训,也不会关心你的职业生涯。莱因哈特说:"一旦管理层和基层员工之间引入软件层,就没有了明显的向上路径",基层员工将毫无晋升到管理层的途径。

软件正在变得越来越强大,用途越来越广,那么 API 层将越来越厚。未来的年轻人生活在 API 之下,抬头向上看,只会看到一个无边无际的软件层,根本不知道如何爬到云端,去做那些 API 之上的工作。

(完)

文档信息

]]>
虽然标题里面有 API,但是本文谈的不是编程,而是更重要的事情。

很多公司的组织架构,都有一个中层。高层领导和基层员工之间,存在大量的中层干部。公司越大,中层干部越多。

2015年,硅谷创业家莱因哈特(Peter Reinhardt)观察到一个现象:硅谷科技公司正在变得越来越大,但是公司的中层几乎没有变大。原因就在于,大公司正在用 API 替代掉中层干部。

所谓 API,就是软件的接口。通过 API,软件接受外部指令,并且输出结果。莱因哈特发现,高层通过软件,直接给基层下达任务,因此不需要中层了。

举例来说,外卖送餐员就没有领导,他们直接从 API 接受任务,然后把送餐结果回报给 API。不仅是外包员工,现在的趋势是公司内部也采用这种管理方式,将日常管理制度化和标准化,基层员工通过 API 获知并完成公司下达的任务。

阿里和腾讯这样的大型互联网公司,只有几万人,但是他们的营业额和业务范围之大,如果换成传统公司,至少需要几十万人。为什么几万人可以做成几十万人的事情?原因之一就是,阿里和腾讯都有很强大的内部网络,员工的各种需求,不需要找领导,直接到内网查询或填写表单就可以了。传统上,中层干部承担的管理职责,都被内部网络取代了。

这种趋势发展下去,长期来看,未来只有两种工作:API 之上的工作和 API 之下的工作。 API 之上就是制定 API 规则、给 API 下达指令的人。API 之下就是接受 API 指令进行工作的人。

福布斯杂志根据莱因哈特的观点,绘制了一张趋势图。

2005年,亚马逊推出Mechanical Turk,允许世界各地的人们到该网站接单,完成任务后领取报酬。这就是第一种 API 之下的工作,此后这类工作不断增加,直到今天。

预计到2020年,人工智能广泛应用以后,API 之下的工作将急剧增加,API 之上的工作将急剧减少,未来的大部分工作岗位都是 API 之下的工作,大部分人都要接受软件的指令工作。同时,由于机器人越来越强大,会抢走一部分工作,以后想找一份 API 之下的工作恐怕也不容易。

很显然,API 之下的工作是比较差的,因为报酬较低、竞争激烈,能不能拿到活、工作业绩的评价都取决于别人,所以远不如 API 之上的工作。而且,API 不会对你进行职业培训,也不会关心你的职业生涯。莱因哈特说:"一旦管理层和基层员工之间引入软件层,就没有了明显的向上路径",基层员工将毫无晋升到管理层的途径。

软件正在变得越来越强大,用途越来越广,那么 API 层将越来越厚。未来的年轻人生活在 API 之下,抬头向上看,只会看到一个无边无际的软件层,根本不知道如何爬到云端,去做那些 API 之上的工作。

(完)

文档信息

]]>
0
<![CDATA[《雪国》《湖》]]> http://www.udpwork.com/item/16999.html http://www.udpwork.com/item/16999.html#reviews Sun, 12 Aug 2018 17:34:04 +0800 qyjohn http://www.udpwork.com/item/16999.html 847bb9256dc3ca5d5f7b285b780b277a_500x500.webp

《雪国》,用美丽到窒息的景物描写反衬出悲哀到绝望的人生,是川端康成惯用的手法。

《湖》,使用了蒙太奇的手法,时间与空间往复切换,在之前读到的几本书里面均未曾见到。第一个故事由洗澡女开始,细致入微的描写引人入胜而恰如其分,不可不谓是“先以欲勾牵,后令入佛智”的经典之作。

]]>
847bb9256dc3ca5d5f7b285b780b277a_500x500.webp

《雪国》,用美丽到窒息的景物描写反衬出悲哀到绝望的人生,是川端康成惯用的手法。

《湖》,使用了蒙太奇的手法,时间与空间往复切换,在之前读到的几本书里面均未曾见到。第一个故事由洗澡女开始,细致入微的描写引人入胜而恰如其分,不可不谓是“先以欲勾牵,后令入佛智”的经典之作。

]]>
0
<![CDATA[直觉的陷阱 - 读《思考快与慢》]]> http://www.udpwork.com/item/16998.html http://www.udpwork.com/item/16998.html#reviews Sat, 11 Aug 2018 09:08:59 +0800 唐巧 http://www.udpwork.com/item/16998.html 最近读完了《思考快与慢》,本书的作者是丹尼尔·卡尼曼。本书作者卡尼曼非常厉害,他由于在展望理论(prospect theory,也被称作前景理论)的贡献,获得了 2002 年诺贝尔经济学奖。

卡尼曼本人其实是一个心理学家,他将心理学研究的视角与经济科学结合起来,成为这一新领域的奠基人。在他之前,经济学和心理学在研究人类决策行为上有着极大的区别:经济学的观点认为外在的激励形成人们的行为,而心理学恰恰相反,认为内在的激励才是决定行为的因素。

卡尼曼最重要的成果是关于不确定情形下人类决策的研究,他证明了人类的决策行为如何系统性地偏离标准经济理论所预测的结果。

这一本《思考快与慢》就是他的代表作品。思考的两个系统、展望理论等观点都在书中得到了详细阐述。该书也获得了《纽约时报》2011 年度十大好书。

下面我介绍一下该书的主要内容。

系统 1 和 系统 2

本书在第一部分中,先介绍了人类思考决策的两个系统:

  • 系统 1:直觉性思维。
  • 系统 2:理性思维。

系统 1 大部分时候都在主动工作,相当于我们的直觉系统。它帮助我们产生印象、感觉、倾向、直觉。

系统 2 大部分时候都躲在系统 1 之后,只有觉查到系统 1 需要帮助的时候,系统 2 才会介入。

对于程序员来说,系统 1 有点类似于计算机的缓存,又可以类比为深度学习训练之后的模型。总之,系统 1 就是快速的、低功耗的、偏直觉和经验的。

系统 2 代表着我们的大脑进入了高速运转模式。缓存失效,模型不适用,CPU 占用率飙升,耗电量也快速升高。除了游戏中常见的「心流」状态外,其它时候,人们都有着逃避使用系统 2 的倾向,原因很简单:累!

不知道大家上大学的时候会不会有这样的经历:上课时努力听老师讲课,但是特别容易分神,一不小心就开小差,而且集中一段时间失败之后,还会特别容易犯困,感觉老师的话就像是催眠曲一样。好不容易下课了,一下子不困了,特别精神。这是我对于逃避系统 2 的亲身体会。

启发法与偏见

在介绍完两个系统后,作者就开始介绍系统 1 给大家带来的各种有趣的认识偏见。

小数定律

小数定律是说,在样本足够小的时候,几乎一定会产生结论偏差,而人们的系统 1 会在潜意识里,对这些偏差进行总结,形成不合理的结论。

书中的例子是:

一项研究对美国 3141 个县的肾癌发病率进行了调查,调查显示该病的分布模式很值得注意。发病率最低的县差不多都位于中西部、南部和西部人口稀少的乡村,这些区域按照惯例由共和党管辖。对此,你有何看法?

由于人口稀少的乡村本身样本量就偏小,所以它更可能产生极端情况,即发病率最低或者发病率最高。但是人们根本注意不到这些。人们更喜欢用直觉解释这些现象,比如:

  • 当乡村发病率最低的时候,大家归结为乡下的空气好,没有污染
  • 当乡村发病率最高的时候,大家归结为乡下的医疗条件差,抽烟喝酒等习惯不好

我自己也有一个例子,我们公司的好多程序员同事都到了要小孩的年纪,然后我们发现每个人的小孩都是女孩,于是,我们就总结了一个「码农生女」的结论。但是有一天,我们的一个同事张导生了个男孩,于是我们的结论变成了:「除了张导,公司的码农都生女」的结论。

你看看,大家潜意识在解释这个世界的时候,总是在寻找规律,因为规律使得记忆变得简单,让理解世界变得容易。而小数定律背后的真相就这样被人们忽视了。

锚定效应

锚定效应的使用随处可见,最多的案例都是在商业环境中。当商品在制定价格时,都需要说服消费者接受,这个时候,寻找一个锚定就容易说服得多了。

蔚来汽车的价格明显高出国内的其它电动车品牌,于是他就把体验店开到特斯拉附近,各种参数对标特斯拉,于是大家拿他和特斯拉比,一下子觉得好便宜哟。

作者在书中举了一个特别夸张的实验:

甘地去世时比 144 岁大还是小?
甘地去世时多少岁?

虽然 144 岁已经是不符合逻辑了,人类社会没有人活了这么久,但是人们在回答这个问题的时候,还是会受 144 岁这个锚定的影响。

可得性偏见

人们会根据自己凭印象的感觉,来对事情做评价。所以,离得近的事情印象深,所以在评价的时候占的比重也会重。

公司在做绩效评估的时候,通常都会年中做一次,年底再做一次,两次结合起来决定年终奖。为什么不发年终奖的时候做一次就好呢?原因就是「可得性偏见」。有了年中那一次绩效的记录,年底的综合评估会更加平衡上半年的表现。

焦虑风险

我们的大脑解决小风险的能力有一个基本限度:我们要么完全忽视风险,要么过于重视风险,没有中间地带。

而媒体对风险的报道通常会产生「效用叠层」:一种集体信念形成的自我增强过程。看看多次在朋友圈被刷爆的文章就能够理解这种现象。

最终,人们并不是理性地按风险产生的概率来做决策,而是按对风险的「感觉」来做决策。

其它

书中提到的相关现象太多,随便再举几个:

  • 少即是多:通常越复杂的描述越让人感受到真实,而忽略了越复杂,概率越低这件事情。贵重的东西如果附加一个看起来廉价的东西,反倒会拉低整体的价格。
  • 光环效应:人们通常在潜意识里认为:一个人好,他就在各方面就好。一个人坏,那他在各方面都坏。这被称为:光环效应。光环效应通过夸大评估的一致性来保持逻辑的简单和连贯。
  • 重视典型:看到一个人长得又高又帅,就猜测他是做模特的。看到一个人瘦小,就猜测他不喜欢运动。

过度自信与决策失误

叙事谬误

介绍完各种认知偏见,就进入了本书的第三部分。作者在第三部分先介绍了过度自信产生的原因:叙事谬误。即人们通常喜欢简单的故事,清晰的逻辑。于是,被广泛传播的故事都是那些通俗易懂,具体而不抽象的故事。而这些故事都忽视了运气的成份。上一部分提到的光环效应,也同样加强了人们在认识上的偏见。

接着作者介绍了后见之明和结果偏见。

后见之明和结果偏见

后见之明是说,人们总是喜欢事后诸葛亮。当事情有结果时,每个人都认为自己早就可以理解和预见这种情况。对付这种情况,我特别喜欢德鲁克的办法:即把自己的观点写下来,然后过一段时间再看。这样自己就很难回避自己观点的错误了。正视错误之后,自己就可以调整和总结。

结果偏见是说,当坏事情没有发生之前,大家不觉得相关负责人有什么功劳。当坏事情发生了,大家就会觉得相关负责人水平不行。这个心理认知在很多行业非常普遍。比如:在企业里面做安全防范就是这样。如果你做得好,什么事情都没有发生,老板很可能认为你不重要,或者没做什么事情。当安全问题发生了,无论你之前做得多么好,老板都会认为你不称职。

结果偏见可能是我见过的最最难以解决的认知问题了。我了解到很多公司里面,CEO 和 CTO 之间也常常会发生这样的结果偏见。明明需求很复杂,技术挑战很多,技术团队拼尽全力上线了,结果老板可能还觉得你做得慢。理由可能是:别的团队做一个类似的,只花了两天时间。但是,非技术出身的老板很难理解:

  • 技术团队可能有很多历史的积累和债务
  • 团队可能同时并行着多个项目
  • 类似的产品需求并不是完全一样,差异的部分看起来很小,但是技术复杂度完全不一样
  • 别的团队可能有类似项目的积累

直觉什么时候有效

在这一部分,作者也认真讨论了一下直觉在什么时候是有用的。作者承认《眨眼之间》一书中提到的直觉的有效性,但是作者觉得获得这种专家的直觉是有条件的,条件是:

  1. 环境有规律,可预测。例如医生、护士、消防员、棋手的工作场景。
  2. 可通过长期训练来学习这些规律。

我在上一篇《iOS 面试之道》的文章中也提到,我觉得面试也符合上面的场景。环境固定,讨论内容偏固定,所以一个长期面试别的人面试官,可能就会形成判断人的一种直觉。

好的决策方法

在做决策的时候,作者推荐了一些实践方法,例如:努力养成采纳外部意见的习惯。因为内部意见通常充斥了乐观。

又比如,抑制乐观主义情绪的实践方法:事前验尸。我们假设这个项目未来失败了,然后总结这次失败的原因。通常从这个角度思考,我们就可以认真重视各种可能的风险。

事前验尸观点有两个主要优点:决策快要制定好时,许多团队成员会受到集体思考的影响,而事前验尸则扼制住了这种影响。另外,它还激发了那些见多识广的个人的想象力,并将他们的想法引导到最需要它们的方向。

我听 Annie 讲如何在腾讯做投资的经验,她提到过一个 Tips:当你觉得这个被投公司未来有可能因为什么失败的时候,通常这种担心都会发生。我就是一个活生生的事前验尸的决策角度。

选择与风险

前景理论

好了,终于讲到作者著名的展望理论(prospect theory,也被称作前景理论),在第四部分「选择与风险」中,作者介绍了传统的理论根本站不住脚,人们对于收益和风险的感受并不均等。

简单来说,所有人都是风险厌恶型的,丢 100 块钱带来的痛苦,比捡 100 块钱带来的快乐强。所以,就会有很多符合这种逻辑的行为产生。以下就是作者关于这个理论最经典的图了:

人们如果要克服这种行为,就只能靠系统 2 来帮助你拜托这种直觉影响。

禀赋效应

禀赋效应是指当个人一旦拥有某个物品,那么他对该物品价值的评价要比未拥有之前大大提高。

泰勒发现 R 教授非常不愿意卖掉自己收藏的葡萄酒,即使对方出价高达 100 美元(当时可是 1975 年)一瓶也不行。R 教授也会从拍卖会上买葡萄酒,但无论质量如何,他出价从不会高过 35 美元一瓶。若价格在 35 美元~100 美元,他就既不买也不卖。这个巨大的价格差在经济理论上看是相互矛盾的,人们希望这位教授能在这个价格区间为某瓶酒定一个值。低于这个值就应该买,高于这个值就应该卖。
这个可以接受的卖价和可以接受的买价应该相同,但事实上,最低卖价(100 美元)比最高买价(35 美元)高出很多,拥有这件物品似乎会提升它的价值。

前景理论也可以用来解释禀赋效应。因为除了商人做生意,普通人卖某些自己的东西的时候,会引起他对于损失的厌恶。

两个自我

两个自我指的是感受当下的经验自我以及记录并作出选择的记忆自我。在书的最后一部分,作者选择讨论人们的选择性记忆。作者发现,人们的记忆非常不可靠。

峰终定律,指我们对一件事物的记忆仅限于高峰和结尾,事件过程对记忆几乎没有影响。高峰之后,终点出现得越迅速,这件事留给我们的印象越深刻。

人们过于在乎结尾,以致于比起整个人生,我们更在意人生的结局。一个穷人辛苦一辈子,晚年终于可以享受几年福气,远远好过一个地主儿子逍遥地活了一辈子,晚年过得穷困潦倒。但是其实从快活的时间来看,地主儿子明显更多。

小结

作者首先在书中引入了两个虚拟人物,分别是运用直觉、进行快速思考的系统 1 和需付出努力、运行更慢的系统 2。系统 2 进行的是慢思考,能监督系统 1 的运作,并在其自身有限的能力下尽可能地占据控制地位。

然后介绍了两个物种,分别是活在理论世界的虚拟经济人以及活在现实世界的人类。

最后介绍了两个自我,指的是感受当下的经验自我以及记录并作出选择的记忆自我。

由于两个系统的差异,所以人类产生了各种奇怪的、不符合经济学规律的行为和认知。

本书列举了相当多的这方面的例子,如:小数定律、可得性偏见、峰终定律、前景理论等。

作者在书中也提供了相当多让系统 2 接管系统 1 的实践,例如:事前验尸。其实了解这些非理性行为本身,也会使得我们在遇到相关场景的时候,激活系统 2 帮助我们做决策。

如果说这本书有什么缺点的话,就是太长了一些,论述稍显啰嗦。这可能是因为作者是心理学家,比较严谨的原因。这是我读的第一本诺贝尔经济学奖获得者作品,推荐给大家。

]]>
最近读完了《思考快与慢》,本书的作者是丹尼尔·卡尼曼。本书作者卡尼曼非常厉害,他由于在展望理论(prospect theory,也被称作前景理论)的贡献,获得了 2002 年诺贝尔经济学奖。

卡尼曼本人其实是一个心理学家,他将心理学研究的视角与经济科学结合起来,成为这一新领域的奠基人。在他之前,经济学和心理学在研究人类决策行为上有着极大的区别:经济学的观点认为外在的激励形成人们的行为,而心理学恰恰相反,认为内在的激励才是决定行为的因素。

卡尼曼最重要的成果是关于不确定情形下人类决策的研究,他证明了人类的决策行为如何系统性地偏离标准经济理论所预测的结果。

这一本《思考快与慢》就是他的代表作品。思考的两个系统、展望理论等观点都在书中得到了详细阐述。该书也获得了《纽约时报》2011 年度十大好书。

下面我介绍一下该书的主要内容。

系统 1 和 系统 2

本书在第一部分中,先介绍了人类思考决策的两个系统:

  • 系统 1:直觉性思维。
  • 系统 2:理性思维。

系统 1 大部分时候都在主动工作,相当于我们的直觉系统。它帮助我们产生印象、感觉、倾向、直觉。

系统 2 大部分时候都躲在系统 1 之后,只有觉查到系统 1 需要帮助的时候,系统 2 才会介入。

对于程序员来说,系统 1 有点类似于计算机的缓存,又可以类比为深度学习训练之后的模型。总之,系统 1 就是快速的、低功耗的、偏直觉和经验的。

系统 2 代表着我们的大脑进入了高速运转模式。缓存失效,模型不适用,CPU 占用率飙升,耗电量也快速升高。除了游戏中常见的「心流」状态外,其它时候,人们都有着逃避使用系统 2 的倾向,原因很简单:累!

不知道大家上大学的时候会不会有这样的经历:上课时努力听老师讲课,但是特别容易分神,一不小心就开小差,而且集中一段时间失败之后,还会特别容易犯困,感觉老师的话就像是催眠曲一样。好不容易下课了,一下子不困了,特别精神。这是我对于逃避系统 2 的亲身体会。

启发法与偏见

在介绍完两个系统后,作者就开始介绍系统 1 给大家带来的各种有趣的认识偏见。

小数定律

小数定律是说,在样本足够小的时候,几乎一定会产生结论偏差,而人们的系统 1 会在潜意识里,对这些偏差进行总结,形成不合理的结论。

书中的例子是:

一项研究对美国 3141 个县的肾癌发病率进行了调查,调查显示该病的分布模式很值得注意。发病率最低的县差不多都位于中西部、南部和西部人口稀少的乡村,这些区域按照惯例由共和党管辖。对此,你有何看法?

由于人口稀少的乡村本身样本量就偏小,所以它更可能产生极端情况,即发病率最低或者发病率最高。但是人们根本注意不到这些。人们更喜欢用直觉解释这些现象,比如:

  • 当乡村发病率最低的时候,大家归结为乡下的空气好,没有污染
  • 当乡村发病率最高的时候,大家归结为乡下的医疗条件差,抽烟喝酒等习惯不好

我自己也有一个例子,我们公司的好多程序员同事都到了要小孩的年纪,然后我们发现每个人的小孩都是女孩,于是,我们就总结了一个「码农生女」的结论。但是有一天,我们的一个同事张导生了个男孩,于是我们的结论变成了:「除了张导,公司的码农都生女」的结论。

你看看,大家潜意识在解释这个世界的时候,总是在寻找规律,因为规律使得记忆变得简单,让理解世界变得容易。而小数定律背后的真相就这样被人们忽视了。

锚定效应

锚定效应的使用随处可见,最多的案例都是在商业环境中。当商品在制定价格时,都需要说服消费者接受,这个时候,寻找一个锚定就容易说服得多了。

蔚来汽车的价格明显高出国内的其它电动车品牌,于是他就把体验店开到特斯拉附近,各种参数对标特斯拉,于是大家拿他和特斯拉比,一下子觉得好便宜哟。

作者在书中举了一个特别夸张的实验:

甘地去世时比 144 岁大还是小?
甘地去世时多少岁?

虽然 144 岁已经是不符合逻辑了,人类社会没有人活了这么久,但是人们在回答这个问题的时候,还是会受 144 岁这个锚定的影响。

可得性偏见

人们会根据自己凭印象的感觉,来对事情做评价。所以,离得近的事情印象深,所以在评价的时候占的比重也会重。

公司在做绩效评估的时候,通常都会年中做一次,年底再做一次,两次结合起来决定年终奖。为什么不发年终奖的时候做一次就好呢?原因就是「可得性偏见」。有了年中那一次绩效的记录,年底的综合评估会更加平衡上半年的表现。

焦虑风险

我们的大脑解决小风险的能力有一个基本限度:我们要么完全忽视风险,要么过于重视风险,没有中间地带。

而媒体对风险的报道通常会产生「效用叠层」:一种集体信念形成的自我增强过程。看看多次在朋友圈被刷爆的文章就能够理解这种现象。

最终,人们并不是理性地按风险产生的概率来做决策,而是按对风险的「感觉」来做决策。

其它

书中提到的相关现象太多,随便再举几个:

  • 少即是多:通常越复杂的描述越让人感受到真实,而忽略了越复杂,概率越低这件事情。贵重的东西如果附加一个看起来廉价的东西,反倒会拉低整体的价格。
  • 光环效应:人们通常在潜意识里认为:一个人好,他就在各方面就好。一个人坏,那他在各方面都坏。这被称为:光环效应。光环效应通过夸大评估的一致性来保持逻辑的简单和连贯。
  • 重视典型:看到一个人长得又高又帅,就猜测他是做模特的。看到一个人瘦小,就猜测他不喜欢运动。

过度自信与决策失误

叙事谬误

介绍完各种认知偏见,就进入了本书的第三部分。作者在第三部分先介绍了过度自信产生的原因:叙事谬误。即人们通常喜欢简单的故事,清晰的逻辑。于是,被广泛传播的故事都是那些通俗易懂,具体而不抽象的故事。而这些故事都忽视了运气的成份。上一部分提到的光环效应,也同样加强了人们在认识上的偏见。

接着作者介绍了后见之明和结果偏见。

后见之明和结果偏见

后见之明是说,人们总是喜欢事后诸葛亮。当事情有结果时,每个人都认为自己早就可以理解和预见这种情况。对付这种情况,我特别喜欢德鲁克的办法:即把自己的观点写下来,然后过一段时间再看。这样自己就很难回避自己观点的错误了。正视错误之后,自己就可以调整和总结。

结果偏见是说,当坏事情没有发生之前,大家不觉得相关负责人有什么功劳。当坏事情发生了,大家就会觉得相关负责人水平不行。这个心理认知在很多行业非常普遍。比如:在企业里面做安全防范就是这样。如果你做得好,什么事情都没有发生,老板很可能认为你不重要,或者没做什么事情。当安全问题发生了,无论你之前做得多么好,老板都会认为你不称职。

结果偏见可能是我见过的最最难以解决的认知问题了。我了解到很多公司里面,CEO 和 CTO 之间也常常会发生这样的结果偏见。明明需求很复杂,技术挑战很多,技术团队拼尽全力上线了,结果老板可能还觉得你做得慢。理由可能是:别的团队做一个类似的,只花了两天时间。但是,非技术出身的老板很难理解:

  • 技术团队可能有很多历史的积累和债务
  • 团队可能同时并行着多个项目
  • 类似的产品需求并不是完全一样,差异的部分看起来很小,但是技术复杂度完全不一样
  • 别的团队可能有类似项目的积累

直觉什么时候有效

在这一部分,作者也认真讨论了一下直觉在什么时候是有用的。作者承认《眨眼之间》一书中提到的直觉的有效性,但是作者觉得获得这种专家的直觉是有条件的,条件是:

  1. 环境有规律,可预测。例如医生、护士、消防员、棋手的工作场景。
  2. 可通过长期训练来学习这些规律。

我在上一篇《iOS 面试之道》的文章中也提到,我觉得面试也符合上面的场景。环境固定,讨论内容偏固定,所以一个长期面试别的人面试官,可能就会形成判断人的一种直觉。

好的决策方法

在做决策的时候,作者推荐了一些实践方法,例如:努力养成采纳外部意见的习惯。因为内部意见通常充斥了乐观。

又比如,抑制乐观主义情绪的实践方法:事前验尸。我们假设这个项目未来失败了,然后总结这次失败的原因。通常从这个角度思考,我们就可以认真重视各种可能的风险。

事前验尸观点有两个主要优点:决策快要制定好时,许多团队成员会受到集体思考的影响,而事前验尸则扼制住了这种影响。另外,它还激发了那些见多识广的个人的想象力,并将他们的想法引导到最需要它们的方向。

我听 Annie 讲如何在腾讯做投资的经验,她提到过一个 Tips:当你觉得这个被投公司未来有可能因为什么失败的时候,通常这种担心都会发生。我就是一个活生生的事前验尸的决策角度。

选择与风险

前景理论

好了,终于讲到作者著名的展望理论(prospect theory,也被称作前景理论),在第四部分「选择与风险」中,作者介绍了传统的理论根本站不住脚,人们对于收益和风险的感受并不均等。

简单来说,所有人都是风险厌恶型的,丢 100 块钱带来的痛苦,比捡 100 块钱带来的快乐强。所以,就会有很多符合这种逻辑的行为产生。以下就是作者关于这个理论最经典的图了:

人们如果要克服这种行为,就只能靠系统 2 来帮助你拜托这种直觉影响。

禀赋效应

禀赋效应是指当个人一旦拥有某个物品,那么他对该物品价值的评价要比未拥有之前大大提高。

泰勒发现 R 教授非常不愿意卖掉自己收藏的葡萄酒,即使对方出价高达 100 美元(当时可是 1975 年)一瓶也不行。R 教授也会从拍卖会上买葡萄酒,但无论质量如何,他出价从不会高过 35 美元一瓶。若价格在 35 美元~100 美元,他就既不买也不卖。这个巨大的价格差在经济理论上看是相互矛盾的,人们希望这位教授能在这个价格区间为某瓶酒定一个值。低于这个值就应该买,高于这个值就应该卖。
这个可以接受的卖价和可以接受的买价应该相同,但事实上,最低卖价(100 美元)比最高买价(35 美元)高出很多,拥有这件物品似乎会提升它的价值。

前景理论也可以用来解释禀赋效应。因为除了商人做生意,普通人卖某些自己的东西的时候,会引起他对于损失的厌恶。

两个自我

两个自我指的是感受当下的经验自我以及记录并作出选择的记忆自我。在书的最后一部分,作者选择讨论人们的选择性记忆。作者发现,人们的记忆非常不可靠。

峰终定律,指我们对一件事物的记忆仅限于高峰和结尾,事件过程对记忆几乎没有影响。高峰之后,终点出现得越迅速,这件事留给我们的印象越深刻。

人们过于在乎结尾,以致于比起整个人生,我们更在意人生的结局。一个穷人辛苦一辈子,晚年终于可以享受几年福气,远远好过一个地主儿子逍遥地活了一辈子,晚年过得穷困潦倒。但是其实从快活的时间来看,地主儿子明显更多。

小结

作者首先在书中引入了两个虚拟人物,分别是运用直觉、进行快速思考的系统 1 和需付出努力、运行更慢的系统 2。系统 2 进行的是慢思考,能监督系统 1 的运作,并在其自身有限的能力下尽可能地占据控制地位。

然后介绍了两个物种,分别是活在理论世界的虚拟经济人以及活在现实世界的人类。

最后介绍了两个自我,指的是感受当下的经验自我以及记录并作出选择的记忆自我。

由于两个系统的差异,所以人类产生了各种奇怪的、不符合经济学规律的行为和认知。

本书列举了相当多的这方面的例子,如:小数定律、可得性偏见、峰终定律、前景理论等。

作者在书中也提供了相当多让系统 2 接管系统 1 的实践,例如:事前验尸。其实了解这些非理性行为本身,也会使得我们在遇到相关场景的时候,激活系统 2 帮助我们做决策。

如果说这本书有什么缺点的话,就是太长了一些,论述稍显啰嗦。这可能是因为作者是心理学家,比较严谨的原因。这是我读的第一本诺贝尔经济学奖获得者作品,推荐给大家。

]]>
0
<![CDATA[闲坐]]> http://www.udpwork.com/item/16997.html http://www.udpwork.com/item/16997.html#reviews Fri, 10 Aug 2018 20:18:39 +0800 qyjohn http://www.udpwork.com/item/16997.html 香炉

闲坐小窗燃乌碳,
慢夹莞香入泥炉。
静听石泉铁壶鸣,
轻执陶盏乱翻书。

]]>
香炉

闲坐小窗燃乌碳,
慢夹莞香入泥炉。
静听石泉铁壶鸣,
轻执陶盏乱翻书。

]]>
0
<![CDATA[每周分享第 17 期]]> http://www.udpwork.com/item/16996.html http://www.udpwork.com/item/16996.html#reviews Fri, 10 Aug 2018 07:55:55 +0800 阮一峰 http://www.udpwork.com/item/16996.html 这里记录过去一周,我看到的值得分享的东西,每周五发布。

(图片说明:2018年6月的气温与1951-1980年平均气温的对比,来自推特@SimonLeeWx

今天夏天,全球高温创纪录。日本韩国都是史上最高温,西班牙葡萄牙接近48度的欧洲高温纪录,北纬71度的一个挪威城市32度。要知道,北极圈是北纬66.5度,这就是说北极圈里面也是高温。上图是今年6月的气温与40年前的平均气温比较,可以看到都是偏高的,尤其是南北极远远偏高。

全球变暖已经是活生生的现实。科学家估计,目前的年平均气温比工业革命前已经升高了1度。《巴黎气候协议》的目标是,气温升高控制在2度,但是成功的希望据说只有5%。如果学过统计学,你就知道,5%的机会在统计学上可以视作不会发生。

千万不要觉得,2度不算什么,《纽约时报》描述了后果。

  • 升高2度:热带珊瑚礁灭绝,海平面上升几米,波斯湾不适合人类居住。
  • 升高3度:北极的森林和大多数沿海城市被淹没。
  • 升高4度:欧洲永久干旱, 中国、印度和孟加拉国大部分地区变成沙漠,美国科罗拉多河接近干涸,美国西南部将不适合居住。
  • 升高5度:人类文明终结。

联合国气候官员称,如果不采取任何行动,目前乐观的估计是全球会升高3度。

气温升高的主要原因是,人类大量消耗化石能源,温室气体(主要是二氧化碳)排放急剧增加。所谓温室气体,就是这一类气体有温室效应,可以让阳光进入温室,但是阻止热量散发出去。火星为什么不适合人类居住?一个原因就是它的表面没有温室气体,留不住热量,导致温度过低。地球现在的问题是,温室气体过多。

现在的计算是,如果人类排放10000亿吨二氧化碳,地球就会升高2度,目前人类已经排放了6237亿吨。有一个网站实时显示目前排放了多少亿吨。

根据计算,2036年3月7日,人类将达到1万亿吨排放量。更热的日子还在后面。

新闻

1、中国的二氧化碳排放

《纽约时报》报道,一个美国教授认为,按照中国现在的二氧化碳排放水平,人类无法达到《巴黎协定》规定的减排目标,即全球平均温度比工业化之前上升不超过2摄氏度,除非中国的排放量大幅下降。

中国是世界最大的二氧化碳排放国。2017年,中国排放了117亿吨的温室气体,占世界总量的四分之一,其中包括92亿吨的二氧化碳,超过美国和欧盟的总和。按照现在的减排速度,中国的二氧化碳排放量最晚将在2030年达到峰值,到那一年,中国五分之一的能源将来自非化石燃料来源。

2、美国的贫富分化

美国经济研究所发现,美国的贫富分化一直在扩大,已经达到了1928年以来的最高点。

现在最富有的1%家庭获得全部收入的22%,只比1928年的23.9%低一点。美国人的年收入至少需要42.2万美元,才能跻身前1%的高收入者。这只是全国平均数,一些州的门槛要高得多,比如康涅狄格州的1%门槛为70万美元。

这就是技术革命的一个社会后果,贫富分化不断扩大,中产阶级消失,财富日益集中在少数富豪手里。

3、开放式办公室

Ruby on Rails 的创始人 DHH 公开抨击,开放式办公室是一个极其糟糕的坏主意。

有人说,开放式办公室可以增加合作。DHH 说实际情况是,开放式办公导致面对面的互动直线下降,因为人们这时需要通过耳机来集中注意力,交流变成依靠即时消息或电子邮件。最糟糕的情况是,同一房间有不同部门的数十个人,销售、营销、客服、管理者、程序员、设计师都混在一起,他们一定会互相打扰。

开放式办公实际带来的不是合作,而是压力和冲突,但它仍然是技术公司的默认配置。我们强迫绝大多数不喜欢开放式办公的人接受这种配置,这为了什么?因为管理层喜欢这样的配置?因为它在照片中看起来不错?还是因为它会给访问办公室的陌生人留下深刻的印象?

4、皮质醇贴片

斯坦福大学的科学家发明了一种皮肤贴片,可以实时测量汗液里面的皮质醇含量。一般来说,我们觉得压力很大的时候,皮质醇分泌就会增加。

以前的测量方法都无法实时得到结果。现在我们可以实时知道人体的感受了,甚至可以找出人群里面最紧张的人,这种传感器为以后更有趣的发明奠定了基础。

5、微型机器人竞赛

美国国防部高级研究局(DARPA)发起了一次微型机器人竞赛。现在大多数机器人都是模仿人类的外形,但是昆虫大小的机器人也有巨大的用处。DARPA 要求,这次参赛的机器人重量小于1克,体积小于1立方厘米。DARPA 为所有参赛者提供3200万美元资助,比赛可能在明年3月举行。

6、最古老的面包

考苦学家在约旦的沙漠里面,发现了一个石头砌的炉子,里面居然还有古人烤剩下来的面包屑。这是现存最古老的面包。

上图是显微镜下的面包屑,可以看到面包经过了充分发酵。

年代鉴定以后,所有人都大吃一惊,这个面包炉子距今14000年。那时人类甚至没有开始农业耕作,因此这个面包不是用小麦粉做的,而是来自野生的谷物。

7、代码搜索

微软的 Bing 搜索引擎新增了代码搜索功能,你问一个编程问题,现在可以直接给出示例代码。

8、机器狗 Spotmini

波士顿动力公司在成立16年后,终于要发售第一款产品了:一个类似小狗的四足机器人,高91厘米,重25公斤。这家公司以前的产品,都是供给美国国防部,这是第一款商业产品,预计明年上市。

这个机器人的功能非常惊人,可以自动识别道路,避开障碍,上楼下楼,跌倒还能爬起,机械臂可以拿起放下各种东西,请看视频

9、博士就业危机

加拿大媒体报道,该国的博士研究生只有五分之一能够找到教职。也就是说,80%的博士只能去企业界或转行,事实上确实有很多博士找不到工作,这篇报道里面就有博士改行当插花师或建筑工。

我想,这样的危机在中国一定更严重。因为中国的博士生规模世界第一,但是国内高校的扩张期已经过去了,现在想进高校当老师其实挺难的。如果转行的话,对个人和社会都是一种浪费。如果你有志攻读博士,一定要慎重。

10、AMD 游戏主机

上海的 ChinaJoy 展会上,AMD 宣布与中山小霸王公司合作推出新的游戏主机,CPU 是锐龙,GPU 是Vega,搭配 8GB GDDR5显存,性能将超过索尼 PS4 及微软 Xbox One 游戏机。

这台游戏机搭配 128GB SSD + 1TB HDD 硬盘,支持正版Windows 10系统,售价4998元,并有中文独占游戏 Onrush。由于没有自己的操作系统,这个所谓的游戏主机其实是一台 Windows 10 电脑。

11、AI 取得 Dota2 的胜利

OpenAI Five 与人类高级玩家的 Dota2 第一场比赛结束,AI 以 2:1 获胜。值得一提的是,AI 输掉的第三局是人类故意为它分配了能力较低的角色,而不是让它自己选择角色,AI 自己预估第三局的胜率只有2.9%。8月下旬将进行 AI 与职业团队的比赛。

12、一句话新闻

  • 随着手机支付的崛起,国内的ATM 和 POS设备制造行业大幅衰退,而二维码扫描设备制造业大幅成长。
  • Dart 语言发布2.0版。该语言的前途完全取决于谷歌的 Flutter 框架(Dart 是 Flutter 唯一支持的语言),如果谷歌大力推广这个框架,Dart 才有可能成功。
  • Android 9.0发布,这个版本大量增加了 AI 支持,可以对每个用户提供更好的个性化服务。
  • Mozilla 浏览器计划取消 RSS 支持,原因是缺乏用户。

教程

1、如何使用 Node 优化图片?(英文)

本文教你使用 JS 的 imagemin 模块,压缩图片的大小。

2、DNS over HTTPS(英文)

DNS 查询都是基于 HTTP 协议的,即使是加密通信,网络服务商依然可以知道你想访问的网站。现在有多种解决方案,本文介绍如何在 Firefox 浏览器打开设置,使得 DNS 协议走 HTTPS 协议。

3、WebAssembly 的发展方向(英文)

WebAssembly 是浏览器可以执行的字节码,使得非 JS 编写的程序可以在浏览器运行。它现在的功能非常少,还处在 MVP(最小可用产品)状态。这篇文章介绍了一些很可能采纳的 WebAssembly 提案。

4、少子化和人口老龄化综述(英文)

全世界发达国家都有少子化和人口老龄化的趋势,这篇文章是我看过的最好的这方面的综述,有大量的数据和事实。除了非洲,其他大洲的人口都接近峰值了,将要开始下降,这意味着许多国家将不得不依靠移民,解决本国人力不足问题。

5、SVG 动画入门:以加载转子为例(英文)

本文手把手教你如何写一个最简单的 SVG 动画。

6、Hash 算法简介(英文)

Hash 算法的概念性介绍。

7、为什么飞机驾驶舱不使用触摸屏?(英文)

现在的飞机驾驶舱还是使用物理仪表盘,而不是触摸屏,这是为什么?主要的原因还是物理按钮会形成肌肉记忆,比操作触摸屏更快。

8、斐波那契数列的计算公式(英文)

如果不用递归,直接算出斐波那契数列的任意项,应该怎么计算?

9、如何通过 npm 窃取信用卡密码?(英文)

本文讲述了作者通过 npm 发布恶意代码的种种手段,非常值得一读。其中有一个技巧,就是package.js 与 package.min.js 的代码不同,恶意代码只放在后者。

工具

1、nouns

一个侦测用户眨眼的装置,让用户通过眨眼控制电脑,可以供霍金那样的用户使用。

2、模拟电路生成器

生成模拟电路的网站。

3、Zotero

管理各种论文和报告的免费桌面软件。

4、fnMatch

一个让对象进行选择性解构赋值的 JS 库。

5、jsinspect

软件项目中,同一段逻辑不应该有多个实现。jsinspect 就是用来查出重复代码的工具。

6、Malvid

一个构建 Web Components 的工具,并且能够自动生成文档。_ _

7、Glances

Glances 是一个用Python编写的跨平台系统监视工具。它自带 Web UI,可以远程监控。

8、Code with Mu

一个 Python 语言专用的代码编辑器。

9、diffconflicts

Git 的合并算法是三方合并(three-way),有人认为这种算法并不是最好的。这里是一个两方合并算法,有兴趣的人可以用它替换到 Git 的合并算法。

资源

1、机械键盘

这个网站收集各种各样的机械键盘。

2、Emulator 101

开源电子书,从零开始讲解如何写一个8080处理器的模拟器。

3、stackshare.io

收集各大网站使用的技术栈。

4、Meteor Wrongs

华盛顿大学维护的一个网站,收集各种假陨石的照片,并附上说明,讲解为什么某块石头不是陨石。

5、Byte 杂志

Byte 杂志是上个世纪很有影响的 IT 杂志,archive.org 提供免费下载。

文摘

1、幸存者偏见

二战时,英国决定要在轰炸机上加装防弹材料,减少被德国炮弹击中时的伤害。

他们按照平安返回的轰炸机被击中的位置,为其他轰炸机加装防弹材料。这种方法看上去正确,其实是错的,真正应该加载防弹材料的,恰恰是那些没有被击中的位置。因为这些轰炸机能返回,就说明它们被击中的位置不是很重要,那些被击中要害位置的轰炸机,都没有能够返回。

这就叫做幸存者偏见,人们过度重视那些幸存的个体,以为他们的特质就代表整个总体的特质。

举例来说,很多创业者总是向某些最成功的企业家学习,比如,比尔盖茨,理查德布兰森,史蒂夫乔布斯,马克扎克伯格,伊隆马斯克等等。殊不知他们可能只是特例,他们的经验不一定普遍适用。

上面这些企业家有一些共同特点。

  • 反传统,不走寻常的道路。
  • 承担巨大风险,有冒险家特质。
  • 极端主义者,他们不喜欢中间立场,有明确的爱和恨。

他们能够成功,并不表示拥有这些特点,你就能成功。很多同样拥有这些特点的人,可能都已经失败了。事实上,稳健经营更能帮助一家小公司生存下来。

2、第一条大西洋海底电缆

以下摘自奥地利作家茨威格的《人类群星闪耀时》一书。

1851年,欧洲大陆都已经连通了电报。但是,美洲一直被排除在世界电报网之外。

大西洋漫无边际,人们根本就不可能在海面上设立众多中间站,更加不可能用一根电线跨越两个大洋。人们不仅不知道海洋的深度,对它的地质结构也知之甚少,大洋底部的电缆能否承受住巨大的海水压力仍然无从得知。

即使从理论和技术上来说,铺设一条如此漫长的海底电缆行得通,但在当时还没有能负载铁铜电缆全部重量的巨轮,也没有一台发电机的功率能输送电流经过如此漫长的距离。就算轮船轻装上阵,也至少要耗费三个星期。并且在此期间,所有的电缆都必须妥善存放,不能露天放置。

英国政府提供了曾经的海战旗舰"阿伽门农"号,美国政府则"贡献"了当时吨位最大的二桅战舰"尼亚加拉"号。经过特殊的改造后,这两艘船都能容纳一半的海底电缆。

最后,同时也是最关键的问题,就是制造电缆。当时,制造一条连接两大洲的电缆需要非常精湛的技术:它既要有钢筋的坚硬而不易断裂的特性,又有非常大的柔韧性,也必须像丝线一样耐压耐磨而能随意弯曲,还必须实心而有一定的空间。总而言之,电缆必须结实、精密。对整个工程而言,电缆上任何一个微乎其微的磨损和坑洼都会破坏电流的传递。

要制造一条这样的电缆,整整需要整座橡胶林的橡胶汁。做一个形象的说明:到工程完工,电缆里使用的铜丝和铁丝长达367000海里,足足能将地球环绕13圈,甚至能将地球和月球连接起来。为此,工厂里的机器整整工作了一年。

下图是160年前第一代的大西洋海底电缆。

3、中美电影周的真相

以下摘自冯小刚的《我把青春献给你》。

中国电影周说穿了,就是由一两个美国穷人,打着热爱中国电影的旗号,从中国的制片厂免费拿到一些电影拷贝,在美国华人集中的城市转着圈的卖票放映,从中有利可图的个人行为。国内的电影制片厂也全无版权的概念,拷贝一撒手就是几个月,条件只不过是几张往返美国的机票。

"中国电影周"放映的电影院条件环境都很差,观众大部分是华人,也有少数闲着没事跟着起哄的白人,因为这些人有强烈的中国情结,看什么破片子都报以热烈的掌声,这些掌声与影片的质量无关,只能反映新老华侨的爱国热情。不明真像的导演误以为自己拍的影片多么伟大,回国后马上约记者采访,据此抱怨国内的发行公司和观众对他影片的冷落是不识货,吹嘘他的影片在美国放映引起轰动。其实也就是寄居美国的少数人自娱自乐的一个派对,主流媒体对此只字未提。

所谓的中美文化交流,说白了还是华人与华人的一次收费联谊会,跟美国大众八竿子打不着。

本周图片

1、2060年的世界人口大国

上图是2060年的世界人口预测。印度是人口最多的国家,17亿左右;其次是中国,13亿左右;后面是尼日利亚,美国,巴基斯坦,印尼,刚果,巴西,埃塞俄比亚,坦桑尼亚和墨西哥。

历史上,亚洲约占世界人口的70%,欧洲大约10%到20%,非洲5%到10%。2060年,非洲人口比重将激增,增加到世界人口的35%左右。

2、Java 的类

Java 语言以众多的类著称,但是你知道它一共有多少个 public Class 吗?

3、LED 街灯

随着 LED 产业的发展,街灯已经大量改成了节能的 LED 灯。传统的昏黄温暖的橙色灯光,变成了明亮的蓝色灯光。有人提出,蓝色的明亮灯光容易对人类造成影响,使得效率降低,失眠和焦虑增加。

本周金句

1、

每颗恒星都在不停燃烧,释放能量。如果宇宙是静止的,必然变得越来越热。幸亏宇宙在不停膨胀,把这个问题解决了。(比尔·布莱森《万物简史》)

2、

人一生最大的幸运,就是在年富力强时发现了自己的人生使命。(茨威格《人类群星闪耀时》)

3、

过去盖起的宫殿中,没有他的位置,他只好在宫殿的旁边,另起炉灶,搭起了一间偏房。问题是偏房越盖越多,越盖越大,越盖越高,渐渐成了一个院落,它就成了另一座宫殿。(刘震云《<我把青春献给你>序言》)

欢迎订阅

这个专栏每周五发布,同步更新在我的个人网站微信公众号语雀

微信搜索"阮一峰的网络日志 "或者扫描二维码,即可订阅。

image | left

(完)

文档信息

]]>
这里记录过去一周,我看到的值得分享的东西,每周五发布。

(图片说明:2018年6月的气温与1951-1980年平均气温的对比,来自推特@SimonLeeWx

今天夏天,全球高温创纪录。日本韩国都是史上最高温,西班牙葡萄牙接近48度的欧洲高温纪录,北纬71度的一个挪威城市32度。要知道,北极圈是北纬66.5度,这就是说北极圈里面也是高温。上图是今年6月的气温与40年前的平均气温比较,可以看到都是偏高的,尤其是南北极远远偏高。

全球变暖已经是活生生的现实。科学家估计,目前的年平均气温比工业革命前已经升高了1度。《巴黎气候协议》的目标是,气温升高控制在2度,但是成功的希望据说只有5%。如果学过统计学,你就知道,5%的机会在统计学上可以视作不会发生。

千万不要觉得,2度不算什么,《纽约时报》描述了后果。

  • 升高2度:热带珊瑚礁灭绝,海平面上升几米,波斯湾不适合人类居住。
  • 升高3度:北极的森林和大多数沿海城市被淹没。
  • 升高4度:欧洲永久干旱, 中国、印度和孟加拉国大部分地区变成沙漠,美国科罗拉多河接近干涸,美国西南部将不适合居住。
  • 升高5度:人类文明终结。

联合国气候官员称,如果不采取任何行动,目前乐观的估计是全球会升高3度。

气温升高的主要原因是,人类大量消耗化石能源,温室气体(主要是二氧化碳)排放急剧增加。所谓温室气体,就是这一类气体有温室效应,可以让阳光进入温室,但是阻止热量散发出去。火星为什么不适合人类居住?一个原因就是它的表面没有温室气体,留不住热量,导致温度过低。地球现在的问题是,温室气体过多。

现在的计算是,如果人类排放10000亿吨二氧化碳,地球就会升高2度,目前人类已经排放了6237亿吨。有一个网站实时显示目前排放了多少亿吨。

根据计算,2036年3月7日,人类将达到1万亿吨排放量。更热的日子还在后面。

新闻

1、中国的二氧化碳排放

《纽约时报》报道,一个美国教授认为,按照中国现在的二氧化碳排放水平,人类无法达到《巴黎协定》规定的减排目标,即全球平均温度比工业化之前上升不超过2摄氏度,除非中国的排放量大幅下降。

中国是世界最大的二氧化碳排放国。2017年,中国排放了117亿吨的温室气体,占世界总量的四分之一,其中包括92亿吨的二氧化碳,超过美国和欧盟的总和。按照现在的减排速度,中国的二氧化碳排放量最晚将在2030年达到峰值,到那一年,中国五分之一的能源将来自非化石燃料来源。

2、美国的贫富分化

美国经济研究所发现,美国的贫富分化一直在扩大,已经达到了1928年以来的最高点。

现在最富有的1%家庭获得全部收入的22%,只比1928年的23.9%低一点。美国人的年收入至少需要42.2万美元,才能跻身前1%的高收入者。这只是全国平均数,一些州的门槛要高得多,比如康涅狄格州的1%门槛为70万美元。

这就是技术革命的一个社会后果,贫富分化不断扩大,中产阶级消失,财富日益集中在少数富豪手里。

3、开放式办公室

Ruby on Rails 的创始人 DHH 公开抨击,开放式办公室是一个极其糟糕的坏主意。

有人说,开放式办公室可以增加合作。DHH 说实际情况是,开放式办公导致面对面的互动直线下降,因为人们这时需要通过耳机来集中注意力,交流变成依靠即时消息或电子邮件。最糟糕的情况是,同一房间有不同部门的数十个人,销售、营销、客服、管理者、程序员、设计师都混在一起,他们一定会互相打扰。

开放式办公实际带来的不是合作,而是压力和冲突,但它仍然是技术公司的默认配置。我们强迫绝大多数不喜欢开放式办公的人接受这种配置,这为了什么?因为管理层喜欢这样的配置?因为它在照片中看起来不错?还是因为它会给访问办公室的陌生人留下深刻的印象?

4、皮质醇贴片

斯坦福大学的科学家发明了一种皮肤贴片,可以实时测量汗液里面的皮质醇含量。一般来说,我们觉得压力很大的时候,皮质醇分泌就会增加。

以前的测量方法都无法实时得到结果。现在我们可以实时知道人体的感受了,甚至可以找出人群里面最紧张的人,这种传感器为以后更有趣的发明奠定了基础。

5、微型机器人竞赛

美国国防部高级研究局(DARPA)发起了一次微型机器人竞赛。现在大多数机器人都是模仿人类的外形,但是昆虫大小的机器人也有巨大的用处。DARPA 要求,这次参赛的机器人重量小于1克,体积小于1立方厘米。DARPA 为所有参赛者提供3200万美元资助,比赛可能在明年3月举行。

6、最古老的面包

考苦学家在约旦的沙漠里面,发现了一个石头砌的炉子,里面居然还有古人烤剩下来的面包屑。这是现存最古老的面包。

上图是显微镜下的面包屑,可以看到面包经过了充分发酵。

年代鉴定以后,所有人都大吃一惊,这个面包炉子距今14000年。那时人类甚至没有开始农业耕作,因此这个面包不是用小麦粉做的,而是来自野生的谷物。

7、代码搜索

微软的 Bing 搜索引擎新增了代码搜索功能,你问一个编程问题,现在可以直接给出示例代码。

8、机器狗 Spotmini

波士顿动力公司在成立16年后,终于要发售第一款产品了:一个类似小狗的四足机器人,高91厘米,重25公斤。这家公司以前的产品,都是供给美国国防部,这是第一款商业产品,预计明年上市。

这个机器人的功能非常惊人,可以自动识别道路,避开障碍,上楼下楼,跌倒还能爬起,机械臂可以拿起放下各种东西,请看视频

9、博士就业危机

加拿大媒体报道,该国的博士研究生只有五分之一能够找到教职。也就是说,80%的博士只能去企业界或转行,事实上确实有很多博士找不到工作,这篇报道里面就有博士改行当插花师或建筑工。

我想,这样的危机在中国一定更严重。因为中国的博士生规模世界第一,但是国内高校的扩张期已经过去了,现在想进高校当老师其实挺难的。如果转行的话,对个人和社会都是一种浪费。如果你有志攻读博士,一定要慎重。

10、AMD 游戏主机

上海的 ChinaJoy 展会上,AMD 宣布与中山小霸王公司合作推出新的游戏主机,CPU 是锐龙,GPU 是Vega,搭配 8GB GDDR5显存,性能将超过索尼 PS4 及微软 Xbox One 游戏机。

这台游戏机搭配 128GB SSD + 1TB HDD 硬盘,支持正版Windows 10系统,售价4998元,并有中文独占游戏 Onrush。由于没有自己的操作系统,这个所谓的游戏主机其实是一台 Windows 10 电脑。

11、AI 取得 Dota2 的胜利

OpenAI Five 与人类高级玩家的 Dota2 第一场比赛结束,AI 以 2:1 获胜。值得一提的是,AI 输掉的第三局是人类故意为它分配了能力较低的角色,而不是让它自己选择角色,AI 自己预估第三局的胜率只有2.9%。8月下旬将进行 AI 与职业团队的比赛。

12、一句话新闻

  • 随着手机支付的崛起,国内的ATM 和 POS设备制造行业大幅衰退,而二维码扫描设备制造业大幅成长。
  • Dart 语言发布2.0版。该语言的前途完全取决于谷歌的 Flutter 框架(Dart 是 Flutter 唯一支持的语言),如果谷歌大力推广这个框架,Dart 才有可能成功。
  • Android 9.0发布,这个版本大量增加了 AI 支持,可以对每个用户提供更好的个性化服务。
  • Mozilla 浏览器计划取消 RSS 支持,原因是缺乏用户。

教程

1、如何使用 Node 优化图片?(英文)

本文教你使用 JS 的 imagemin 模块,压缩图片的大小。

2、DNS over HTTPS(英文)

DNS 查询都是基于 HTTP 协议的,即使是加密通信,网络服务商依然可以知道你想访问的网站。现在有多种解决方案,本文介绍如何在 Firefox 浏览器打开设置,使得 DNS 协议走 HTTPS 协议。

3、WebAssembly 的发展方向(英文)

WebAssembly 是浏览器可以执行的字节码,使得非 JS 编写的程序可以在浏览器运行。它现在的功能非常少,还处在 MVP(最小可用产品)状态。这篇文章介绍了一些很可能采纳的 WebAssembly 提案。

4、少子化和人口老龄化综述(英文)

全世界发达国家都有少子化和人口老龄化的趋势,这篇文章是我看过的最好的这方面的综述,有大量的数据和事实。除了非洲,其他大洲的人口都接近峰值了,将要开始下降,这意味着许多国家将不得不依靠移民,解决本国人力不足问题。

5、SVG 动画入门:以加载转子为例(英文)

本文手把手教你如何写一个最简单的 SVG 动画。

6、Hash 算法简介(英文)

Hash 算法的概念性介绍。

7、为什么飞机驾驶舱不使用触摸屏?(英文)

现在的飞机驾驶舱还是使用物理仪表盘,而不是触摸屏,这是为什么?主要的原因还是物理按钮会形成肌肉记忆,比操作触摸屏更快。

8、斐波那契数列的计算公式(英文)

如果不用递归,直接算出斐波那契数列的任意项,应该怎么计算?

9、如何通过 npm 窃取信用卡密码?(英文)

本文讲述了作者通过 npm 发布恶意代码的种种手段,非常值得一读。其中有一个技巧,就是package.js 与 package.min.js 的代码不同,恶意代码只放在后者。

工具

1、nouns

一个侦测用户眨眼的装置,让用户通过眨眼控制电脑,可以供霍金那样的用户使用。

2、模拟电路生成器

生成模拟电路的网站。

3、Zotero

管理各种论文和报告的免费桌面软件。

4、fnMatch

一个让对象进行选择性解构赋值的 JS 库。

5、jsinspect

软件项目中,同一段逻辑不应该有多个实现。jsinspect 就是用来查出重复代码的工具。

6、Malvid

一个构建 Web Components 的工具,并且能够自动生成文档。_ _

7、Glances

Glances 是一个用Python编写的跨平台系统监视工具。它自带 Web UI,可以远程监控。

8、Code with Mu

一个 Python 语言专用的代码编辑器。

9、diffconflicts

Git 的合并算法是三方合并(three-way),有人认为这种算法并不是最好的。这里是一个两方合并算法,有兴趣的人可以用它替换到 Git 的合并算法。

资源

1、机械键盘

这个网站收集各种各样的机械键盘。

2、Emulator 101

开源电子书,从零开始讲解如何写一个8080处理器的模拟器。

3、stackshare.io

收集各大网站使用的技术栈。

4、Meteor Wrongs

华盛顿大学维护的一个网站,收集各种假陨石的照片,并附上说明,讲解为什么某块石头不是陨石。

5、Byte 杂志

Byte 杂志是上个世纪很有影响的 IT 杂志,archive.org 提供免费下载。

文摘

1、幸存者偏见

二战时,英国决定要在轰炸机上加装防弹材料,减少被德国炮弹击中时的伤害。

他们按照平安返回的轰炸机被击中的位置,为其他轰炸机加装防弹材料。这种方法看上去正确,其实是错的,真正应该加载防弹材料的,恰恰是那些没有被击中的位置。因为这些轰炸机能返回,就说明它们被击中的位置不是很重要,那些被击中要害位置的轰炸机,都没有能够返回。

这就叫做幸存者偏见,人们过度重视那些幸存的个体,以为他们的特质就代表整个总体的特质。

举例来说,很多创业者总是向某些最成功的企业家学习,比如,比尔盖茨,理查德布兰森,史蒂夫乔布斯,马克扎克伯格,伊隆马斯克等等。殊不知他们可能只是特例,他们的经验不一定普遍适用。

上面这些企业家有一些共同特点。

  • 反传统,不走寻常的道路。
  • 承担巨大风险,有冒险家特质。
  • 极端主义者,他们不喜欢中间立场,有明确的爱和恨。

他们能够成功,并不表示拥有这些特点,你就能成功。很多同样拥有这些特点的人,可能都已经失败了。事实上,稳健经营更能帮助一家小公司生存下来。

2、第一条大西洋海底电缆

以下摘自奥地利作家茨威格的《人类群星闪耀时》一书。

1851年,欧洲大陆都已经连通了电报。但是,美洲一直被排除在世界电报网之外。

大西洋漫无边际,人们根本就不可能在海面上设立众多中间站,更加不可能用一根电线跨越两个大洋。人们不仅不知道海洋的深度,对它的地质结构也知之甚少,大洋底部的电缆能否承受住巨大的海水压力仍然无从得知。

即使从理论和技术上来说,铺设一条如此漫长的海底电缆行得通,但在当时还没有能负载铁铜电缆全部重量的巨轮,也没有一台发电机的功率能输送电流经过如此漫长的距离。就算轮船轻装上阵,也至少要耗费三个星期。并且在此期间,所有的电缆都必须妥善存放,不能露天放置。

英国政府提供了曾经的海战旗舰"阿伽门农"号,美国政府则"贡献"了当时吨位最大的二桅战舰"尼亚加拉"号。经过特殊的改造后,这两艘船都能容纳一半的海底电缆。

最后,同时也是最关键的问题,就是制造电缆。当时,制造一条连接两大洲的电缆需要非常精湛的技术:它既要有钢筋的坚硬而不易断裂的特性,又有非常大的柔韧性,也必须像丝线一样耐压耐磨而能随意弯曲,还必须实心而有一定的空间。总而言之,电缆必须结实、精密。对整个工程而言,电缆上任何一个微乎其微的磨损和坑洼都会破坏电流的传递。

要制造一条这样的电缆,整整需要整座橡胶林的橡胶汁。做一个形象的说明:到工程完工,电缆里使用的铜丝和铁丝长达367000海里,足足能将地球环绕13圈,甚至能将地球和月球连接起来。为此,工厂里的机器整整工作了一年。

下图是160年前第一代的大西洋海底电缆。

3、中美电影周的真相

以下摘自冯小刚的《我把青春献给你》。

中国电影周说穿了,就是由一两个美国穷人,打着热爱中国电影的旗号,从中国的制片厂免费拿到一些电影拷贝,在美国华人集中的城市转着圈的卖票放映,从中有利可图的个人行为。国内的电影制片厂也全无版权的概念,拷贝一撒手就是几个月,条件只不过是几张往返美国的机票。

"中国电影周"放映的电影院条件环境都很差,观众大部分是华人,也有少数闲着没事跟着起哄的白人,因为这些人有强烈的中国情结,看什么破片子都报以热烈的掌声,这些掌声与影片的质量无关,只能反映新老华侨的爱国热情。不明真像的导演误以为自己拍的影片多么伟大,回国后马上约记者采访,据此抱怨国内的发行公司和观众对他影片的冷落是不识货,吹嘘他的影片在美国放映引起轰动。其实也就是寄居美国的少数人自娱自乐的一个派对,主流媒体对此只字未提。

所谓的中美文化交流,说白了还是华人与华人的一次收费联谊会,跟美国大众八竿子打不着。

本周图片

1、2060年的世界人口大国

上图是2060年的世界人口预测。印度是人口最多的国家,17亿左右;其次是中国,13亿左右;后面是尼日利亚,美国,巴基斯坦,印尼,刚果,巴西,埃塞俄比亚,坦桑尼亚和墨西哥。

历史上,亚洲约占世界人口的70%,欧洲大约10%到20%,非洲5%到10%。2060年,非洲人口比重将激增,增加到世界人口的35%左右。

2、Java 的类

Java 语言以众多的类著称,但是你知道它一共有多少个 public Class 吗?

3、LED 街灯

随着 LED 产业的发展,街灯已经大量改成了节能的 LED 灯。传统的昏黄温暖的橙色灯光,变成了明亮的蓝色灯光。有人提出,蓝色的明亮灯光容易对人类造成影响,使得效率降低,失眠和焦虑增加。

本周金句

1、

每颗恒星都在不停燃烧,释放能量。如果宇宙是静止的,必然变得越来越热。幸亏宇宙在不停膨胀,把这个问题解决了。(比尔·布莱森《万物简史》)

2、

人一生最大的幸运,就是在年富力强时发现了自己的人生使命。(茨威格《人类群星闪耀时》)

3、

过去盖起的宫殿中,没有他的位置,他只好在宫殿的旁边,另起炉灶,搭起了一间偏房。问题是偏房越盖越多,越盖越大,越盖越高,渐渐成了一个院落,它就成了另一座宫殿。(刘震云《<我把青春献给你>序言》)

欢迎订阅

这个专栏每周五发布,同步更新在我的个人网站微信公众号语雀

微信搜索"阮一峰的网络日志 "或者扫描二维码,即可订阅。

image | left

(完)

文档信息

]]>
0
<![CDATA[午夜书社]]> http://www.udpwork.com/item/16995.html http://www.udpwork.com/item/16995.html#reviews Wed, 08 Aug 2018 08:40:58 +0800 qyjohn http://www.udpwork.com/item/16995.html 午夜的书社
静谧而静寂
对面的女孩
穿着一身飘逸的裙子
温柔又美丽

她戴着耳机
一脸的惬意
不知是啥歌
她听得是如此的入迷
也许是啥戏

蜘蛛在结网
壁虎在捕食
斑驳的桌面
不知哪个该死的小子
刻了许多字

年轻的诗人
来回去找书
换了七八本
却读不进哪怕一个字

他一定是有什么心事

她把脑袋晃
她把头发理
她素手扶膝
她的娇姿懒懒往后依
她是一个谜

他鼓起勇气
写了几个字
我是个诗人
发表过许多许多文字
美丽的姑娘
可否请你留一个名字

姑娘抬起头
姑娘侧眼看
姑娘站起身
她说对面有家咖啡店
她说外面夜景好美丽
她说Do you wanna come with me

紫檀在开花
木棉在抽芽
凤凰花瓣沙沙下
夜空中闪电划过天际
他说你去吧
我还要再写一些文字

午夜的书社
静谧而静寂
对面的女孩
不知到底叫什么名字
对面的女孩
只记得她温柔又美丽

]]>
午夜的书社
静谧而静寂
对面的女孩
穿着一身飘逸的裙子
温柔又美丽

她戴着耳机
一脸的惬意
不知是啥歌
她听得是如此的入迷
也许是啥戏

蜘蛛在结网
壁虎在捕食
斑驳的桌面
不知哪个该死的小子
刻了许多字

年轻的诗人
来回去找书
换了七八本
却读不进哪怕一个字

他一定是有什么心事

她把脑袋晃
她把头发理
她素手扶膝
她的娇姿懒懒往后依
她是一个谜

他鼓起勇气
写了几个字
我是个诗人
发表过许多许多文字
美丽的姑娘
可否请你留一个名字

姑娘抬起头
姑娘侧眼看
姑娘站起身
她说对面有家咖啡店
她说外面夜景好美丽
她说Do you wanna come with me

紫檀在开花
木棉在抽芽
凤凰花瓣沙沙下
夜空中闪电划过天际
他说你去吧
我还要再写一些文字

午夜的书社
静谧而静寂
对面的女孩
不知到底叫什么名字
对面的女孩
只记得她温柔又美丽

]]>
0
<![CDATA[如何快速判断一个人水平高低 - 旁观者]]> http://www.udpwork.com/item/16993.html http://www.udpwork.com/item/16993.html#reviews Mon, 06 Aug 2018 21:07:00 +0800 旁观者 http://www.udpwork.com/item/16993.html 【摘要】先让他回答两个问题: 如何看待一个公司的技术体系,你怎么判断一个公司技术牛不牛? 你如何判断一个人(领导,同事,同龄人)牛不牛?阅读全文

]]>
【摘要】先让他回答两个问题: 如何看待一个公司的技术体系,你怎么判断一个公司技术牛不牛? 你如何判断一个人(领导,同事,同龄人)牛不牛?阅读全文

]]>
0
<![CDATA[SVG 图像入门教程]]> http://www.udpwork.com/item/16992.html http://www.udpwork.com/item/16992.html#reviews Mon, 06 Aug 2018 12:59:18 +0800 阮一峰 http://www.udpwork.com/item/16992.html 一、概述

SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics)。其他图像格式都是基于像素处理的,SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。

SVG 文件可以直接插入网页,成为 DOM 的一部分,然后用 JavaScript 和 CSS 进行操作。

<!DOCTYPE html>
<html>
<head></head>
<body>
<svg
  id="mysvg"
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 800 600"
  preserveAspectRatio="xMidYMid meet"
>
  <circle id="mycircle" cx="400" cy="300" r="50" />
<svg>
</body>
</html>

上面是 SVG 代码直接插入网页的例子。

SVG 代码也可以写在一个独立文件中,然后用<img>、<object>、<embed>、<iframe>等标签插入网页。

<img src="circle.svg">
<object id="object" data="circle.svg" type="image/svg+xml"></object>
<embed id="embed" src="icon.svg" type="image/svg+xml">
<iframe id="iframe" src="icon.svg"></iframe>

CSS 也可以使用 SVG 文件。

.logo {
  background: url(icon.svg);
}

SVG 文件还可以转为 BASE64 编码,然后作为 Data URI 写入网页。

<img src="data:image/svg+xml;base64,[data]">

二、语法

2.1<svg>标签

SVG 代码都放在顶层标签<svg>之中。下面是一个例子。

<svg width="100%" height="100%">
  <circle id="mycircle" cx="50" cy="50" r="50" />
</svg>

<svg>的width属性和height属性,指定了 SVG 图像在 HTML 元素中所占据的宽度和高度。除了相对单位,也可以采用绝对单位(单位:像素)。如果不指定这两个属性,SVG 图像默认大小是300像素(宽) x 150像素(高)。

如果只想展示 SVG 图像的一部分,就要指定viewBox属性。

<svg width="100" height="100" viewBox="50 50 50 50">
  <circle id="mycircle" cx="50" cy="50" r="50" />
</svg>

<viewBox>属性的值有四个数字,分别是左上角的横坐标和纵坐标、视口的宽度和高度。上面代码中,SVG 图像是100像素宽 x 100像素高,viewBox属性指定视口从(50, 50)这个点开始。所以,实际看到的是右下角的四分之一圆。

注意,视口必须适配所在的空间。上面代码中,视口的大小是 50 x 50,由于 SVG 图像的大小是 100 x 100,所以视口会放大去适配 SVG 图像的大小,即放大了四倍。

如果不指定width属性和height属性,只指定viewBox属性,则相当于只给定 SVG 图像的长宽比。这时,SVG 图像的默认大小将等于所在的 HTML 元素的大小。

2.2<circle>标签

<circle>标签代表圆形。

<svg width="300" height="180">
  <circle cx="30"  cy="50" r="25" />
  <circle cx="90"  cy="50" r="25" class="red" />
  <circle cx="150" cy="50" r="25" class="fancy" />
</svg>

上面的代码定义了三个圆。<circle>标签的cx、cy、r属性分别为横坐标、纵坐标和半径,单位为像素。坐标都是相对于<svg>画布的左上角原点。

class属性用来指定对应的 CSS 类。

.red {
  fill: red;
}

.fancy {
  fill: none;
  stroke: black;
  stroke-width: 3pt;
}

SVG 的 CSS 属性与网页元素有所不同。

  • fill:填充色
  • stroke:描边色
  • stroke-width:边框宽度

2.3<line>标签

<line>标签用来绘制直线。

<svg width="300" height="180">
  <line x1="0" y1="0" x2="200" y2="0" style="stroke:rgb(0,0,0);stroke-width:5" />
</svg>

上面代码中,<line>标签的x1属性和y1属性,表示线段起点的横坐标和纵坐标;x2属性和y2属性,表示线段终点的横坐标和纵坐标;style属性表示线段的样式。

2.4<polyline>标签

<polyline>标签用于绘制一根折线。

<svg width="300" height="180">
  <polyline points="3,3 30,28 3,53" fill="none" stroke="black" />
</svg>

<polyline>的points属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。

2.5<rect>标签

<rect>标签用于绘制矩形。

<svg width="300" height="180">
  <rect x="0" y="0" height="100" width="200" style="stroke: #70d5dd; fill: #dd524b" />
</svg>

<rect>的x属性和y属性,指定了矩形左上角端点的横坐标和纵坐标;width属性和height属性指定了矩形的宽度和高度(单位像素)。

2.6<ellipse>标签

<ellipse>标签用于绘制椭圆。

<svg width="300" height="180">
  <ellipse cx="60" cy="60" ry="40" rx="20" stroke="black" stroke-width="5" fill="silver"/>
</svg>

<ellipse>的cx属性和cy属性,指定了椭圆中心的横坐标和纵坐标(单位像素);rx属性和ry属性,指定了椭圆横向轴和纵向轴的半径(单位像素)。

2.7<polygon>标签

<polygon>标签用于绘制多边形。

<svg width="300" height="180">
  <polygon fill="green" stroke="orange" stroke-width="1" points="0,0 100,0 100,100 0,100 0,0"/>
</svg>

<polygon>的points属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。

2.8<path>标签

<path>标签用于制路径。

<svg width="300" height="180">
<path d="
  M 18,3
  L 46,3
  L 46,40
  L 61,40
  L 32,68
  L 3,40
  L 18,40
  Z
"></path>
</svg>

<path>的d属性表示绘制顺序,它的值是一个长字符串,每个字母表示一个绘制动作,后面跟着坐标。

  • M:移动到(moveto)
  • L:画直线到(lineto)
  • Z:闭合路径

2.9<text>标签

<text>标签用于绘制文本。

<svg width="300" height="180">
  <text x="50" y="25">Hello World</text>
</svg>

<text>的x属性和y属性,表示文本区块基线(baseline)起点的横坐标和纵坐标。文字的样式可以用class或style属性指定。

2.10<use>标签

<use>标签用于复制一个形状。

<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
  <circle id="myCircle" cx="5" cy="5" r="4"/>

  <use href="#myCircle" x="10" y="0" fill="blue" />
  <use href="#myCircle" x="20" y="0" fill="white" stroke="blue" />
</svg>

<use>的href属性指定所要复制的节点,x属性和y属性是<use>左上角的坐标。另外,还可以指定width和height坐标。

2.11<g>标签

<g>标签用于将多个形状组成一个组(group),方便复用。

<svg width="300" height="100">
  <g id="myCircle">
    <text x="25" y="20">圆形</text>
    <circle cx="50" cy="50" r="20"/>
  </g>

  <use href="#myCircle" x="100" y="0" fill="blue" />
  <use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>

2.12<defs>标签

<defs>标签用于自定义形状,它内部的代码不会显示,仅供引用。

<svg width="300" height="100">
  <defs>
    <g id="myCircle">
      <text x="25" y="20">圆形</text>
      <circle cx="50" cy="50" r="20"/>
    </g>
  </defs>

  <use href="#myCircle" x="0" y="0" />
  <use href="#myCircle" x="100" y="0" fill="blue" />
  <use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>

2.13<pattern>标签

<pattern>标签用于自定义一个形状,该形状可以被引用来平铺一个区域。

<svg width="500" height="500">
  <defs>
    <pattern id="dots" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
      <circle fill="#bee9e8" cx="50" cy="50" r="35" />
    </pattern>
  </defs>
  <rect x="0" y="0" width="100%" height="100%" fill="url(#dots)" />
</svg>

上面代码中,<pattern>标签将一个圆形定义为dots模式。patternUnits="userSpaceOnUse"表示<pattern>的宽度和长度是实际的像素值。然后,指定这个模式去填充下面的矩形。

2.14<image>标签

<image>标签用于插入图片文件。

<svg viewBox="0 0 100 100" width="100" height="100">
  <image xlink:href="path/to/image.jpg"
    width="50%" height="50%"/>
</svg>

上面代码中,<image>的xlink:href属性表示图像的来源。

2.15<animate>标签

<animate>标签用于产生动画效果。

<svg width="500px" height="500px">
  <rect x="0" y="0" width="100" height="100" fill="#feac5e">
    <animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
  </rect>
</svg>

上面代码中,矩形会不断移动,产生动画效果。

<animate>的属性含义如下。

  • attributeName:发生动画效果的属性名。
  • from:单次动画的初始值。
  • to:单次动画的结束值。
  • dur:单次动画的持续时间。
  • repeatCount:动画的循环模式。

可以在多个属性上面定义动画。

<animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
<animate attributeName="width" to="500" dur="2s" repeatCount="indefinite" />

2.16<animateTransform>标签

<animate>标签对 CSS 的transform属性不起作用,如果需要变形,就要使用<animateTransform>标签。

<svg width="500px" height="500px">
  <rect x="250" y="250" width="50" height="50" fill="#4bc0c8">
    <animateTransform attributeName="transform" type="rotate" begin="0s" dur="10s" from="0 200 200" to="360 400 400" repeatCount="indefinite" />
  </rect>
</svg>

上面代码中,<animateTransform>的效果为旋转(rotate),这时from和to属性值有三个数字,第一个数字是角度值,第二个值和第三个值是旋转中心的坐标。from="0 200 200"表示开始时,角度为0,围绕(200, 200)开始旋转;to="360 400 400"表示结束时,角度为360,围绕(400, 400)旋转。

三、JavaScript 操作

3.1 DOM 操作

如果 SVG 代码直接写在 HTML 网页之中,它就成为网页 DOM 的一部分,可以直接用 DOM 操作。

<svg
  id="mysvg"
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 800 600"
  preserveAspectRatio="xMidYMid meet"
>
  <circle id="mycircle" cx="400" cy="300" r="50" />
<svg>

上面代码插入网页之后,就可以用 CSS 定制样式。

circle {
  stroke-width: 5;
  stroke: #f00;
  fill: #ff0;
}

circle:hover {
  stroke: #090;
  fill: #fff;
}

然后,可以用 JavaScript 代码操作 SVG。

var mycircle = document.getElementById('mycircle');

mycircle.addEventListener('click', function(e) {
  console.log('circle clicked - enlarging');
  mycircle.setAttribute('r', 60);
}, false);

上面代码指定,如果点击图形,就改写circle元素的r属性。

3.2 获取 SVG DOM

使用<object>、<iframe>、<embed>标签插入 SVG 文件,可以获取 SVG DOM。

var svgObject = document.getElementById('object').contentDocument;
var svgIframe = document.getElementById('iframe').contentDocument;
var svgEmbed = document.getElementById('embed').getSVGDocument();

注意,如果使用<img>标签插入 SVG 文件,就无法获取 SVG DOM。

3.3 读取 SVG 源码

由于 SVG 文件就是一段 XML 文本,因此可以通过读取 XML 代码的方式,读取 SVG 源码。

<div id="svg-container">
  <svg
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xml:space="preserve" width="500" height="440"
  >
    <!-- svg code -->
  </svg>
</div>

使用XMLSerializer实例的serializeToString()方法,获取 SVG 元素的代码。

var svgString = new XMLSerializer()
  .serializeToString(document.querySelector('svg'));

3.4 SVG 图像转为 Canvas 图像

首先,需要新建一个Image对象,将 SVG 图像指定到该Image对象的src属性。

var img = new Image();
var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});

var DOMURL = self.URL || self.webkitURL || self;
var url = DOMURL.createObjectURL(svg);

img.src = url;

然后,当图像加载完成后,再将它绘制到<canvas>元素。

img.onload = function () {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
};

四、实例:折线图

下面将一张数据表格画成折线图。

Date |Amount
-----|------
2014-01-01 | $10
2014-02-01 | $20
2014-03-01 | $40
2014-04-01 | $80

上面的图形,可以画成一个坐标系,Date作为横轴,Amount作为纵轴,四行数据画成一个数据点。

<svg width="350" height="160">
  <g class="layer" transform="translate(60,10)">
    <circle r="5" cx="0"   cy="105" />
    <circle r="5" cx="90"  cy="90"  />
    <circle r="5" cx="180" cy="60"  />
    <circle r="5" cx="270" cy="0"   />

    <g class="y axis">
      <line x1="0" y1="0" x2="0" y2="120" />
      <text x="-40" y="105" dy="5">$10</text>
      <text x="-40" y="0"   dy="5">$80</text>
    </g>
    <g class="x axis" transform="translate(0, 120)">
      <line x1="0" y1="0" x2="270" y2="0" />
      <text x="-30"   y="20">January 2014</text>
      <text x="240" y="20">April</text>
    </g>
  </g>
</svg>

五、参考链接

(完)

文档信息

]]>
一、概述

SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics)。其他图像格式都是基于像素处理的,SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。

SVG 文件可以直接插入网页,成为 DOM 的一部分,然后用 JavaScript 和 CSS 进行操作。

<!DOCTYPE html>
<html>
<head></head>
<body>
<svg
  id="mysvg"
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 800 600"
  preserveAspectRatio="xMidYMid meet"
>
  <circle id="mycircle" cx="400" cy="300" r="50" />
<svg>
</body>
</html>

上面是 SVG 代码直接插入网页的例子。

SVG 代码也可以写在一个独立文件中,然后用<img>、<object>、<embed>、<iframe>等标签插入网页。

<img src="circle.svg">
<object id="object" data="circle.svg" type="image/svg+xml"></object>
<embed id="embed" src="icon.svg" type="image/svg+xml">
<iframe id="iframe" src="icon.svg"></iframe>

CSS 也可以使用 SVG 文件。

.logo {
  background: url(icon.svg);
}

SVG 文件还可以转为 BASE64 编码,然后作为 Data URI 写入网页。

<img src="data:image/svg+xml;base64,[data]">

二、语法

2.1<svg>标签

SVG 代码都放在顶层标签<svg>之中。下面是一个例子。

<svg width="100%" height="100%">
  <circle id="mycircle" cx="50" cy="50" r="50" />
</svg>

<svg>的width属性和height属性,指定了 SVG 图像在 HTML 元素中所占据的宽度和高度。除了相对单位,也可以采用绝对单位(单位:像素)。如果不指定这两个属性,SVG 图像默认大小是300像素(宽) x 150像素(高)。

如果只想展示 SVG 图像的一部分,就要指定viewBox属性。

<svg width="100" height="100" viewBox="50 50 50 50">
  <circle id="mycircle" cx="50" cy="50" r="50" />
</svg>

<viewBox>属性的值有四个数字,分别是左上角的横坐标和纵坐标、视口的宽度和高度。上面代码中,SVG 图像是100像素宽 x 100像素高,viewBox属性指定视口从(50, 50)这个点开始。所以,实际看到的是右下角的四分之一圆。

注意,视口必须适配所在的空间。上面代码中,视口的大小是 50 x 50,由于 SVG 图像的大小是 100 x 100,所以视口会放大去适配 SVG 图像的大小,即放大了四倍。

如果不指定width属性和height属性,只指定viewBox属性,则相当于只给定 SVG 图像的长宽比。这时,SVG 图像的默认大小将等于所在的 HTML 元素的大小。

2.2<circle>标签

<circle>标签代表圆形。

<svg width="300" height="180">
  <circle cx="30"  cy="50" r="25" />
  <circle cx="90"  cy="50" r="25" class="red" />
  <circle cx="150" cy="50" r="25" class="fancy" />
</svg>

上面的代码定义了三个圆。<circle>标签的cx、cy、r属性分别为横坐标、纵坐标和半径,单位为像素。坐标都是相对于<svg>画布的左上角原点。

class属性用来指定对应的 CSS 类。

.red {
  fill: red;
}

.fancy {
  fill: none;
  stroke: black;
  stroke-width: 3pt;
}

SVG 的 CSS 属性与网页元素有所不同。

  • fill:填充色
  • stroke:描边色
  • stroke-width:边框宽度

2.3<line>标签

<line>标签用来绘制直线。

<svg width="300" height="180">
  <line x1="0" y1="0" x2="200" y2="0" style="stroke:rgb(0,0,0);stroke-width:5" />
</svg>

上面代码中,<line>标签的x1属性和y1属性,表示线段起点的横坐标和纵坐标;x2属性和y2属性,表示线段终点的横坐标和纵坐标;style属性表示线段的样式。

2.4<polyline>标签

<polyline>标签用于绘制一根折线。

<svg width="300" height="180">
  <polyline points="3,3 30,28 3,53" fill="none" stroke="black" />
</svg>

<polyline>的points属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。

2.5<rect>标签

<rect>标签用于绘制矩形。

<svg width="300" height="180">
  <rect x="0" y="0" height="100" width="200" style="stroke: #70d5dd; fill: #dd524b" />
</svg>

<rect>的x属性和y属性,指定了矩形左上角端点的横坐标和纵坐标;width属性和height属性指定了矩形的宽度和高度(单位像素)。

2.6<ellipse>标签

<ellipse>标签用于绘制椭圆。

<svg width="300" height="180">
  <ellipse cx="60" cy="60" ry="40" rx="20" stroke="black" stroke-width="5" fill="silver"/>
</svg>

<ellipse>的cx属性和cy属性,指定了椭圆中心的横坐标和纵坐标(单位像素);rx属性和ry属性,指定了椭圆横向轴和纵向轴的半径(单位像素)。

2.7<polygon>标签

<polygon>标签用于绘制多边形。

<svg width="300" height="180">
  <polygon fill="green" stroke="orange" stroke-width="1" points="0,0 100,0 100,100 0,100 0,0"/>
</svg>

<polygon>的points属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。

2.8<path>标签

<path>标签用于制路径。

<svg width="300" height="180">
<path d="
  M 18,3
  L 46,3
  L 46,40
  L 61,40
  L 32,68
  L 3,40
  L 18,40
  Z
"></path>
</svg>

<path>的d属性表示绘制顺序,它的值是一个长字符串,每个字母表示一个绘制动作,后面跟着坐标。

  • M:移动到(moveto)
  • L:画直线到(lineto)
  • Z:闭合路径

2.9<text>标签

<text>标签用于绘制文本。

<svg width="300" height="180">
  <text x="50" y="25">Hello World</text>
</svg>

<text>的x属性和y属性,表示文本区块基线(baseline)起点的横坐标和纵坐标。文字的样式可以用class或style属性指定。

2.10<use>标签

<use>标签用于复制一个形状。

<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
  <circle id="myCircle" cx="5" cy="5" r="4"/>

  <use href="#myCircle" x="10" y="0" fill="blue" />
  <use href="#myCircle" x="20" y="0" fill="white" stroke="blue" />
</svg>

<use>的href属性指定所要复制的节点,x属性和y属性是<use>左上角的坐标。另外,还可以指定width和height坐标。

2.11<g>标签

<g>标签用于将多个形状组成一个组(group),方便复用。

<svg width="300" height="100">
  <g id="myCircle">
    <text x="25" y="20">圆形</text>
    <circle cx="50" cy="50" r="20"/>
  </g>

  <use href="#myCircle" x="100" y="0" fill="blue" />
  <use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>

2.12<defs>标签

<defs>标签用于自定义形状,它内部的代码不会显示,仅供引用。

<svg width="300" height="100">
  <defs>
    <g id="myCircle">
      <text x="25" y="20">圆形</text>
      <circle cx="50" cy="50" r="20"/>
    </g>
  </defs>

  <use href="#myCircle" x="0" y="0" />
  <use href="#myCircle" x="100" y="0" fill="blue" />
  <use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>

2.13<pattern>标签

<pattern>标签用于自定义一个形状,该形状可以被引用来平铺一个区域。

<svg width="500" height="500">
  <defs>
    <pattern id="dots" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
      <circle fill="#bee9e8" cx="50" cy="50" r="35" />
    </pattern>
  </defs>
  <rect x="0" y="0" width="100%" height="100%" fill="url(#dots)" />
</svg>

上面代码中,<pattern>标签将一个圆形定义为dots模式。patternUnits="userSpaceOnUse"表示<pattern>的宽度和长度是实际的像素值。然后,指定这个模式去填充下面的矩形。

2.14<image>标签

<image>标签用于插入图片文件。

<svg viewBox="0 0 100 100" width="100" height="100">
  <image xlink:href="path/to/image.jpg"
    width="50%" height="50%"/>
</svg>

上面代码中,<image>的xlink:href属性表示图像的来源。

2.15<animate>标签

<animate>标签用于产生动画效果。

<svg width="500px" height="500px">
  <rect x="0" y="0" width="100" height="100" fill="#feac5e">
    <animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
  </rect>
</svg>

上面代码中,矩形会不断移动,产生动画效果。

<animate>的属性含义如下。

  • attributeName:发生动画效果的属性名。
  • from:单次动画的初始值。
  • to:单次动画的结束值。
  • dur:单次动画的持续时间。
  • repeatCount:动画的循环模式。

可以在多个属性上面定义动画。

<animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
<animate attributeName="width" to="500" dur="2s" repeatCount="indefinite" />

2.16<animateTransform>标签

<animate>标签对 CSS 的transform属性不起作用,如果需要变形,就要使用<animateTransform>标签。

<svg width="500px" height="500px">
  <rect x="250" y="250" width="50" height="50" fill="#4bc0c8">
    <animateTransform attributeName="transform" type="rotate" begin="0s" dur="10s" from="0 200 200" to="360 400 400" repeatCount="indefinite" />
  </rect>
</svg>

上面代码中,<animateTransform>的效果为旋转(rotate),这时from和to属性值有三个数字,第一个数字是角度值,第二个值和第三个值是旋转中心的坐标。from="0 200 200"表示开始时,角度为0,围绕(200, 200)开始旋转;to="360 400 400"表示结束时,角度为360,围绕(400, 400)旋转。

三、JavaScript 操作

3.1 DOM 操作

如果 SVG 代码直接写在 HTML 网页之中,它就成为网页 DOM 的一部分,可以直接用 DOM 操作。

<svg
  id="mysvg"
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 800 600"
  preserveAspectRatio="xMidYMid meet"
>
  <circle id="mycircle" cx="400" cy="300" r="50" />
<svg>

上面代码插入网页之后,就可以用 CSS 定制样式。

circle {
  stroke-width: 5;
  stroke: #f00;
  fill: #ff0;
}

circle:hover {
  stroke: #090;
  fill: #fff;
}

然后,可以用 JavaScript 代码操作 SVG。

var mycircle = document.getElementById('mycircle');

mycircle.addEventListener('click', function(e) {
  console.log('circle clicked - enlarging');
  mycircle.setAttribute('r', 60);
}, false);

上面代码指定,如果点击图形,就改写circle元素的r属性。

3.2 获取 SVG DOM

使用<object>、<iframe>、<embed>标签插入 SVG 文件,可以获取 SVG DOM。

var svgObject = document.getElementById('object').contentDocument;
var svgIframe = document.getElementById('iframe').contentDocument;
var svgEmbed = document.getElementById('embed').getSVGDocument();

注意,如果使用<img>标签插入 SVG 文件,就无法获取 SVG DOM。

3.3 读取 SVG 源码

由于 SVG 文件就是一段 XML 文本,因此可以通过读取 XML 代码的方式,读取 SVG 源码。

<div id="svg-container">
  <svg
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xml:space="preserve" width="500" height="440"
  >
    <!-- svg code -->
  </svg>
</div>

使用XMLSerializer实例的serializeToString()方法,获取 SVG 元素的代码。

var svgString = new XMLSerializer()
  .serializeToString(document.querySelector('svg'));

3.4 SVG 图像转为 Canvas 图像

首先,需要新建一个Image对象,将 SVG 图像指定到该Image对象的src属性。

var img = new Image();
var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});

var DOMURL = self.URL || self.webkitURL || self;
var url = DOMURL.createObjectURL(svg);

img.src = url;

然后,当图像加载完成后,再将它绘制到<canvas>元素。

img.onload = function () {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
};

四、实例:折线图

下面将一张数据表格画成折线图。

Date |Amount
-----|------
2014-01-01 | $10
2014-02-01 | $20
2014-03-01 | $40
2014-04-01 | $80

上面的图形,可以画成一个坐标系,Date作为横轴,Amount作为纵轴,四行数据画成一个数据点。

<svg width="350" height="160">
  <g class="layer" transform="translate(60,10)">
    <circle r="5" cx="0"   cy="105" />
    <circle r="5" cx="90"  cy="90"  />
    <circle r="5" cx="180" cy="60"  />
    <circle r="5" cx="270" cy="0"   />

    <g class="y axis">
      <line x1="0" y1="0" x2="0" y2="120" />
      <text x="-40" y="105" dy="5">$10</text>
      <text x="-40" y="0"   dy="5">$80</text>
    </g>
    <g class="x axis" transform="translate(0, 120)">
      <line x1="0" y1="0" x2="270" y2="0" />
      <text x="-30"   y="20">January 2014</text>
      <text x="240" y="20">April</text>
    </g>
  </g>
</svg>

五、参考链接

(完)

文档信息

]]>
0
<![CDATA[iOS 面试之道]]> http://www.udpwork.com/item/16994.html http://www.udpwork.com/item/16994.html#reviews Sun, 05 Aug 2018 18:12:23 +0800 唐巧 http://www.udpwork.com/item/16994.html

关于新书

故胤道长 和 我合著的一本 iOS 面试方面的新书《iOS 面试之道》,两周前出版了。这本书我负责前面的第一章,讲面试的准备。后面的算法基础和 100 多道面试题,则是由道长编写。

老实说,这算不上一本很难很深的书。面试嘛,一般考察的内容也不会很偏很深,还是会偏基础知识一些,所以各位读者可以把这当作一本基础的面试讨论的书。书中有道长精心整理的 100 多道面试题,拿来练练手也是不错。

该书刚刚上市,还是获得了一些成绩。首先首印的 3500 册已经在几天内售罄,你现在下单的话,买到的是刚刚补货成功的 4000 册。另外,该书在上周冲上了京东的“计算机与互联网销量榜”第一名。

以下还有一些图书的相关信息

相信大家不管是当面试官还是当候选人,都可以从本书中学到一些有用的东西。该书在各大网店都已上架,点击这里,可以直达京东购买。

面试之道

我从一个程序员,转变为业务负责人,面试的人从 iOS 到服务器研发,再到测试、产品经理、UI、教研,运营等。所以,我可以在这儿分享一些面试各类成才的通用的「面试之道」。当然,这些内容是没写在书里面的,该书还是只讲「iOS面试」之道的。

面试的不严谨一面

基本上,面试有着它不严谨的一面:因为你要求在 3 个小时内,考察出一个人的水平。程序员还好,你可以问问他专业知识,写两行代码。但是别的职位其实很难。

就拿产品经理来说吧,因为一个产品线上的结果是由各方面决定的,你很难评价一个产品经理的工作质量。也许这个产品经理能力一般,但是他的老板本身非常注重产品细节,让最终的产品细节打磨得很好,除非这个候选人特别诚实,否则你这在面试的时候很难判断得出来。

又比如说设计师的作品,一般设计团队的 Leader 会对团队的作品严格把关,这就使得你看到的作品,不知道多少是他自己的能力,多少是他所在团队的能力。

所以,有些公司只招好学校的毕业生,只招成功产品的产品经理,只招成功投放过的市场人员,也是为了降低这类的风险,与歧视无关。

面试的严谨一面

如果你看过《眨眼之间》《思考快与慢》这些书,你就会发现,直觉这个东西其实是可以训练的。《思考快与慢》的作者是诺贝尔经济学家得主丹尼尔·卡尼曼,他认为直觉很多时候是不靠谱的。但是他赞同《眨眼之间》作者的一个观点:在环境类似,方法可提炼的场景,个人的直觉能力会被提升。例如医生、消防员、画家、警察等职业工作场景。

我个人认为,面试也是一个非常类似的场景。虽然面试官只有短短的 45 分钟与候选人交谈,问的问题也是千篇一律的问题。但是就是因为面试官不停地在“重复”,所以他很容易就对同一个问题的上百次回答产生直觉性判断。面试得多了,候选人的一些小细节都可能被面试官捕捉并观察到。打个不恰当的比喻,这和《眨眼之间》里面警察审犯人时能一眼看出犯人是否撒谎是一个道理

执行层面

在执行层面,我觉得一个面试各类职位的通用型的面试应该考察到:逻辑、表达、热情、细节、团队合作这些方面。下面简单展开说一说。

逻辑。所有职位的人,都要讲逻辑。不管是产品经理,还是设计师。逻辑不清楚的人,很难让别人理解和接受他的意见。所以,我会特别看重一个人表达的逻辑性。如果一个人的表达不但有逻辑,还很「结构化」,那么我会很喜欢。

表达。表达的流利程度也很重要,但是这个看职位和性格,我不会特别强求。比如程序员大多内向,表达语速偏慢,偏严谨,都是很正常的。重要的还是他的表达背后的逻辑性强不强,信息量是不是足够的。我特别不喜欢一个候选人回答了很久,但是没有抓住问题的重点,简单来说就是答非所问。

热情。现在早已经不是吃大锅饭的年代,大家也很难一辈子在一家公司。我希望候选人对应聘的职位有热情,希望提升他自己的某些方面,这样才是一个双赢的事情。如果一个候选人在专业上表达得并不热情,又特别看重按时上下班这些,我通常是减分的。这其实并不代表我希望大家加班,其实我们公司是一个加班文化特别少的公司,甚至还会强调尽量不加班。但是我觉得如果一个人工作的追求仅仅是「不加班」,是很低级的,这就像一个人工作只希望吃饱饭一样,追求层次太低。

细节。每个人的简历都是偏概括型的,只有深入追问细节,你才可以有更多的信息量进行判断。要深入细节问,可以问项目的背景,目标,流程,进度控制,人员规模和分工,协作方式,挑战等各种信息。深入细节后,你首先可以判断出他对于简历的描述是否是真实的,然后可以判断他对于项目的贡献度是多少,有些时候你还可以判断出他的工作质量。

团队合作。几乎所有的职位都不是单打独斗的,所以团队合作非常重要。有一些候选人在面试时性格表现得特别咄咄逼人,那么在工作中对待同事可能也是这样。有一些候选人把所有的项目失败的原因都归结给别人,但是又没能利用自己的影响力对项目做引导。有一些候选人性格特别内向,但是他的职位需要偏外向的性格。这些都是面试考察中需要注意的地方。

结束语

不管怎么努力,面试终究还是博一个概率事件,再牛逼的面试官也有看走眼的时候,只是相对来说概率比较低。这也是为什么所有企业都有「试用期」一说。所以如果真的招进来人不合适,还是尽快给双方一个退路更好。

就酱。

欢迎购买道长和我的新书《iOS 面试之道》,谢谢~

]]>

关于新书

故胤道长 和 我合著的一本 iOS 面试方面的新书《iOS 面试之道》,两周前出版了。这本书我负责前面的第一章,讲面试的准备。后面的算法基础和 100 多道面试题,则是由道长编写。

老实说,这算不上一本很难很深的书。面试嘛,一般考察的内容也不会很偏很深,还是会偏基础知识一些,所以各位读者可以把这当作一本基础的面试讨论的书。书中有道长精心整理的 100 多道面试题,拿来练练手也是不错。

该书刚刚上市,还是获得了一些成绩。首先首印的 3500 册已经在几天内售罄,你现在下单的话,买到的是刚刚补货成功的 4000 册。另外,该书在上周冲上了京东的“计算机与互联网销量榜”第一名。

以下还有一些图书的相关信息

相信大家不管是当面试官还是当候选人,都可以从本书中学到一些有用的东西。该书在各大网店都已上架,点击这里,可以直达京东购买。

面试之道

我从一个程序员,转变为业务负责人,面试的人从 iOS 到服务器研发,再到测试、产品经理、UI、教研,运营等。所以,我可以在这儿分享一些面试各类成才的通用的「面试之道」。当然,这些内容是没写在书里面的,该书还是只讲「iOS面试」之道的。

面试的不严谨一面

基本上,面试有着它不严谨的一面:因为你要求在 3 个小时内,考察出一个人的水平。程序员还好,你可以问问他专业知识,写两行代码。但是别的职位其实很难。

就拿产品经理来说吧,因为一个产品线上的结果是由各方面决定的,你很难评价一个产品经理的工作质量。也许这个产品经理能力一般,但是他的老板本身非常注重产品细节,让最终的产品细节打磨得很好,除非这个候选人特别诚实,否则你这在面试的时候很难判断得出来。

又比如说设计师的作品,一般设计团队的 Leader 会对团队的作品严格把关,这就使得你看到的作品,不知道多少是他自己的能力,多少是他所在团队的能力。

所以,有些公司只招好学校的毕业生,只招成功产品的产品经理,只招成功投放过的市场人员,也是为了降低这类的风险,与歧视无关。

面试的严谨一面

如果你看过《眨眼之间》《思考快与慢》这些书,你就会发现,直觉这个东西其实是可以训练的。《思考快与慢》的作者是诺贝尔经济学家得主丹尼尔·卡尼曼,他认为直觉很多时候是不靠谱的。但是他赞同《眨眼之间》作者的一个观点:在环境类似,方法可提炼的场景,个人的直觉能力会被提升。例如医生、消防员、画家、警察等职业工作场景。

我个人认为,面试也是一个非常类似的场景。虽然面试官只有短短的 45 分钟与候选人交谈,问的问题也是千篇一律的问题。但是就是因为面试官不停地在“重复”,所以他很容易就对同一个问题的上百次回答产生直觉性判断。面试得多了,候选人的一些小细节都可能被面试官捕捉并观察到。打个不恰当的比喻,这和《眨眼之间》里面警察审犯人时能一眼看出犯人是否撒谎是一个道理

执行层面

在执行层面,我觉得一个面试各类职位的通用型的面试应该考察到:逻辑、表达、热情、细节、团队合作这些方面。下面简单展开说一说。

逻辑。所有职位的人,都要讲逻辑。不管是产品经理,还是设计师。逻辑不清楚的人,很难让别人理解和接受他的意见。所以,我会特别看重一个人表达的逻辑性。如果一个人的表达不但有逻辑,还很「结构化」,那么我会很喜欢。

表达。表达的流利程度也很重要,但是这个看职位和性格,我不会特别强求。比如程序员大多内向,表达语速偏慢,偏严谨,都是很正常的。重要的还是他的表达背后的逻辑性强不强,信息量是不是足够的。我特别不喜欢一个候选人回答了很久,但是没有抓住问题的重点,简单来说就是答非所问。

热情。现在早已经不是吃大锅饭的年代,大家也很难一辈子在一家公司。我希望候选人对应聘的职位有热情,希望提升他自己的某些方面,这样才是一个双赢的事情。如果一个候选人在专业上表达得并不热情,又特别看重按时上下班这些,我通常是减分的。这其实并不代表我希望大家加班,其实我们公司是一个加班文化特别少的公司,甚至还会强调尽量不加班。但是我觉得如果一个人工作的追求仅仅是「不加班」,是很低级的,这就像一个人工作只希望吃饱饭一样,追求层次太低。

细节。每个人的简历都是偏概括型的,只有深入追问细节,你才可以有更多的信息量进行判断。要深入细节问,可以问项目的背景,目标,流程,进度控制,人员规模和分工,协作方式,挑战等各种信息。深入细节后,你首先可以判断出他对于简历的描述是否是真实的,然后可以判断他对于项目的贡献度是多少,有些时候你还可以判断出他的工作质量。

团队合作。几乎所有的职位都不是单打独斗的,所以团队合作非常重要。有一些候选人在面试时性格表现得特别咄咄逼人,那么在工作中对待同事可能也是这样。有一些候选人把所有的项目失败的原因都归结给别人,但是又没能利用自己的影响力对项目做引导。有一些候选人性格特别内向,但是他的职位需要偏外向的性格。这些都是面试考察中需要注意的地方。

结束语

不管怎么努力,面试终究还是博一个概率事件,再牛逼的面试官也有看走眼的时候,只是相对来说概率比较低。这也是为什么所有企业都有「试用期」一说。所以如果真的招进来人不合适,还是尽快给双方一个退路更好。

就酱。

欢迎购买道长和我的新书《iOS 面试之道》,谢谢~

]]>
0
<![CDATA[每周分享第 16 期]]> http://www.udpwork.com/item/16991.html http://www.udpwork.com/item/16991.html#reviews Fri, 03 Aug 2018 11:03:33 +0800 阮一峰 http://www.udpwork.com/item/16991.html 这里记录过去一周,我看到的值得分享的东西,每周五发布。

影视作品经常出现,病人的心脏停止跳动,医生使用两块电极板对心脏电击。它叫除颤器(defibrillator),通过放电刺激心脏恢复跳动。

除颤器必须在心跳停止以后立刻使用,拖延越久,希望越渺茫。可想而知,大部分心脏停止的病人是死定的。据统计,美国每年心脏骤停有35万人,其中90%以上都没有抢救的机会。医生们于是想到了,能不能把除颤器放在体内呢?

体内除颤器就是这样发明的。这个装置放在心脏衰弱的病人体内,自动检查心脏骤停,一旦发现立刻电击。它救了很多人,但带来了另一个问题。那些心脏衰弱的病人,即使抢救回来,心脏还是衰弱的,而且由于经受了一次电击,会变得比以前更衰弱。病人很可能不久就会发生另一次心脏骤停,或者心脏越来越弱,无法满足身体新陈代谢的需要,导致其他器官慢性衰竭。也就是说,除颤器只是推迟了死亡的时间和方式,病人从死于心脏骤停变成死于慢性衰竭。

安装"体内除颤器"需要病人的同意,毕竟是一个大手术。《纽约时报》就有一篇心脏医生的文章,他认为这迫使病人选择自己的死亡方式:你要死得快而无痛,还是慢而痛苦?他举例,一个心脏病人虽然抢救回来了,但是肺部逐渐衰竭,严重积液,导致每一口呼吸都非常困难,最终在窒息的痛苦中慢慢死去。

我觉得,这种问题是技术带来的,也只有靠技术解决。如果技术可以让病人免于骤死,那么可能也能免于慢性衰竭。心脏衰竭了,就换人工心脏;肺衰竭了,就装人工肺。到了那时,人类好像就不那么容易死亡了,只是一刻都离不开机器了,一旦停电或机器故障,立马就没命了。

新闻

1、射向地球的高能粒子

1912年,科学家发现,地球每天都在遭受高能粒子的撞击。这些粒子的能量非常大,因此必定有一个地方在源源不断地射出它们,然后地球正好在这些粒子的喷射轨道上。但是,一百多年来,科学家都没有答案,到底什么地方在喷射高能粒子?

上个月终于发现了,宇宙射线的来源之一是一个叫做 blazar 的星系。它的中心有超大质量的黑洞,将吸入的物质撕成粒子,然后像激光炮一样将这些粒子抛向太空。

2、贝佐斯成为现代史上最富有的人

亚马逊公司的股票不断上涨,创始人贝佐斯成为世界首富,还成为现代历史上最有钱的人。

他的财富估计为1500亿美元。第二位的比尔·盖茨大概拥有953亿美元。不过,盖茨捐掉了近7亿股微软股票和29亿美元现金。如果算上这些钱,那么他的净资产将超过1500亿美元。

3、消除图片噪点的算法

美国科学家公布了一种消除图片噪点的 AI 算法。这种算法可以从有噪点的图片推断出原图。上面第一张图是原图,第二张是算法处理的结果,第三张是没有噪点的实际图像。

4、飞行汽车

很多公司都在开发可以飞行的汽车,不少已经做出了成品。BlackFly 是最接近完成的一个产品。

它可以用100公里/小时的速度,飞行40公里。能量来自电池,一次充电需要30分钟。下图后面的架子是它的充电器。

它是垂直起降的,带有八个推进器,分布在两个机翼上,只能载一个人。出品公司宣称,已经进行了多年1400多次的测试,飞行距离超过12,000多英里。

5、2018 美国最佳工作场所

美国一家媒体根据员工体验,对财富500强的工作环境进行了排名。员工心目中的最佳工作场所前三名依次是 Facebook、西南航空和 Salesforce。下面是对它们的评语。

  • Facebook:工作场所充满活力。人员都经验丰富,能力极强。管理层坚定但乐于助人。团队合作至关重要。
  • 西南航空:精彩的管理,令人敬畏的同事,鼓励个性和进步。
  • Salseforce: 快节奏,具有挑战性的项目和聪明的人以及酷炫有趣的文化相结合。无论头衔或职级如何,你都可以发表自己的声音和意见,尽管有疯狂的工作安排,但有趣的氛围可以平衡。

6、开放的视频编码方案

目前,互联网视频大部分采用 H.264 编码方案。这个方案是有专利的,使用必须付费。即使你可以在 Youtube 这样的视频网站免费观看视频,但是 Youtube 必须为使用 H.264 每年支付几百万美元。

为了有一个彻底开放的视频编码方案,也为了更好的性能,2015年多家软件和硬件厂商成立了 AOMedia 联盟。现在,新的视频编解码器AV1终于问世了。AV1 主要基于谷歌的 VP9 编码方案,并加入了其他代码。AV1是无版权的,任何人都可以免费使用。它比 H.264 提供更高效的压缩,大约高出30%。

7、芝加哥地下快运系统

特斯拉老板马斯克旗下的 Boring Company,不久前中标芝加哥市地下快运系统,挖一条隧道,连接市中心到机场。

Boring Company 披露了这个系统的细节。它依靠电动轨道车承运旅客,单车载客8~16人,时速最高240公里,每30秒一班,单程12分钟,比现有的客运系统节约70%的时间。施工时间最短18个月,最长可能要3年。

8、人工智能生成慢镜头

Nvidia 公司宣布了一种 Super Slomo 技术,可以用人工智能生成慢镜头。

常规的做法是,摄像机每秒拍摄240帧,然后以每秒30帧的速度播放,从而达到放慢8倍的效果。这种新技术可以基于普通视频,自动生成多余的帧,从而达到超级慢镜头的效果。

9、智能绷带

美国一所大学发明了智能绷带,上面有传感器和药物。传感器监控伤口的 pH 值,实现智能给药。这对于慢性伤口非常有效。

10、一万亿美元市值的公司

历史上,从来没有一家美国公司达到 10000 亿美元的市值。现在,五家公司正在接近这个金额。

  • Apple:9240亿美元
  • 亚马逊:8480亿美元
  • Alphabet:8140亿美元
  • 微软:7820亿美元
  • Facebook:5870亿美元

这五家公司合计占标准普尔500指数总市值的16.5%。这个比例虽然不是历史最高,但这五家公司都是同一个行业的,这是历史上从来没有的。

最新消息是,苹果公司已经达到了1万亿美元市值。但是,媒体发现2007年有一家中国公司也曾有一万亿美元市值,因此苹果公司只能排在历史第二。2007年,中国石油在上交所上市,第一天的开盘价是48元,市值超过1万亿美元,成为全球最大公司。但是,它只在那个位置待了一天,然后不断下跌,再也没有涨回去过。

11、一句话新闻

  • PrePack的最新 PR,把编译后端从 Node 改成了LLVM,使得 JS 可以编译成 webAssembly 甚至汇编语言了。
  • GitHub放弃使用 jQuery,改用标准 JS 操作 DOM。jQuery 的历史使命已经完成,正在退出前端开发的工具箱。
  • Opera 浏览器发布 Linux 版本。

教程

1、图数据结构入门(英文)

图(graph)是一种数据结构,由点(vertex)和边(edge)组成。本文介绍图结构的算法基本知识。

2、判断油画的年代(英文)

上面这幅欧洲油画是什么时候画的,15世纪还是17世纪?

这种问题恐怕要熟悉欧洲艺术的专家才能回答。现在,有人写了一个神经网络教程,介绍如何用算法判断油画的年代。

3、SVG 背景(英文)

这篇文章教你如何手写一个 SVG 文件,作为网页的背景图案。

4、气候变暖的入门介绍(英文)

全球气候正在变暖,这到底是怎么一回事,原因是什么。本文是我读过最好的这方面的入门读物。

5、如何设计 Web 应用的架构(中文)

大型 Web 应用最关键的就是架构,最难的也是架构。这份教程整理了这方面需要知道的知识。

6、Webpack 4 入门教程(英文)

Webpack 是 JS 代码的打包器,现在前端开发的主流工具。Webpack 4 是它的最新版本。

7、ssh 端口为什么是 22?(英文)

SSH 的作者回忆, ftp 端口是21,telnet 的端口是23,他就挑了中间剩下的22。

8、PDF 格式有什么用?(英文)

作者认为应该避免使用 PDF 格式。一般情况下,HTML 格式是更好的选择。如果要求保证精确的打印效果,可以使用压缩的 Postscript 格式。

9、为什么 Kubernetes 是新的应用服务器?(英文)

这篇文章解释,为什么以后发布应用的时候,不是直接发布在服务器上,而是通过 Kubernetes 发布。

工具

1、微软 Whiteboard

微软推出了一个团队协作工具,可以让用户在多种设备上,远程实时分享电子白板。目前,它只有 Windows 10 的客户端,但马上就会推出 iOS 客户端和 Web 版本。

2、thumbor

有的图片 CDN 可以对图片进行实时处理,允许指定图片的大小和方向。thumbor 就是这样一种图片服务器。

3、prose

Go 语言写的自然语言处理工具,目前只能处理英语。

4、Nand Game

一个网页游戏,玩家通过组合虚拟电路,组装出一台计算机。

5、Video Hub

一个管理本地视频的免费桌面软件,可以预览、搜索、分类各类视频文件。

6、Vialer-js

一个基于 WebRTC 技术的实时通讯平台,可以实现 P2P 的文字聊天、语音和视频对话。

7、Neutralinojs

一个使用系统原生组件开发桌面应用的框架,相比 Electron,好处就是打包出来的体积比较小。

8、μPad

一个开源的多端笔记本工具,兼容 Evernote。

9、Browsh

Browsh 是一个基于 Firefox 的命令行脚本,可以在命令行打开网页,并且渲染出大致的样子。它也可以用作移动端网页浏览的处理方案。

资源

1、汇编语言初学者教程(PDF)

开源电子书,从零开始介绍汇编语言,读者必须懂一点 C 语言。内容很全,也非常厚。

2、Bloomberg 机器学习课程

这个培训课程帮助学员深入理解机器学习的概念,技术和数学框架。一共30个讲座,包括一整套课后作业。

3、XV6

麻省理工学院开发的一个类似 Unix 的教学操作系统。

4、Acceptance Test Driven Development with React

中国开发者写的英语专著,介绍前端测试。书放在 Leanpub,付不付费、付多少钱都是自愿的。

5、网站可靠性工作手册

《网站可靠性工作手册》一书现在免费下载,谷歌官网提供,为期一个月。

文摘

1、郭台铭的创业

郭台铭创业初期,好不容易有了进一步投资的钱,当时有两个选择:一是买地自己盖厂房,然后买人家的模具;二是租别人的厂房,自己买机床开发模具,加强研发能力。

他选择了后者。结果几年后,地价一口气涨了10倍,房东大幅上涨房租,而模具还没开发出来,还在摸索中,因此苦不堪言,经济很窘迫。但是,郭台铭后来说,幸好选择了后者,因为房价到一定程度就不再快速上涨了,靠房地产只能赚一次的钱,但是一旦掌握了核心技术,可以赚无数次钱。

2、达芬奇的求职信

1483年,31岁的达芬奇离开故乡,来到米兰。他没钱,需要找工作,就给米兰公爵写了一封求职信。

这封信写得极好,公爵一看就认定达芬奇是一个人才,从而给他资助。即使在今天,这样的信依然能帮你找到工作。

尊敬的,显贵的公爵阁下:

我是来自佛罗伦萨的作战机械发明者达·芬奇,希望可以成为阁下您的军事工程师,同时求见阁下,以便面陈机密:

一、我能建造坚固、轻便又耐用的桥梁,可用来野外行军。这种桥梁的装卸非常方便。我也能破坏敌军的桥梁。

二、我能制造出围攻城池的云梯和其他类似设备。

三、我能制造一种易于搬运的大炮,可用来投射小石块,犹如下冰雹一般,可以给敌军造成重大损失和混乱。

四、我能制造出装有大炮的铁甲车,可用来冲破敌军密集的队伍,为我军的进攻开辟道路。

五、我能设计出各种地道,无论是直的还是弯的,必要时还可以设计出在河流下面挖地道的方法。

六、倘若您要在海上作战,我能设计出多种适宜进攻的兵船,这些兵船的防护力很好,能够抵御敌军的炮火攻击。......

九、如果战斗发生在海上,我打算建造能够抵抗最猛烈炮火和烟尘的船只。

十、和平时期,我相信在建筑上,以及从一地到另一地的引水工程上,我一样可以像其他人那样令您完全满意。......

此外,我还擅长建造其他民用设施,同时擅长绘画和雕塑。

如果有人认为上述任何一项我办不到的话,我愿在您的花园,或您指定的其他任何地点进行试验。

谨此无限谦恭之忱,向阁下问安!

列奥纳多·迪·皮耶罗·达·芬奇

3、澳大利亚的巨响蚁

1931年,西澳大利亚州的阿里德角半岛,一些自然爱好者在灌木丛生的荒原上,发现了一种没人见过的昆虫。

它看上去隐约有点蚂蚁的模样,可却是一种不寻常的淡黄色,还有一双奇怪的眼睛,很惹眼,显得异常局促不安。人们收集了一些标本,送到墨尔本维多利亚国家博物馆某位专家的桌上,专家立马就认定这种昆虫是巨响蚁。这一发现使人们极为兴奋,因为据人类所知,类似的东西不存于地球已经1亿年之久了。巨响蚁是一种原始蚂蚁,是蚂蚁自黄蜂开始的进化过程中某一时段的活化石。在昆虫学领域,这非凡卓越得就仿佛有人发现一群三角龙在某个遥远的草原上啃草一样。

考察队立刻组织起来,可是,虽然进行了最为一丝不苟的搜寻,但没人找得到阿里德角蚁群。之后的寻找也同样空手而回。

差不多过了半个世纪,当传闻一队美国科学家正计划寻找这种蚂蚁,而且几乎肯定会带上那种让澳大利亚人显得业余且组织不力的高科技精巧装置的时候,堪培拉的官方科学家们决定先发制人,为找到这种蚂蚁的活体做最后一次努力。于是,他们组织了一队人马出发横穿整个国家。

野外的第二天,正开车经过南澳大利亚州荒漠的时候,一辆车冒烟了,开起来啪啪啪地乱响,他们被迫打破日程,在公路上的一处偏僻驿站普彻拉停留一晚。晚间,科学家鲍勃·泰勒踱步出来透透气,无所事事之间把玩着手电筒,光柱扫向周围的地面。你可以想象出他的惊诧莫名啦,他发现,在他们营地附近一棵桉树树干上爬过的那队人丁兴旺的蚁群不是巨响蚁又是什么。

现在,我们来考虑一下可能性的问题。泰勒和他的同事距他们预定搜寻地有800英里之遥。在澳大利亚约摸3百万平方英里的旷野中,一小撮能够识别地球上最稀有、最吃香的虫子的人中的一个找到了这种虫子----它的活体只被人看见过一趟,还是差不多半个世纪之前----而这统统是因为他们的车子在此处抛锚了。其附带结果便是,巨响蚁至今仍旧没有在其原发现地被找到。

本周图片

1、平铺平面的五边形

有一个数学难题,怎样的多边形可以铺满一个平面?数学家已经证明,任意三角形和四边形都可以,五边形不确定,六边形只有三种可以,其他都不行。

上图是目前找到的所有15种五边形,可以平铺平面。

其中的第15种五边形,2015年发现的。

2、最热门的编程语言

根据谷歌搜索指数,Python 语言过去10年一直在上升,现在已经是最热门的编程语言。(图片来源《经济学家》杂志)

3、圣赫勒拿岛游记(组图)

圣赫勒拿岛最著名的景点,当然是拿破仑故居和空的拿破仑墓。1815年,拿破仑被流放到这里,1821年去世安葬在岛上的墓地。1840年法国政府将灵柩移回巴黎,买下岛上三块拿破仑有关土地,并入法国领土,成为"在英国海外领地上的法国海外领土"。

拿破仑故居门口立着牌子,禁止拍照,不过没有监控,靠自觉。我是2018年这个别墅的第一个参观游客,在别墅里忍不住,拍了一些内部照片。里面的所有家具和设施完全是原物原样,没有任何变化,让你觉得好像拿破仑昨天才在这里去世。

往山下开一段路,就是另一块法国领土,拿破仑墓。当然,是空的,灵柩已经移回巴黎。这块墓地占的区域很大,由松木屑铺成防滑的山路一直走下去。没人看管,任何时候都可以来。

我住的旅馆,由英国遗民Hazel老太太经营。其中一部分是2008年从所罗门家族买来的,包括书房,大部分都保持原样几百年。临走前一天,Hazel告诉我,她接到一个叫信天翁的旅游agent订单,有11个北京来的中国团第二天到。然后她有点担心地问我,他们会不会在房间 cooking?

以前有一个中国人住的时候,在房间煮面方便面,弄得房间都是味道。我想了一下,觉得非常有可能。于是我帮她写了5页纸的中文 tips,希望他们不要在房间煮面,另外也尽可能告知了一些岛上的吃喝玩乐地方,不晓得最后这11位中国同胞看到没有。

本周金句

1、

圆明园的兽头,原本是喷水池的水龙头。它们不太可能是八国联军抢走的,因为圆明园珍宝如山,八国联军会抢这种仿制西方的喷头吗?它们十有八九是圆明园废弃后,中国人自己弄下来卖掉的。(张鸣

2、

你存心做一个与世无争的老实人吧,人家就利用你欺侮你。你稍有才德品貌,人家就嫉妒你排挤你。 你大度退让,人家就侵犯你损害你。你要不与人争,就得与世无求,同时还要维持实力准备斗争。你要和别人和平共处,就先得和他们周旋,还得准备随时吃亏。 (杨绛

3、

摩尔定理有一个后果,每隔几年,我们就要学习一个新的希腊语前缀:mega-、giga-、tera-、peta-、exa-、......(推特@UnitFact

欢迎订阅

这个专栏每周五发布,同步更新在我的个人网站微信公众号语雀

微信搜索"阮一峰的网络日志 "或者扫描二维码,即可订阅。

image | left

(完)

文档信息

]]>
这里记录过去一周,我看到的值得分享的东西,每周五发布。

影视作品经常出现,病人的心脏停止跳动,医生使用两块电极板对心脏电击。它叫除颤器(defibrillator),通过放电刺激心脏恢复跳动。

除颤器必须在心跳停止以后立刻使用,拖延越久,希望越渺茫。可想而知,大部分心脏停止的病人是死定的。据统计,美国每年心脏骤停有35万人,其中90%以上都没有抢救的机会。医生们于是想到了,能不能把除颤器放在体内呢?

体内除颤器就是这样发明的。这个装置放在心脏衰弱的病人体内,自动检查心脏骤停,一旦发现立刻电击。它救了很多人,但带来了另一个问题。那些心脏衰弱的病人,即使抢救回来,心脏还是衰弱的,而且由于经受了一次电击,会变得比以前更衰弱。病人很可能不久就会发生另一次心脏骤停,或者心脏越来越弱,无法满足身体新陈代谢的需要,导致其他器官慢性衰竭。也就是说,除颤器只是推迟了死亡的时间和方式,病人从死于心脏骤停变成死于慢性衰竭。

安装"体内除颤器"需要病人的同意,毕竟是一个大手术。《纽约时报》就有一篇心脏医生的文章,他认为这迫使病人选择自己的死亡方式:你要死得快而无痛,还是慢而痛苦?他举例,一个心脏病人虽然抢救回来了,但是肺部逐渐衰竭,严重积液,导致每一口呼吸都非常困难,最终在窒息的痛苦中慢慢死去。

我觉得,这种问题是技术带来的,也只有靠技术解决。如果技术可以让病人免于骤死,那么可能也能免于慢性衰竭。心脏衰竭了,就换人工心脏;肺衰竭了,就装人工肺。到了那时,人类好像就不那么容易死亡了,只是一刻都离不开机器了,一旦停电或机器故障,立马就没命了。

新闻

1、射向地球的高能粒子

1912年,科学家发现,地球每天都在遭受高能粒子的撞击。这些粒子的能量非常大,因此必定有一个地方在源源不断地射出它们,然后地球正好在这些粒子的喷射轨道上。但是,一百多年来,科学家都没有答案,到底什么地方在喷射高能粒子?

上个月终于发现了,宇宙射线的来源之一是一个叫做 blazar 的星系。它的中心有超大质量的黑洞,将吸入的物质撕成粒子,然后像激光炮一样将这些粒子抛向太空。

2、贝佐斯成为现代史上最富有的人

亚马逊公司的股票不断上涨,创始人贝佐斯成为世界首富,还成为现代历史上最有钱的人。

他的财富估计为1500亿美元。第二位的比尔·盖茨大概拥有953亿美元。不过,盖茨捐掉了近7亿股微软股票和29亿美元现金。如果算上这些钱,那么他的净资产将超过1500亿美元。

3、消除图片噪点的算法

美国科学家公布了一种消除图片噪点的 AI 算法。这种算法可以从有噪点的图片推断出原图。上面第一张图是原图,第二张是算法处理的结果,第三张是没有噪点的实际图像。

4、飞行汽车

很多公司都在开发可以飞行的汽车,不少已经做出了成品。BlackFly 是最接近完成的一个产品。

它可以用100公里/小时的速度,飞行40公里。能量来自电池,一次充电需要30分钟。下图后面的架子是它的充电器。

它是垂直起降的,带有八个推进器,分布在两个机翼上,只能载一个人。出品公司宣称,已经进行了多年1400多次的测试,飞行距离超过12,000多英里。

5、2018 美国最佳工作场所

美国一家媒体根据员工体验,对财富500强的工作环境进行了排名。员工心目中的最佳工作场所前三名依次是 Facebook、西南航空和 Salesforce。下面是对它们的评语。

  • Facebook:工作场所充满活力。人员都经验丰富,能力极强。管理层坚定但乐于助人。团队合作至关重要。
  • 西南航空:精彩的管理,令人敬畏的同事,鼓励个性和进步。
  • Salseforce: 快节奏,具有挑战性的项目和聪明的人以及酷炫有趣的文化相结合。无论头衔或职级如何,你都可以发表自己的声音和意见,尽管有疯狂的工作安排,但有趣的氛围可以平衡。

6、开放的视频编码方案

目前,互联网视频大部分采用 H.264 编码方案。这个方案是有专利的,使用必须付费。即使你可以在 Youtube 这样的视频网站免费观看视频,但是 Youtube 必须为使用 H.264 每年支付几百万美元。

为了有一个彻底开放的视频编码方案,也为了更好的性能,2015年多家软件和硬件厂商成立了 AOMedia 联盟。现在,新的视频编解码器AV1终于问世了。AV1 主要基于谷歌的 VP9 编码方案,并加入了其他代码。AV1是无版权的,任何人都可以免费使用。它比 H.264 提供更高效的压缩,大约高出30%。

7、芝加哥地下快运系统

特斯拉老板马斯克旗下的 Boring Company,不久前中标芝加哥市地下快运系统,挖一条隧道,连接市中心到机场。

Boring Company 披露了这个系统的细节。它依靠电动轨道车承运旅客,单车载客8~16人,时速最高240公里,每30秒一班,单程12分钟,比现有的客运系统节约70%的时间。施工时间最短18个月,最长可能要3年。

8、人工智能生成慢镜头

Nvidia 公司宣布了一种 Super Slomo 技术,可以用人工智能生成慢镜头。

常规的做法是,摄像机每秒拍摄240帧,然后以每秒30帧的速度播放,从而达到放慢8倍的效果。这种新技术可以基于普通视频,自动生成多余的帧,从而达到超级慢镜头的效果。

9、智能绷带

美国一所大学发明了智能绷带,上面有传感器和药物。传感器监控伤口的 pH 值,实现智能给药。这对于慢性伤口非常有效。

10、一万亿美元市值的公司

历史上,从来没有一家美国公司达到 10000 亿美元的市值。现在,五家公司正在接近这个金额。

  • Apple:9240亿美元
  • 亚马逊:8480亿美元
  • Alphabet:8140亿美元
  • 微软:7820亿美元
  • Facebook:5870亿美元

这五家公司合计占标准普尔500指数总市值的16.5%。这个比例虽然不是历史最高,但这五家公司都是同一个行业的,这是历史上从来没有的。

最新消息是,苹果公司已经达到了1万亿美元市值。但是,媒体发现2007年有一家中国公司也曾有一万亿美元市值,因此苹果公司只能排在历史第二。2007年,中国石油在上交所上市,第一天的开盘价是48元,市值超过1万亿美元,成为全球最大公司。但是,它只在那个位置待了一天,然后不断下跌,再也没有涨回去过。

11、一句话新闻

  • PrePack的最新 PR,把编译后端从 Node 改成了LLVM,使得 JS 可以编译成 webAssembly 甚至汇编语言了。
  • GitHub放弃使用 jQuery,改用标准 JS 操作 DOM。jQuery 的历史使命已经完成,正在退出前端开发的工具箱。
  • Opera 浏览器发布 Linux 版本。

教程

1、图数据结构入门(英文)

图(graph)是一种数据结构,由点(vertex)和边(edge)组成。本文介绍图结构的算法基本知识。

2、判断油画的年代(英文)

上面这幅欧洲油画是什么时候画的,15世纪还是17世纪?

这种问题恐怕要熟悉欧洲艺术的专家才能回答。现在,有人写了一个神经网络教程,介绍如何用算法判断油画的年代。

3、SVG 背景(英文)

这篇文章教你如何手写一个 SVG 文件,作为网页的背景图案。

4、气候变暖的入门介绍(英文)

全球气候正在变暖,这到底是怎么一回事,原因是什么。本文是我读过最好的这方面的入门读物。

5、如何设计 Web 应用的架构(中文)

大型 Web 应用最关键的就是架构,最难的也是架构。这份教程整理了这方面需要知道的知识。

6、Webpack 4 入门教程(英文)

Webpack 是 JS 代码的打包器,现在前端开发的主流工具。Webpack 4 是它的最新版本。

7、ssh 端口为什么是 22?(英文)

SSH 的作者回忆, ftp 端口是21,telnet 的端口是23,他就挑了中间剩下的22。

8、PDF 格式有什么用?(英文)

作者认为应该避免使用 PDF 格式。一般情况下,HTML 格式是更好的选择。如果要求保证精确的打印效果,可以使用压缩的 Postscript 格式。

9、为什么 Kubernetes 是新的应用服务器?(英文)

这篇文章解释,为什么以后发布应用的时候,不是直接发布在服务器上,而是通过 Kubernetes 发布。

工具

1、微软 Whiteboard

微软推出了一个团队协作工具,可以让用户在多种设备上,远程实时分享电子白板。目前,它只有 Windows 10 的客户端,但马上就会推出 iOS 客户端和 Web 版本。

2、thumbor

有的图片 CDN 可以对图片进行实时处理,允许指定图片的大小和方向。thumbor 就是这样一种图片服务器。

3、prose

Go 语言写的自然语言处理工具,目前只能处理英语。

4、Nand Game

一个网页游戏,玩家通过组合虚拟电路,组装出一台计算机。

5、Video Hub

一个管理本地视频的免费桌面软件,可以预览、搜索、分类各类视频文件。

6、Vialer-js

一个基于 WebRTC 技术的实时通讯平台,可以实现 P2P 的文字聊天、语音和视频对话。

7、Neutralinojs

一个使用系统原生组件开发桌面应用的框架,相比 Electron,好处就是打包出来的体积比较小。

8、μPad

一个开源的多端笔记本工具,兼容 Evernote。

9、Browsh

Browsh 是一个基于 Firefox 的命令行脚本,可以在命令行打开网页,并且渲染出大致的样子。它也可以用作移动端网页浏览的处理方案。

资源

1、汇编语言初学者教程(PDF)

开源电子书,从零开始介绍汇编语言,读者必须懂一点 C 语言。内容很全,也非常厚。

2、Bloomberg 机器学习课程

这个培训课程帮助学员深入理解机器学习的概念,技术和数学框架。一共30个讲座,包括一整套课后作业。

3、XV6

麻省理工学院开发的一个类似 Unix 的教学操作系统。

4、Acceptance Test Driven Development with React

中国开发者写的英语专著,介绍前端测试。书放在 Leanpub,付不付费、付多少钱都是自愿的。

5、网站可靠性工作手册

《网站可靠性工作手册》一书现在免费下载,谷歌官网提供,为期一个月。

文摘

1、郭台铭的创业

郭台铭创业初期,好不容易有了进一步投资的钱,当时有两个选择:一是买地自己盖厂房,然后买人家的模具;二是租别人的厂房,自己买机床开发模具,加强研发能力。

他选择了后者。结果几年后,地价一口气涨了10倍,房东大幅上涨房租,而模具还没开发出来,还在摸索中,因此苦不堪言,经济很窘迫。但是,郭台铭后来说,幸好选择了后者,因为房价到一定程度就不再快速上涨了,靠房地产只能赚一次的钱,但是一旦掌握了核心技术,可以赚无数次钱。

2、达芬奇的求职信

1483年,31岁的达芬奇离开故乡,来到米兰。他没钱,需要找工作,就给米兰公爵写了一封求职信。

这封信写得极好,公爵一看就认定达芬奇是一个人才,从而给他资助。即使在今天,这样的信依然能帮你找到工作。

尊敬的,显贵的公爵阁下:

我是来自佛罗伦萨的作战机械发明者达·芬奇,希望可以成为阁下您的军事工程师,同时求见阁下,以便面陈机密:

一、我能建造坚固、轻便又耐用的桥梁,可用来野外行军。这种桥梁的装卸非常方便。我也能破坏敌军的桥梁。

二、我能制造出围攻城池的云梯和其他类似设备。

三、我能制造一种易于搬运的大炮,可用来投射小石块,犹如下冰雹一般,可以给敌军造成重大损失和混乱。

四、我能制造出装有大炮的铁甲车,可用来冲破敌军密集的队伍,为我军的进攻开辟道路。

五、我能设计出各种地道,无论是直的还是弯的,必要时还可以设计出在河流下面挖地道的方法。

六、倘若您要在海上作战,我能设计出多种适宜进攻的兵船,这些兵船的防护力很好,能够抵御敌军的炮火攻击。......

九、如果战斗发生在海上,我打算建造能够抵抗最猛烈炮火和烟尘的船只。

十、和平时期,我相信在建筑上,以及从一地到另一地的引水工程上,我一样可以像其他人那样令您完全满意。......

此外,我还擅长建造其他民用设施,同时擅长绘画和雕塑。

如果有人认为上述任何一项我办不到的话,我愿在您的花园,或您指定的其他任何地点进行试验。

谨此无限谦恭之忱,向阁下问安!

列奥纳多·迪·皮耶罗·达·芬奇

3、澳大利亚的巨响蚁

1931年,西澳大利亚州的阿里德角半岛,一些自然爱好者在灌木丛生的荒原上,发现了一种没人见过的昆虫。

它看上去隐约有点蚂蚁的模样,可却是一种不寻常的淡黄色,还有一双奇怪的眼睛,很惹眼,显得异常局促不安。人们收集了一些标本,送到墨尔本维多利亚国家博物馆某位专家的桌上,专家立马就认定这种昆虫是巨响蚁。这一发现使人们极为兴奋,因为据人类所知,类似的东西不存于地球已经1亿年之久了。巨响蚁是一种原始蚂蚁,是蚂蚁自黄蜂开始的进化过程中某一时段的活化石。在昆虫学领域,这非凡卓越得就仿佛有人发现一群三角龙在某个遥远的草原上啃草一样。

考察队立刻组织起来,可是,虽然进行了最为一丝不苟的搜寻,但没人找得到阿里德角蚁群。之后的寻找也同样空手而回。

差不多过了半个世纪,当传闻一队美国科学家正计划寻找这种蚂蚁,而且几乎肯定会带上那种让澳大利亚人显得业余且组织不力的高科技精巧装置的时候,堪培拉的官方科学家们决定先发制人,为找到这种蚂蚁的活体做最后一次努力。于是,他们组织了一队人马出发横穿整个国家。

野外的第二天,正开车经过南澳大利亚州荒漠的时候,一辆车冒烟了,开起来啪啪啪地乱响,他们被迫打破日程,在公路上的一处偏僻驿站普彻拉停留一晚。晚间,科学家鲍勃·泰勒踱步出来透透气,无所事事之间把玩着手电筒,光柱扫向周围的地面。你可以想象出他的惊诧莫名啦,他发现,在他们营地附近一棵桉树树干上爬过的那队人丁兴旺的蚁群不是巨响蚁又是什么。

现在,我们来考虑一下可能性的问题。泰勒和他的同事距他们预定搜寻地有800英里之遥。在澳大利亚约摸3百万平方英里的旷野中,一小撮能够识别地球上最稀有、最吃香的虫子的人中的一个找到了这种虫子----它的活体只被人看见过一趟,还是差不多半个世纪之前----而这统统是因为他们的车子在此处抛锚了。其附带结果便是,巨响蚁至今仍旧没有在其原发现地被找到。

本周图片

1、平铺平面的五边形

有一个数学难题,怎样的多边形可以铺满一个平面?数学家已经证明,任意三角形和四边形都可以,五边形不确定,六边形只有三种可以,其他都不行。

上图是目前找到的所有15种五边形,可以平铺平面。

其中的第15种五边形,2015年发现的。

2、最热门的编程语言

根据谷歌搜索指数,Python 语言过去10年一直在上升,现在已经是最热门的编程语言。(图片来源《经济学家》杂志)

3、圣赫勒拿岛游记(组图)

圣赫勒拿岛最著名的景点,当然是拿破仑故居和空的拿破仑墓。1815年,拿破仑被流放到这里,1821年去世安葬在岛上的墓地。1840年法国政府将灵柩移回巴黎,买下岛上三块拿破仑有关土地,并入法国领土,成为"在英国海外领地上的法国海外领土"。

拿破仑故居门口立着牌子,禁止拍照,不过没有监控,靠自觉。我是2018年这个别墅的第一个参观游客,在别墅里忍不住,拍了一些内部照片。里面的所有家具和设施完全是原物原样,没有任何变化,让你觉得好像拿破仑昨天才在这里去世。

往山下开一段路,就是另一块法国领土,拿破仑墓。当然,是空的,灵柩已经移回巴黎。这块墓地占的区域很大,由松木屑铺成防滑的山路一直走下去。没人看管,任何时候都可以来。

我住的旅馆,由英国遗民Hazel老太太经营。其中一部分是2008年从所罗门家族买来的,包括书房,大部分都保持原样几百年。临走前一天,Hazel告诉我,她接到一个叫信天翁的旅游agent订单,有11个北京来的中国团第二天到。然后她有点担心地问我,他们会不会在房间 cooking?

以前有一个中国人住的时候,在房间煮面方便面,弄得房间都是味道。我想了一下,觉得非常有可能。于是我帮她写了5页纸的中文 tips,希望他们不要在房间煮面,另外也尽可能告知了一些岛上的吃喝玩乐地方,不晓得最后这11位中国同胞看到没有。

本周金句

1、

圆明园的兽头,原本是喷水池的水龙头。它们不太可能是八国联军抢走的,因为圆明园珍宝如山,八国联军会抢这种仿制西方的喷头吗?它们十有八九是圆明园废弃后,中国人自己弄下来卖掉的。(张鸣

2、

你存心做一个与世无争的老实人吧,人家就利用你欺侮你。你稍有才德品貌,人家就嫉妒你排挤你。 你大度退让,人家就侵犯你损害你。你要不与人争,就得与世无求,同时还要维持实力准备斗争。你要和别人和平共处,就先得和他们周旋,还得准备随时吃亏。 (杨绛

3、

摩尔定理有一个后果,每隔几年,我们就要学习一个新的希腊语前缀:mega-、giga-、tera-、peta-、exa-、......(推特@UnitFact

欢迎订阅

这个专栏每周五发布,同步更新在我的个人网站微信公众号语雀

微信搜索"阮一峰的网络日志 "或者扫描二维码,即可订阅。

image | left

(完)

文档信息

]]>
0
<![CDATA[方法论]]> http://www.udpwork.com/item/16990.html http://www.udpwork.com/item/16990.html#reviews Fri, 03 Aug 2018 03:49:24 +0800 Felix021 http://www.udpwork.com/item/16990.html 1. 意志力

    有些人似乎天生就有很强的意志力,可以长时间连续做某件事情而不知疲倦,例如学霸可以长时间做题,计算机大神可以长时间编写代码(看看那些 Hackathon 比赛)。但我认为这里有一些事实被掩盖了——你回顾一下,是不是也有一些自己可以长时间做而不会疲倦的事情,例如王者荣耀、吃鸡,又或者刷各种美剧?你也许会觉得,这不一样啊,玩游戏和刷剧是这种有意思的事情,并不需要意志力的支撑。问题就在这里——可能很多人无法理解的是,学霸们和计算机大神们可以从做题、写码中获得快乐,所以才会觉得是强大的意志力在支撑着他们。

    在能得到快乐的事情上,持续的投入不需要强大意志力的支撑。反过来说,在不是特别感兴趣甚至令人反感的事情上,意志力就非常重要。不巧的是,意志力是一种有限的资源,合理、有效地利用这个资源,我认为是取得成绩的一个关键因素。

    那该怎么办呢?鸡汤地说,就是想办法让自己喜欢上要做的事情,如果做不到,至少也应该减少排斥感。当然,给汤不给勺是耍流氓,所以请继续往下看。

2. 反馈(奖励)

    很多人都对嗑瓜子这种带有魔性的娱乐活动深有体会,拿着一袋瓜子,不嗑完根本停不下来。如果不巧你不喜欢嗑瓜子,可以想想那些让你觉得非常爽的游戏,无论具体的游戏形式如何呈现,都会有一个共性,就是总会给你立即的回馈。游戏总会给完成挑战的玩家一些奖励,激励他们继续玩下去。好玩的游戏尤其在意回馈的呈现形式,比如施放一个技能产生的光影声音特效、对手被攻击掉血的数值化呈现,杀死一个对手后增加经验值、掉下来的装备,完成一个剧情任务以后的礼包奖励等等,都希望够给玩家创造充分的满足感,引导玩家继续完成下一个目标。

    人类本质上还是一种动物,大脑中对反馈的本能反应,相当于给游戏的设计者开了一个后门,用于操纵玩家的行为。利用好这个特点,即使在本来并不十分感兴趣的领域,也能够显著改善对意志力的消耗。举例而言,我总是会边写边运行我的代码,一方面可以确认写好的代码没有错误(避免把一大堆问题积攒到最后),另一方面运行结果本身是一个有效的反馈(每次运行结果都更完整、更接近目标),激励我继续改进;而且在学习数据结构时(例如一个二叉树),我总会写一个 dump 方法,用来把内存中抽象的数据可视化。

3. 目标

    游戏设计的“心流(flow)”理论给出的几个关键因素中,我认为反馈是最重要的,其次是目标。好的游戏总会设定合理的目标,引导玩家一步一步入坑。太简单的目标会让人觉得无聊,太难的目标则很容易让人因畏难而放弃。就像下棋/打球,和新手、或水平远高于自己的选手对战,都不是一件愉快的事情,而让人既觉得愉快又能提高自己水平的,正是与水平相当(或者略高)的人对战,获胜的可能性(不确定性)和对获胜的追求,会带来双方激烈的对抗,而这些对抗能给参与者淋漓酣畅的快意(反馈),从而形成有效的正反馈循环。

    同样地,在学习过程中,给自己设定合理的目标能够有效降低对意志力的消耗。如何设置合理的目标,可能没有通用的方法,但幸运的是,可以在实践中调整,找到最适合自己的阈值。

4. 启动成本

    俗话说万事开头难,如果能想办法减少开头的困难,那万事就不那么难了。所谓的困难,换种说法就是成本高。这里的成本是广义的,不仅仅包含金钱成本,也包含时间成本,以及其他为了达成目标所要付出的代价。而这里的目标还只是开始做某件事情,如果启动成本过高,在开始之前就会消耗大量意志力,那么结果便可想而知。

    一个典型的例子是健身。我曾经的一份工作,公司隔壁是一个专业大型健身房,提供浴巾、拖鞋等各种洗浴用品,公司发放免费的年卡,于是我每周都会有2~3次午休或下班时间“说走就走”地去健身,甚至还请了教练来辅导我,过程虽然有些辛苦,但回想起来确实很享受那段时光。换工作以后,我也曾经办过一次季度健身卡,但是启动成本陡增:我需要自掏腰包来办理健身卡,而且这家健身房离我有十几分钟脚程、不提供浴巾和拖鞋等,每次去健身房之前心里都一番挣扎,结果是,虽然我坚持了一周2次的频率,但季度卡到期后就没再续费。我做了另一个决定:在家里腾出一小块地方,买了一架椭圆机,只要有15分钟空隙就可以完成一次轻松的健身。如果我愿意,还可以开启刷剧模式,很愉快地在椭圆机上磨蹭大半个小时。

    降低启动成本,其本质就是想办法制定一个较容易达成的初始目标(启动)。硅谷创业家 Eric Rise 所著《精益创业》(Lean Startup)的核心思想“最小化可行产品”(Minimum Viable Product, MVP),我认为也是最小化启动成本的一个应用,通过最小代价开发出一个可用的产品(达成目标:启动),推向市场,验证其可行性(反馈),根据市场反馈持续不断地迭代改进(阶段性目标),形成正反馈循环。

通过降低启动成本,设置适合自己的目标,建立能够带来奖赏的反馈机制,形成正反馈的循环,从而最大化地利用好意志力资源,这就是我的方法论。

如果不够的话,还有一个开挂的技巧——研究表明,吃糖可以在一定程度上补充意志力。也对,要是在健身减肥的过程中可以吃甜品,应该就没那么难坚持下来了吧?

]]>
1. 意志力

    有些人似乎天生就有很强的意志力,可以长时间连续做某件事情而不知疲倦,例如学霸可以长时间做题,计算机大神可以长时间编写代码(看看那些 Hackathon 比赛)。但我认为这里有一些事实被掩盖了——你回顾一下,是不是也有一些自己可以长时间做而不会疲倦的事情,例如王者荣耀、吃鸡,又或者刷各种美剧?你也许会觉得,这不一样啊,玩游戏和刷剧是这种有意思的事情,并不需要意志力的支撑。问题就在这里——可能很多人无法理解的是,学霸们和计算机大神们可以从做题、写码中获得快乐,所以才会觉得是强大的意志力在支撑着他们。

    在能得到快乐的事情上,持续的投入不需要强大意志力的支撑。反过来说,在不是特别感兴趣甚至令人反感的事情上,意志力就非常重要。不巧的是,意志力是一种有限的资源,合理、有效地利用这个资源,我认为是取得成绩的一个关键因素。

    那该怎么办呢?鸡汤地说,就是想办法让自己喜欢上要做的事情,如果做不到,至少也应该减少排斥感。当然,给汤不给勺是耍流氓,所以请继续往下看。

2. 反馈(奖励)

    很多人都对嗑瓜子这种带有魔性的娱乐活动深有体会,拿着一袋瓜子,不嗑完根本停不下来。如果不巧你不喜欢嗑瓜子,可以想想那些让你觉得非常爽的游戏,无论具体的游戏形式如何呈现,都会有一个共性,就是总会给你立即的回馈。游戏总会给完成挑战的玩家一些奖励,激励他们继续玩下去。好玩的游戏尤其在意回馈的呈现形式,比如施放一个技能产生的光影声音特效、对手被攻击掉血的数值化呈现,杀死一个对手后增加经验值、掉下来的装备,完成一个剧情任务以后的礼包奖励等等,都希望够给玩家创造充分的满足感,引导玩家继续完成下一个目标。

    人类本质上还是一种动物,大脑中对反馈的本能反应,相当于给游戏的设计者开了一个后门,用于操纵玩家的行为。利用好这个特点,即使在本来并不十分感兴趣的领域,也能够显著改善对意志力的消耗。举例而言,我总是会边写边运行我的代码,一方面可以确认写好的代码没有错误(避免把一大堆问题积攒到最后),另一方面运行结果本身是一个有效的反馈(每次运行结果都更完整、更接近目标),激励我继续改进;而且在学习数据结构时(例如一个二叉树),我总会写一个 dump 方法,用来把内存中抽象的数据可视化。

3. 目标

    游戏设计的“心流(flow)”理论给出的几个关键因素中,我认为反馈是最重要的,其次是目标。好的游戏总会设定合理的目标,引导玩家一步一步入坑。太简单的目标会让人觉得无聊,太难的目标则很容易让人因畏难而放弃。就像下棋/打球,和新手、或水平远高于自己的选手对战,都不是一件愉快的事情,而让人既觉得愉快又能提高自己水平的,正是与水平相当(或者略高)的人对战,获胜的可能性(不确定性)和对获胜的追求,会带来双方激烈的对抗,而这些对抗能给参与者淋漓酣畅的快意(反馈),从而形成有效的正反馈循环。

    同样地,在学习过程中,给自己设定合理的目标能够有效降低对意志力的消耗。如何设置合理的目标,可能没有通用的方法,但幸运的是,可以在实践中调整,找到最适合自己的阈值。

4. 启动成本

    俗话说万事开头难,如果能想办法减少开头的困难,那万事就不那么难了。所谓的困难,换种说法就是成本高。这里的成本是广义的,不仅仅包含金钱成本,也包含时间成本,以及其他为了达成目标所要付出的代价。而这里的目标还只是开始做某件事情,如果启动成本过高,在开始之前就会消耗大量意志力,那么结果便可想而知。

    一个典型的例子是健身。我曾经的一份工作,公司隔壁是一个专业大型健身房,提供浴巾、拖鞋等各种洗浴用品,公司发放免费的年卡,于是我每周都会有2~3次午休或下班时间“说走就走”地去健身,甚至还请了教练来辅导我,过程虽然有些辛苦,但回想起来确实很享受那段时光。换工作以后,我也曾经办过一次季度健身卡,但是启动成本陡增:我需要自掏腰包来办理健身卡,而且这家健身房离我有十几分钟脚程、不提供浴巾和拖鞋等,每次去健身房之前心里都一番挣扎,结果是,虽然我坚持了一周2次的频率,但季度卡到期后就没再续费。我做了另一个决定:在家里腾出一小块地方,买了一架椭圆机,只要有15分钟空隙就可以完成一次轻松的健身。如果我愿意,还可以开启刷剧模式,很愉快地在椭圆机上磨蹭大半个小时。

    降低启动成本,其本质就是想办法制定一个较容易达成的初始目标(启动)。硅谷创业家 Eric Rise 所著《精益创业》(Lean Startup)的核心思想“最小化可行产品”(Minimum Viable Product, MVP),我认为也是最小化启动成本的一个应用,通过最小代价开发出一个可用的产品(达成目标:启动),推向市场,验证其可行性(反馈),根据市场反馈持续不断地迭代改进(阶段性目标),形成正反馈循环。

通过降低启动成本,设置适合自己的目标,建立能够带来奖赏的反馈机制,形成正反馈的循环,从而最大化地利用好意志力资源,这就是我的方法论。

如果不够的话,还有一个开挂的技巧——研究表明,吃糖可以在一定程度上补充意志力。也对,要是在健身减肥的过程中可以吃甜品,应该就没那么难坚持下来了吧?

]]>
0
<![CDATA[画个老虎]]> http://www.udpwork.com/item/16989.html http://www.udpwork.com/item/16989.html#reviews Thu, 02 Aug 2018 15:23:51 +0800 qyjohn http://www.udpwork.com/item/16989.html bunny01bunny02

 

入佛界易,入魔界难。

]]>
bunny01bunny02

 

入佛界易,入魔界难。

]]>
0