taocoding


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

MacBooPro升级固态-实战

发表于 2020-04-04

准备工作

  • 时间机器备份

    使用“时间机器”备份您的 Mac,按照官方指导一步一步来就可以了。这里要特别强调一点,在备份的时候务必确认一下这里:备份排除项目 第一次备份的时候没注意,导致没有按需备份所需资料,后面重新备份恢复浪费大把时间。

  • U盘启动盘

    如何创建可引导的 macOS 安装器

  • 转接卡

    上篇文章提过,mac的硬盘接口不是标准的m.2,必须得弄一个转接卡,这个万能的宝上有比较多,关键字:“m.2 转 苹果”,价格15~30之间,我选择了一个开了10年的店铺,但是非要两个包邮,想着也不算太贵,就直接拍了,在这个特殊情况下竟然只花了1天半时间就到手了,竟然比正常时候都快。之前看网上的文章,有说这个卡看运气,运气不好长了或者短了或者兼容性不好,那就尴尬了,我这次还算运气好,大小很合适,兼容性也没问题。
    转接卡非常小巧

  • 螺丝刀

    mac背面的几个螺丝非常小,需要特殊的螺丝刀,这个我在某东上买的,比较亏,建议在某宝上买,10块钱应该可以搞定。除了后背螺丝外,拆解硬盘的时候还需要一个不一样的螺丝刀,如下图:
    螺丝刀其中1.2上用于拆后盖螺丝,t5拆解硬盘。

  • 新固态硬盘

    由于最近疫情原因,ssd涨价非常多,一直在intel760p和三星970evo中纠结,本着这两个都是网友们推荐的兼容性较好的,而且我的本本也都不跑满这些新硬件的性能,选择的依据就是性价比了。在我出手时这两个一直都是100的差价,当转接卡到手后准备下手760的时候,不知道店家干啥的突然涨价100,估计是被大数据杀熟了(我添加了这几款ssd在购物车了),刚好三星那边又搞活动降价了一点点,这么一看那970毫不犹豫了,毕竟原装的也是三星的,性能相对也更好。
    螺丝刀

拆机

关闭电源!!!

  • 拆后背螺丝

    这个比较简单,拿1.2螺丝刀挨个弄下里就行了,唯一需要注意的是键盘部位中间的两个螺丝跟其他螺丝相比稍短,不然找起来比较麻烦。

  • 拔下电池,这个非常重要!!!
    电池插口位置
    电池插口拔下来

硬盘更换

这个步骤需要用到t5螺丝刀

  • 拆下原装硬盘螺丝
  • 拔下硬盘
  • 插上转接卡
  • 插上新硬盘
  • 撞上螺丝

硬盘换上之后,记得把电池插口还原,此时可以把后盖盖上,但是先不要上螺丝,以免遇到各种不兼容问题导致电脑无法点亮。

新硬盘系统安装

插上u盘启动盘,打开电源开关,此时会进到macos的恢复模式,首选需要进行新硬盘的格式化。
关于硬盘格式的选择网上大部分都是建议选择Mac OS 扩展(日志式)+ GUID分区,其实官方也有相应的文档说明:在 APFS 和 Mac OS 扩展格式之间进行选择。我直接用的APFS格式,后面也没遇到啥问题,格式化之后,又回回到使用工具界面:
这次选择重新安装macos,按照提示来就好了。

恢复原硬盘备份

上面的系统安装完成后,会进行一系列的设置等操作,后面会进到迁移助理界面,这个就需要用到前面提到的时间机器备份了,官方也有很详细的描述。
从备份恢复 Mac。我第一次恢复之后,进入系统发现很多应用没有了,部分目录也不见了,当时觉得很奇怪,难道是时间机器有bug么?期间打了一次苹果的技术支持电话,详细说明了情况,可惜那个顾问也没能给到有效解释,只是让我再备份一次。

我只好再把硬盘来回倒腾了一番,装上了原来的,再次进入时间机器,我猛然看到一个前面第一幅图,然来是有些备份被排除了,很奇怪的是官方的文档也没强调这一点。再次按需备份之后,进入新硬盘系统,时间机器里面也能看到最新的一次备份,但是就是没法进行恢复(按钮颜色都不一样)。

但是因为有时间机器,我打算干脆重新装一次再恢复得了,进入恢复模式的实用工具之后,点击从TimeMachine恢复,里面就可以看到最新的备份,而且也提示会直接把系统也一起抹掉恢复,最后总算是顺利完成。

最后来两张性能对比:


读性能基本上没啥区别,写提高近三倍,跟官方标榜的读2300 MB/s 和 写3400 MB/s差距还不小,当然这个主要是2015款mbp的物理接口限制了。

总结

mac换硬盘这个事情,其实从预谋到实施也就两周,期间主要是新硬盘选择和准备工具花了不少时间。真正换硬盘的时间反而是最微不足道的,备份数据和恢复数据花了95%的时间,最终新的硬盘果然也是没法最大程度释放硬件能力,不过我的初衷是扩大容量,这么来看也算符合预期了。

Envoy初试

发表于 2019-10-29 | 分类于 microservice , service-mesh

这两天抽空试玩了一下envoy:

编译安装

习惯于编译代码然后debug,而最新的代码依赖实在过于庞大,因此选择了envoy的第一个开源版本
稍微修改了一下自带的ci脚本,将对应的第三方依赖手动下载之后,目前基本上可以做到二键编译(在我的Ubuntu 16.04.3 LTS虚拟机上编译通过)。

配置说明

envoy初期版本的配置是json格式的,现在的版本已经改成了yaml了,尽管是1.0.0版本,envoy配置还是显得非常丰富,主要包括以下几大类:

  • listeners:监听器,也就是对外供downstream链接的配置
  • admin:管理端口
  • cluster_manager:upstream的集群配置,提供诸如服务发现,负载均衡,健康检查等特性
  • flags_path:基于文件的配置指令
  • statsd_local_udp_port:上报统计数据的statsd服务对应的udp端口
  • statsd_tcp_cluster_name:上报统计数据的statsd服务对应的tcp服务集群名
  • tracing:调用链数据上报配置
  • rate_limit_service:外部依赖的全局限流服务
  • runtime:运行时动态配置,可以做到热加载

其中前三类为必选的,其中每类里面又分为各个小类别,看下文这个例子就很清楚了。

一个基于mongodb的代理例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
"listeners": [
{
"port": 10086,
"filters": [
{
"type": "both",
"name": "mongo_proxy",
"config": {
"stat_prefix": "mongo_stat",
"access_log": "mongo_access"
}
},
{
"type": "read",
"name": "tcp_proxy",
"config": {
"cluster": "mongo-db",
"stat_prefix": "tcp_proxy"
}
}
]
}
],
"admin": {
"access_log_path": "/dev/null",
"port": 8001
},
"cluster_manager": {
"clusters": [
{
"name": "mongo-db",
"connect_timeout_ms": 250,
"type": "static",
"lb_type": "round_robin",
"hosts": [
{
"url": "tcp://10.0.0.6:27017"
}
]
}
]
}
}

这里需要注意的是listeners里面可以有多个filters,组成一个类似职责链的模式。
官网文档有一段描述:

Since Envoy is fundamentally written as a L3/L4 server, basic L3/L4 proxy is easily implemented. The TCP proxy filter performs basic 1:1 network connection proxy between downstream clients and upstream clusters. It can be used by itself as an stunnel replacement, or in conjunction with other filters such as the MongoDB filter or the rate limit filter.

envoy对于L3/4层有一个基础的实现,像示例中的mongo_proxy其实只是做了各类统计工作,一般都需要额外配置一个tcp_proxy来做流量转发。

那些年见识过的微服务思想

发表于 2019-09-10 | 分类于 microservice

Martin大叔那篇著名的微服务文章出来后,”微服务”这个词逐渐进入大众视野,然后一系列关于微服务的框架,治理手段层出不穷,如spring cloud全家桶。

经过这一年多对服务框架和调用链的实践,多多少少有些体会,每次在套用这些名词的时候总会有一种似曾相识的感觉,静下心来想想其实在鹅厂的时候已经接触不过不少相关的套路,那会大叔的文章并没有出来,也没有人把他给总结的这么高大上,这里先堆一些名词,等日后慢慢丰富。

大系统小做

将功能复杂较大的系统,化大为小,减少模块耦合,降低相关联性,用多个独立的进程相互协作来实现整体的复杂系统功能,比如把读和写的功能分成不同的进程实现。

  • 微服务思想的精髓

tbus,spp

前者是IEG当时游戏服务器的标配框架,后者是SNG业务服务的标配框架。
两者都共同点是业务进程通过网络或者共享内存与本机的一个代理进程进行通信,该代理进程负责与外部其他节点> 通信,从而对业务屏蔽了网络通信的逻辑,想想这不就是现在service-mesh中的sidecar么。

  • service mesh

QZA

由于qzone平台层的模块众多,中间层的业务对接起来不可能都自己去实现一套协议转换,鉴权,频率控制等逻辑,于是qza(qzone access)应运而生

  • API网关

CLog

当时这个系统印象比较深刻的用途就是给老板(GM)这类人专门定位问题的,比较模块太多了,一个一个log查起来不现实,只能把log集中存储,按照uin,seq等维度来聚合。

  • 染色,调用链

L5

这是个神器,当时SNG基本上所有的业务机器上面都有一个L5-Agent,干啥呢,就是帮你做服务发现,你每次调用下游服务的时候,都会通过api从其共享内存中拿一个IP:PORT,拿的过程就做了负载均衡了,只不过调用者感受不到,调用完下游服务之后,你会上报这次调用的结果(返回码,耗时等),基于这些上报,当某个下游服务出故障了,他会自动帮你摘除掉该节点,这不就是熔断么。

  • 服务发现
  • 负载均衡
  • 熔断

柔性可用

“结合用户使用场景,根据资源消耗,调整产品策略,设计几个级别的、不同的用户体验,最大限度的保证关键服务的可用性。” 这跟降级的思路基本一致。

  • 降级

稳定的重要性

发表于 2019-06-30 | 分类于 思考

本文摘抄自微信公众号:插坐学院

虽说是鸡汤文,但是将其对照到工作和生活中确实有那么一些似曾相识,不管是技术上常常提到的系统稳定性,还是与人相处过程中的情绪和内心稳定性。


情绪稳定:是成年人最稀缺的能力

在《危险人格识别》一书中,情绪不稳定被视为危险人格。情绪不稳定的人往往缺乏控制情绪的能力,一点点刺激就能让情绪成为他的主人。这就导致他们性情多变,且极端跳跃。

人们都是追求安稳平静的,没有人喜欢在惊吓中度日。过度的愤怒与抱怨,只会让朋友、机会越来越远。周而复始形成恶性循环,工作生活都可能受到影响,伤害的是自己。

情绪不稳定的人,往往还会选择向亲人发火。当争吵成为家庭生活的常态,坏情绪传染太多,不论是亲情还是爱情都会在反复无常的“变脸”中消磨殆尽。

其实,不管遇到了多大的困难和痛楚,总有人能做到向死而生,生活永远不会崩溃,会崩溃的只有我们那经不起考验的情绪。

观察生活我们能发现,那些真正优秀的人,那些会让你打心眼里产生依赖感、信任感、安全感、亲近感的人,往往都是情绪很稳定的人。

他们遇到突发情况镇定自若,不会大惊失色、六神无主;
遇到困难,执着坚定,不会轻易怀疑后退;
遇到愤怒的事谋定后动、尽力周旋,不会一冲动就不计后果。


能力稳定:决定了一个人能走多远

“通盘无妙手”是一个下棋的术语,是说很会下棋的人,往往一整盘棋你是看不到那种神奇的一招,或者力挽狂澜的一手的。

这有点违反我们的直觉,为什么是这样呢?

韩国有一位围棋选手叫李昌镐,是围棋界的世界级顶尖高手。他下棋最大的特点,也是最让对手头疼的手法,就是每手棋,只求51%的胜率,俗称“半目胜”。

他曾对记者说:“我从不追求妙手,也没想过要一举击溃对手。”只要每一步比对手好一点点,就足够赢了。

这恰恰是高手的战略。所谓的“妙手”,虽然看起来很酷,赢得很漂亮,但存在一个问题——给对方致命一击的同时,往往也会暴露自己的缺陷,正所谓“大胜之后,必有大败;大明之后,必有大暗”。

而且,“妙手”存在不稳定和不可持续性,无法通过刻意练习来形成技能上的积累,一旦“灵感”枯竭,难免手足无措。正如守卫一座城池,只靠“奇兵”是不行的,终归要有深沟、高垒的防护。

而与之相比,“通盘无妙手”看似平淡无奇,但是积胜势于点滴、化危机于无形,最终取得胜利是稳稳当当的。

真正的高手,都懂得能力稳定的重要性,他们稳定地“输入”,稳定地“输出”。

每天提高一点点,再前进一点点,到一定时候回头看,你会发现,自己已经走出了很远的距离。


内心稳定:是一个人幸福的根本本源

每个人的内心,都有一种深层的不安存在着。心灵内部的那种无助感,那种随波逐流,那种对前程的不确定感……常常令我们力不从心。

所谓内心稳定,首先是内心对未来的笃定,不急躁,不盲目。只要方向正确,步子稳定,何时抵达只是时间问题罢了。

其次是对生活稳定的把握。明白什么是可以改变的,比如如何看待自己,看待世界,然后尽自己所能去改变它;明白什么是自己无力改变的,然后放手,看淡。

人生一世,草木一秋,即使是物欲横流,也要坚守,唯有静心笃定,方能不乱一心,安然面对。

jaeger实战

发表于 2019-04-11 | 分类于 microservice

做tracing选型时发现除了Zipkin(这个其实很久之前就有所闻,但是一直没实操过),还有Uber开源的Jaeger,看到官网就感觉这是一个用心的产品,这个应该离不开Uber有专门的团队维护。

特性

官网列了几个特性:

  • Opentracing兼容,提供了Go, Java, Node, Python, C++的官方客户端
  • 服务之间使用一致的采样逻辑
  • 多存储支持:Cassandra, Elasticsearch, Kafka, memory
  • 动态采样(吐槽一下这个,一年多了,还没合入开源版本)
  • 支持收集的数据做后续分析
  • 现代化的UI
  • 云原生支持
  • 可视化(每个组建都支持将metric导出到Prometheus)
  • 兼容Zipkin

由于调研的时候没法对细节做深入了解,当时选择Jaeger最重要的一点其实是其实是:jaeger-agent是一个通过UDP方式接收本机发出的spans。
为什么是这一点呢?因为对于业务来说tracing其实是一个相对无关紧要的东西,如果给一个TCP的通道让它上报,其实是不太友好的,性能和维护性方面都没有UDP好。

架构

Jaeger架构图

  • jaeger-client:嵌入在应用程序里面,负责span的创建以及上报
  • jaeger-agent:每个物理机部署一个,负责收集client上报的span,然后转发给collector
  • jaeger-collector:接收agent发来的span,写入后端存储
  • jaeger-query:提供rest接口,负责从存储中拉取trace信息供UI查询
  • jaeger-ui:展示trace和服务依赖图

实战

如果想快速体验,可以按照官网的Docker方式部署,由于当时的线上环境还没有这方面的支持,下面以最新的Release二进制版本简述一下部署的流程。

准备工作
  • Jaeger安装包:
    https://github.com/jaegertracing/jaeger/releases/download/v1.11.0/jaeger-1.11.0-darwin-amd64.tar.gz
  • elasticsearch-6.4.0:
    https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.4.0.tar.gz
启动
  1. bin/elasticsearch
  2. SPAN_STORAGE_TYPE=elasticsearch ./jaeger-collector
  3. ./jaeger-agent –collector.host-port 127.0.0.1:14267
  4. SPAN_STORAGE_TYPE=elasticsearch ./jaeger-query

打开http://127.0.0.1:16686即可看到Jaeger的查询页面:

  • Search,按照 服务:操作,tag,时间等维度进行trace的筛选
  • Compare,比较两个trace
  • Dependencies,查看服务依赖图,这个需要一个单独的Spark任务才能生成,下文会讲到
例子

Jaeger的安装包里面自带了一个测试程序:example-hotrod,模拟Uber的打车服务,通过如下方式启动:

jaeger-1.11.0-darwin-amd64 billowqiu$ ./example-hotrod all

这样会一次性启动所有的服务,包括:Customer service,Driver service,Route service,Frontend service,同时内部还会模拟调用MySQL和Redis。
启动该服务后,打开http://127.0.0.1:8080/ 随便点一个乘客姓名,这时在Jaeger的ui里面可以看到如下trace:

点进去可以看到详细的trace:

Dependencies生成

上面通过例子程序可以看到6个服务的调用流程及耗时等trace数据,但是http://127.0.0.1:16686/dependencies 里面依然是空的,这是因为服务依赖图需要单独的任务生成:
jaegertracing/spark-dependencies, 当时为了解决一个生产环境的问题,还为这个项目提了个pr,最后官方合入了master,也算是一个小惊喜吧。
代码clone下来之后执行:

spark-dependencies billowqiu$ mvn clean package -Dmaven.test.skip=true

这样会build一个jar包,然后执行:

spark-dependencies billowqiu$ STORAGE=elasticsearch ES_NODES=http://localhost:9200 java -jar jaeger-spark-dependencies/target/jaeger-spark-dependencies-0.0.1-SNAPSHOT.jar

在Mac下面可能会出现:Can’t assign requested address: Service ‘sparkDriver’ failed after 16 retries (starting from 0) 这个错误,可以参照这个解决。
这时再打开http://127.0.0.1:16686/dependencies 选择DAG,服务依赖如图所示:

opentracing-api-overview

发表于 2018-11-11 | 分类于 microservice

简介

opentracing是一个API规范,各类框架和库负责实现该规范,从而允许开发人员通过手动埋点实现平台无关的tracing跟踪。目前主流的语言都有对应的接口提供,具体可以参考链接。下面以opentracing-go为例对其做一个大致介绍。

Span

SpanContext

表示一个Span的状态,通常会传递给相关联的Span,也包括跨进程传递,例如<trace_id, span_id, sampled>。主要接口有:
ForeachBaggageItem(handler func(k, v string) bool),handler函数会针对每个BaggageItem进行调用。

Baggage

跟spancontext一样也是跨进程传递的,为一系列key:value对

Tag

设置用于过滤span的tags,其中key必须是string类型,value可以是任意类型,opentracing有一些预定义的tags

1
2
SetTag(key string, value interface{}) Span
span.SetTag()

Log

1
2
3
4
5
LogFields(fields ...log.Field)
// span.LogFields(
// log.String("event", "soft error"),
// log.String("type", "cache timeout"),
// log.Int("waited.millis", 1500))

Finish

1
2
3
4
5
6
7
FinishWithOptions(opts FinishOptions)
通常这是对于span的最后一个操作,目前看到的实现基本上都是在这个动作做span的上报。

type FinishOptions struct {
FinishTime time.Time // 重写span的结束时间
LogRecords []LogRecord // 可以在这个时候一次性写入所有的Log,效果同手动调用LogFields
}

一个span的列子:

t=0            operation name: db_query               t=x 

 +-----------------------------------------------------+
 | · · · · · · · · · ·    Span     · · · · · · · · · · |
 +-----------------------------------------------------+

Tags:

  • db.instance:”jdbc:mysql://127.0.0.1:3306/customers
  • db.statement: “SELECT * FROM mytable WHERE foo=’bar’;”

Logs:

  • message:”Can’t connect to mysql server on ‘127.0.0.1’(10061)”

SpanContext:

  • trace_id:”abc123”
  • span_id:”xyz789”
  • Baggage Items:
    • special_id:”vsid1738”

Tracer

负责创建Span和SpanContext的传播,属于一个Manager角色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
type SpanReference struct {
// 与ReferencedContext的关联关系,有ChildOfRef和FollowsFromRef,具体可见http://opentracing.io/spec/
Type SpanReferenceType
// 需要建立关联关系的spancontext
ReferencedContext SpanContext
}
type StartSpanOptions struct {
// 一次可以设置0到多个span之间的关联,如果不设置此字段,表明当前创建的span为root span
References []SpanReference

// StartTime overrides the Span's start time, or implicitly becomes
// time.Now() if StartTime.IsZero().
// 指定span的开始时间
StartTime time.Time

// 类似于Span的SetTag()
Tags map[string]interface{}
}

// 创建一个新的span
StartSpan(operationName string, opts ...StartSpanOption) Span

// 将sm按照format的格式序列化到carrier,通常是在client端调用
Inject(sm SpanContext, format interface{}, carrier interface{}) error
// 从carrier中按照format的格式取出sm,通常是在server端收到client调用后,取出spancontext
Extract(format interface{}, carrier interface{}) (SpanContext, error)

// opentracing有定义一些内置的BuiltinFormat:
Binary:二进制方式
TextMap:key:value 的string pairs,对应的carrier类型为map[string]string
HTTPHeaders:作为HTTP header的string pairs,对应的carrier类型为http.Header

分布式跟踪系统历史

发表于 2018-10-21 | 分类于 microservice

介绍

从五月份到现在一直都在和tracing打交道,也算对这个领域有了一定的了解,打算做点记录,第一篇就从tracing系统的历史说起。

tracing系统历史

Google在互联网领域基础设施方面的理论贡献真的是当之无愧的No.1,从早期的三驾马车,到tracing相关开源系统的鼻祖Dapper,再到近年的spanner,F1等等,几乎都是发个paper科普一下自家已经运营N年的东西,然后开源领域就各种开种”山寨”。
调用链跟踪这个话题,其实很早就有了,具体可以去翻看一下dapper的引用文献,但是最近两年因为微服务的火热,各大公司才开始真正对这个东西重视,毕竟一个接口的调用可能引起几十个甚至上百个下游服务的调用,如果没有一个跟踪系统,对于问题的定位难度可想而知。

  • Dapper论文发表于2010年,翻译版
  • Twitter在2012年开源了zipkin
  • zipkin开源后
    • 估计Twitter维护不力,而且是相对小众的scale写的,后面由开源社区用java重写了并改名为OpenZipkin继续维护维护
    • 7月份完成了2.0的数据模型切换Zipkin 2.10 completes our v2 migration
    • 8.30号捐给了Apache。
  • Jaeger的诞生
    • Uber在集成到内部系统之后各种坑出来了,具体可见Evolving Distributed Tracing at Uber Engineering,于是另起炉灶于2017年初开源了Jaeger

tracing标准

  • opentracing

    2016年就开始启动了,为了解决tracing系统各自为政,搞了个统一的标准,并提供了各种语言的api。目前的主要参与者为Uber,LightStep(Dapper第一作者的公司),Redhat(Jaeger开源后,直接放弃自家研发的类似产品,转而到Jaeger上面来了,哈)等公司。

  • opencensus

    Google年初提出的一个集metrics和tracing的新标准,估计一方面是看到Opentracing想竞争一把,就像之前的容器编排一样,另外也可以推广自己家的Stackdriver,目前微软也加入了对该标准的支持,准备搞到自己的Auze里面。

  • w3c/distributed-tracing

    2017年提出的一个为了统一各种tracer系统中Context格式标准,目前还是Draft阶段,主要参与者为Google和微软。

tracer实现

上面提到了三个tracing标准,w3c的就不说了,opencensus由于是谷歌主导的,参与者不多,相应的tracer实现也只有自家的Stackdriver。
opentracing实现则是遍地开花:

  • Jaeger
  • Appdash
  • LightStep
  • Instana
  • SkyWalking
  • inspectIT
  • stagemonitor
  • Datadog

其中大部分都是商业产品,顺带支持一下opentracing,而且都是属于APM级别的,Zipkin竟然不在名列!!!
开源方面的,Jaeger和Appdash都是go语言开发的,部署起来相对比较轻便;而且Jaeger背后有Uber支持,提供了个各种语言的API,这个也是当时技术选型时选择的一个点,同时其基于UDP方式的Agent数据采集也比较符合个人的胃口。

总结

随着微服务的流行,传统的单体应用监控已经不能满足大规模分布式服务之间的问题定位,分布式跟踪刚好能解决这个问题,而Opentracing的出现统一了各个Tracer系统的接入标准,让开发者在选择的时候不用绑定在某一个厂商。由于tracing和monitoring在实现和用途上有一定的重叠,集tracing和monitoring的APM应该是该领域的一个趋势,这也是opencensus的一大优势。

sakura

发表于 2018-03-25 | 分类于 生活轨迹

10年前去过一次武汉大学,那会也没有特别的觉得樱花有多美,直到前两年去了一趟岛国,也是三月中下旬,再一次见到樱花,才发现她的美,可惜的是岛国樱花盛开期比武汉这边的晚,所以那次也没有看到盛开的场景,今天终于在樱花的盛开期近距离拍了几张,确实美,不愧为岛国国花。

樱花
樱花
樱花
樱花
樱花
樱花
樱花
樱花
樱花

boost.python

发表于 2017-11-19

最近工作中使用到boost.python,感觉网上这方面的资料还是比较少,官方文档写的也不够详尽,算是做个备忘吧

const char* greet()
{
    return "hello,world";
}
// operator= for index

typedef std::vector<int> VI;
struct Foo
{
    int32_t a;
    std::string b;
    VI vi;
    bool operator==(Foo const& f) const { return f.a == a; }
};

// A friendly class.
typedef std::vector<Foo> VecFoo;
class hello
{
public:
    hello(const std::string& country) { this->country = country; }
    std::string greet() const { return "Hello from " + country; }
    Foo get_foo()const
    {
        Foo foo;
        foo.a = 123;
        foo.b = country;
        return foo;
    }
public:
    std::string country;
    VecFoo vf;
};

template <typename T>
struct VecConvert
{
    typedef std::vector<T> VecT;
    static PyObject* convert(const VecT& vt)
    {
        boost::python::list pylist;
        for (auto& t : vt)
        {
            pylist.append(t);
        }
        return boost::python::incref(pylist.ptr());
    }
};    
  • 导出函数及POD结构
    boost::python::def("greet", greet);
    boost::python::class_<Foo>("Foo")
        .def_readwrite("a", &Foo::a)
        .def_readwrite("b", &Foo::b)
        .def_readwrite("vi", &Foo::vi);
    
  • 导出类
    boost::python::class_<hello>("hello", init<std::string>())
        // Add a regular member function.
        .def("greet", &hello::greet)
        // Add invite() as a member of hello!
        .def("invite", invite)
        .def("get_foo", &hello::get_foo)
        .def_readwrite("vf", &hello::vf);  
    
  • 导出容器
    1. 导出一个新的容器类
      boost::python::class_<VI>("VI").def(boost::python::vector_indexing_suite<VI>());
      
    2. 直接转换为python的list
      boost::python::to_python_converter<VI, VecConvert<int>>();
      
  • python list对象转换为c++ vector
    //c++
    void setFoos(const boost::python::list& pylist)
    {
        std::vector<Foo> fs;
        for (int i =0; i< boost::python::len(pylist); i++)
        {
            fs.push_back(boost::python::extract<Foo>(pylist[i]));
        }
    }
    boost::python::def("setFoos", setFoos);
    //python
    Foo f1,f2
    setFoos([f1, f2])
    

software-engineering-advice-from-google

发表于 2017-11-11
  • google计算环境
    • 大量廉价PC组成的集群
    • 新集群存在大量的硬件故障
  • google工程环境
    • 分布式系统(数据或者请求都没法在一个机器上完成)
    • 遍布全球的多个数据中心
  • 产品大都是服务,而不是简单包装的软件
    • 服务在内部也会大量
    • 。。。
  • 设计软件系统需要各种平衡
    • 简单
    • 扩展
    • 性能
    • 可靠性
    • 通用性
    • 专有性
  • 在编码和详细文档之前需要做的事情
    • 先做一个大致的设计
    • 跟做过类似系统的人在白板上讨论
    • 最好是讨论一些不同的可选设计
  • 接口
    • 接口需要仔细考虑
    • 想象一下一些遗留的客户需要如何使用
    • 精确的文档,但是要避免实现上的限制
    • 在实现接口之前要注意反馈的意见
    • 最好的学习方式是借鉴已有的优秀接口设计
12…16

billowqiu

157 日志
33 分类
10 标签
GitHub E-Mail
© 2020 billowqiu
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.3