使用 Chome Timeline 来优化页面性能

有时候,我们就是会不由自主地写出一些低效的代码,严重影响页面运行的效率。或者我们接手的项目中,前人写出来的代码千奇百怪,比如为了一个 Canvas 特效需要同时绘制 600 个三角形,又比如 Coding.net 的任务中心需要同时 watch 上万个变量的变化等等。那么,如果我们遇到了一个比较低效的页面,应该如何去优化它呢?

优化前的准备:知己知彼

在一切开始之前,我们先打开 F12 面板,熟悉一下我们接下来要用到的工具: Timeline :

2

嗯没错就是它。下面逐一介绍一下吧。区域 1 是一个缩略图,可以看到除了时间轴以外被上下分成了四块,分别代表 FPS 、 CPU 时间、网络通信时间、堆栈占用;这个缩略图可以横向缩放,白色区域是下面可以看到的时间段(灰色当然是不可见的啦)。区域 2 可以看一些交互事件,例如你滚动了一下页面,那么这里会出现一个 scroll 的线段,线段覆盖的范围就是滚动经过的时间。区域 3 则是具体的事件列表了。

一开始没有记录的时候,所有的区域都是空的。开始统计和结束统计都很简单,左上角那坨黑色的圆圈就是。它右边那个长得像“禁止通行”的按钮是用来清除现有记录的。当有数据的时候,我们把鼠标滚轮向上滚,可以看到区域被放大了:

3

短短的时间里,浏览器做了这么多事情。对于一般的屏幕,原则上来说一秒要往屏幕上绘制 60 帧,所以理论上讲我们一帧内的计算时间不能超过 16 毫秒,然而浏览器除了执行我们的代码以外,还要干点别的(例如计算 CSS ,播放音频……),所以其实我们能用的只有 10~12 毫秒左右。

差不多熟悉操作了,那么就来一下实战吧!假如有一天,你接手了这样一段代码:

<!-- 一段小动画:点击按钮之后会有一个爆炸的粒子效果 -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Test</title>
    <style>
        .main {
            position: relative;
            width: 500px;
            height: 500px;
            background: #000;
            overflow: hidden;
        }
        .circle {
            position: absolute;
            border-radius: 50%;
            border: 1px solid #FFF;
            width: 8px;
            height: 8px;
        }
    </style>
</head>
<body>
    <div class="main"></div>
    <hr>
    <button onclick="showAnimation()">点我</button>
    <script src="jquery.min.js"></script>
    <script src="animation.js"></script>
</body>
</html>
// animation.js

// 粒子总数
var COUNT = 500;
// 重力
var G = -0.1;
// 摩擦力
var F = -0.04;

function init() {
    for (var i = 0; i < COUNT; i++) {
        var d = Math.random() * 2 * Math.PI;
        var v = Math.random() * 5;
        var circle = $('<div id="circle-' + i + '" class="circle" data-x="250" data-y="250" data-d="' + d + '" data-v="' + v + '"></div>');
        circle.appendTo($('.main'));
    }
}

function updateCircle() {
    for (var i = 0; i < COUNT; i++) {
        var x = parseFloat($('#circle-' + i).attr('data-x'));
        var y = parseFloat($('#circle-' + i).attr('data-y'));
        var d = parseFloat($('#circle-' + i).attr('data-d'));
        var v = parseFloat($('#circle-' + i).attr('data-v'));
        var vx = v * Math.cos(d);
        var vy = v * Math.sin(d);
        if (Math.abs(vx) < 1e-9) vx = 0;
        // 速度分量改变
        vx += F * Math.cos(d);
        vy += F * Math.sin(d) + G;
        // 计算新速度
        v = Math.sqrt(vx * vx + vy * vy);
        if (vy > 0) d = Math.acos(vx / v);
        else d = -Math.acos(vx / v);
        // 位移分量改变
        x += vx;
        y += vy;
        $('#circle-' + i).attr('data-x', x);
        $('#circle-' + i).attr('data-y', y);
        $('#circle-' + i).attr('data-d', d);
        $('#circle-' + i).attr('data-v', v);
        $('#circle-' + i).css({'top': 400 - y, 'left': x});
    }
}

var interval = null;

function showAnimation() {
    if (interval) clearInterval(interval);
    $('.main').html('');
    init();
    interval = setInterval(updateCircle, 1000 / 60);
}

效果如下(右上角的 FPS 计数器是 Chrome 调试工具自带的):

1

只有 10 FPS …… 10 FPS ……坑爹呢这是!

4

好吧,打开 Timeline ,按下记录按钮,点一下页面中的“点我”,稍微过一会儿停止记录,就会得到一些数据。放大一些,对 jQuery 比较熟悉的同学可以看出来,这些大部分是 jQuery 的函数。我们点一下那个 updateCircle 的区块,然后看下面:

5

这里告诉我们,这个函数运行了多久、函数代码在哪儿。我们点一下那个链接,于是就跳到了 Source 页:

6

是不是很震撼,之前这个页面只是用来 Debug 的,没想到现在居然带了精确到行的运行时间统计。当然,这个时间是当前这一行在“刚才我们点击的区块对应的执行时间段”中运行的时间。所以我们就拿最慢的几句话来下手吧!

优化一:减少 DOM 操作

看到这几行代码,第一反应是: mdzz 。本来 DOM 操作就慢,还要在字符串和 float 之间转来转去。果断改掉!于是用一个单独的数组来存 xydv 这些属性。

var objects = [];
// 在 init 函数中
objects.push({
    x: 250,
    y: 250,
    d: d,
    v: v
});
// 在 updateCircle 函数中
var x = objects[i].x;
var y = objects[i].y;
var d = objects[i].d;
var v = objects[i].v;
// ….
objects[i].x = x;
objects[i].y = y;
objects[i].d = d;
objects[i].v = v;

7

效果显著!我们再来看一下精确到行的数据:

8

优化二:减少不必要的运算

所以最耗时的那句话已经变成了计算 vxvy,毕竟三角函数算法比较复杂嘛,可以理解。至于后面的三角函数为什么那么快,我猜可能是 Chrome 的 V8 引擎将其缓存了(这句话不保证正确性)。然而不知道大家有没有发现,其实计算 d完全没必要!我们只需要存 vxvy 即可,不需要存 vd

// init
var vx = v * Math.cos(d);
var vy = v * Math.sin(d);
objects.push({
    x: 250,
    y: 250,
    vx: vx,
    vy: vy
});
// updateCircle
var vx = objects[i].vx;
var vy = objects[i].vy;
// 计算新速度
var v = Math.sqrt(vx * vx + vy * vy);
if (Math.abs(vx) < 1e-9) vx = 0;
// 速度分量改变
vx += F * vx / v;
vy += F * vy / v + G;
// ….
objects[i].vx = vx;
objects[i].vy = vy;

9

只有加减乘除和开平方运算,每次比原来的时间又少了两毫秒。从流畅的角度来说其实已经可以满帧运行了,然而为什么我还是觉得偶尔会有点卡呢?

优化三:替换 setInterval

既然偶尔会掉帧,那么就看看是怎么掉的呗~原则上来说,在每一次浏览器进行绘制之前, Timeline 里面应该有一个叫 Paint 的事件,就像这样:

10

看到这些绿色的东西了没?就是它们!看上面的时间轴,虽然代码中 setInterval 的长度是 1000/16 毫秒,但是其实根本不能保证!所以我们需要使用 requestAnimationFrame 来代替它。这是浏览器自带的专门为动画服务的函数,浏览器会自动优化这个函数的调用时机。并且如果页面被隐藏,浏览器还会自动暂停调用,有效地减少了 CPU 的开销。

// 在 updateCircle 最后加一句
requestAnimationFrame(updateCircle);
// 去掉全部跟 setInterval 有关的句子,把 showAnimation 最后一句直接改成这个
updateCircle();

我们至少可以保证,我们每算一次,屏幕上就会显示一次,因此不会掉帧(前提是每计算一次的时间小于 12ms )。但是虽然计算时间少了,浏览器重计算样式、绘制图像的时间可是一点都没变。能不能再做优化呢?

优化四:使用硬件加速、避免反复查找元素

如果我们用 transform 来代替 lefttop 来对元素进行定位,那么浏览器会为这个元素单独创立一个合成层,专门使用 GPU 进行渲染,这样可以把重计算的代价降到最低。有兴趣的同学可以研究一下“ CSS 硬件加速”的机制。同时,我们可以缓存一下 jQuery 的元素(或者 DOM 元素),这样不用每次都重新查找,也能稍微提高一点效率。如果把元素缓存在 objects 数组中,那么连 id 都不用写了!

// init
var circle = $('<div class="circle"></div>');
objects.push({
    x: 250,
    y: 250,
    vx: vx,
    vy: vy,
    // 其实可以只存 DOM ,不存 jQuery 对象
    circle: circle[0]
});
// updateCircle 里面 for 循环的最后一句话替换掉
objects[i].circle.style.transform = 'translate(' + x + 'px, ' + (400 - y) + 'px)';

11

看起来是不是很爽了?

其实,优化是无止境的,例如我在 init 函数中完全可以不用 jQuery ,改用 createDocumentFragment 来拼接元素,这样初始化的时间就可以急剧缩短;调换 updateCircle 中的几个语句的顺序,在 V8 引擎下效率可能会有一定的提升;甚至还可以结合 Profile 面板来分析内存占用,查看浏览器绘图的细节……然而个人感觉并用不到这么极限的优化。对于一个项目来说,如果单纯为了优化而写一些奇怪的代码,是很不合算的。

P.S. 全部的代码在这里,欢迎吐槽:

未优化版 | 优化版

 

转载自:http://www.v2ex.com/t/298334#reply9

打造 Golang Atom IDE

简直太折磨人了,我膝盖已经全部是血了。

得知了Golang已经1.5.1了,我兴致勃勃的进行更新,这之后就是跪着走完了这条路啊。真的go die了

安装go

首先我先从官方网站:https://golang.org/ 下载Go的安装包,很happy的安装了。然后在终端里输入go可以看到安装已经成功了。但是当我输入go version出现了第一个坑。

go: GOPATH entry is relative; must be absolute path: "".
Run 'go help gopath' for usage.

我开始了Google之旅,发现别人都是windows的分号问题,妈蛋啊我又不是windows,经过了一段时间的战斗,我发现在~/.bash_profile下面我定义了一个GOPATH,是老的一个Go版本,也许问题出在这里,紧接着我将GOPATH定义成了一个自定义的目录,终于妥妥的了。再次输入go version,如下

go version go1.5.1 darwin/amd64

至此环境终于妥妥的了。

go in Atom

接着开始在Atom上面开始进行Go环境的安装了,再次一滩血。首先Google告诉我需要安装go-plus,我老老实实的安装了这个插件,如下:

 

你们也看到了,关键是这货需要安装其他很多插件,我照着装了之后貌似没有太大的效果,所以我开始本地安装之旅。主要是这样一些
安装golint

go get github.com/golang/lint
go install github.com/golang/lint
go install github.com/golang/lint/golint

安装gooracle

go get code.google.com/p/go.tools/cmd/oracle
go install code.google.com/p/go.tools/cmd/oracle

安装goimport

go get golang.org/x/tools/cmd/goimports
go install golang.org/x/tools/cmd/goimports

安装gocode

go get -u github.com/nsf/gocode
go install -u github.com/nsf/gocode

安装 godef

go get -v code.google.com/p/rog-go/exp/cmd/godef
go install -v code.google.com/p/rog-go/exp/cmd/godef

但是这不是关键,关键是国内golang.org/x/tools根本就连不上啊,扑街了。我开了vpn的说。。。随即找了别的方式。我这里使用的是下载安装包到本地,然后通过go install的方式进行安装。但是关键是go非常蛋疼的是根本不认绝对路径,只认GOPATH+本地的组合路径,所以所有的安装包还必须放在GOPATH的对应的src路径下面。
我找到的非常好的下载安装包的网站url:https://gopm.io/download

大家下载好之后,使用go install xxxx的方式进行安装,安装成功之后可以看到在GOPATH对应的bin目录下会有对应的命令文件出现,代表安装成功了,如下:

 

Demo

我们新建一个go的脚本,然后选中插件中的go-plus中的Display go information的选项,见到如下界面代表你的环境一切都ok了,开始几乎就是全红。。。。。

 

之后就开始爽爽的了。

 
 

至此,HP已经空了。。。。

 

转载自:https://testerhome.com/topics/3728

基于微服务的软件架构模式

今天阅读了两篇关于微服务的文章,总结一些笔记,不敢贸然翻译:一是因为水平不够,翻译的过程会丢掉作者的原意;二是因为技术翻译是一个略微吃力不讨好的活。

微服务(micro services)这个概念不是新概念,很多公司已经在实践了,例如亚马逊、Google、FaceBook,Alibaba。微服务架构模式(Microservices Architecture Pattern)的目的是将大型的、复杂的、长期运行的应用程序构建为一组相互配合的服务,每个服务都可以很容易得局部改良。 Micro这个词意味着每个服务都应该足够小,但是,这里的小不能用代码量来比较,而应该是从业务逻辑上比较——符合SRP原则的才叫微服务。

暂且不讨论大小问题,读者朋友你首先要考虑的是如何解决目前技术团队遇到的开发问题、部署问题。正是在解决这些问题的过程中,才渐渐总结提炼出了微服务架构模式的概念。

微服务跟SOA有什么区别呢,可以把微服务当做去除了ESB的SOA。ESB是SOA架构中的中心总线,设计图形应该是星形的,而微服务是去中心化的分布式软件架构。

接下来会讨论以下几个话题:

  1. 应用微服务的动机,跟传统巨石应用的比较
  2. 微服务的优点与缺点
  3. 应用微服务架构设计时可能遇到的关键问题(内部服务通信、分布式数据管理)

一、巨石(monolith)

web应用程序发展的早期,大部分web工程是将所有的功能模块(service side)打包到一起并放在一个web容器中运行,很多企业的Java应用程序打包为war包。其他语言(Ruby,Python或者C++)写的程序也有类似的问题。

假设你正在构建一个在线商店系统:客户下订单、核对清单和信用卡额度,并将货物运输给客户。很快,你们团队一定能构造出如下图所示的系统。

Fig1- the monolithic architecture

这种将所有功能都部署在一个web容器中运行的系统就叫做巨石型应用。巨石型应用有很多好处:IDE都是为开发单个应用设计的、容易测试——在本地就可以启动完整的系统、容易部署——直接打包为一个完整的包,拷贝到web容器的某个目录下即可运行。

但是,上述的好处是有条件的:应用不那么复杂。对于大规模的复杂应用,巨石型应用会显得特别笨重:要修改一个地方就要将整个应用全部部署(PS:在不同的场景下优势也变成了劣势);编译时间过长;回归测试周期过长;开发效率降低等。另外,巨石应用不利于更新技术框架,除非你愿意将系统全部重写(代价太高你愿意老板也不愿意)。

二、应用拆分

详细一个网站在业务大规模爬升时会发生什么事情?并发度不够?OK,加web服务器。数据库压力过大?OK,买更大更贵的数据库。数据库太贵了?将一个表的数据分开存储,俗称“分库分表”。这些都没有问题,good job。不过,老外的抽象能力比我们强,看下图Fig2。

Fig2 – the scale cube

这张图从三个维度概括了一个系统的扩展过程:(1)x轴,水平复制,即在负载均衡服务器后增加多个web服务器;(2)z轴扩展,是对数据库的扩展,即分库分表(分库是将关系紧密的表放在一台数据库服务器上,分表是因为一张表的数据太多,需要将一张表的数据通过hash放在不同的数据库服务器上);(3)y轴扩展,是功能分解,将不同职能的模块分成不同的服务。从y轴这个方向扩展,才能将巨型应用分解为一组不同的服务,例如订单管理中心、客户信息管理中心、商品管理中心等等。

将系统划分为不同的服务有很多方法:(1)按照用例划分,例如在线商店系统中会划分出一个checkout UI服务,这个服务实现了checkout这个用例;(2)按照资源划分,例如可以划分出一个catlog服务来存储产品目录。

服务划分有两个原则要遵循:(1)每个服务应该尽可能符合单一职责原则——Single Responsible Principle,即每个服务只做一件事,并把这件事做好;(2)参考Unix命令行工具的设计,Unix提供了大量的简单易用的工具,例如grep、cat和find。每个工具都小而美。

最后还要强调:系统分解的目标并不仅仅是搞出一堆很小的服务,这不是目标;真正的目标是解决巨石型应用在业务急剧增长时遇到的问题。

对于上面的例子,按照功能和资源划分后,就形成下面图3的架构图。分解后的微服务架构包含多个前端服务和后端服务。前端服务包括Catalog UI(用于商品搜索和浏览)、Checkout UI(用于实现购物车和下单操作);后端服务包括一些业务逻辑模块,我们将在巨石应用中的每个服务模块重构为一个单独的服务。这么做有什么问题呢?

Fig 3 – the microservice architecture

三、微服务架构的优点与缺点

1. 优点

  • 每个服务足够内聚,足够小,代码容易理解、开发效率提高
  • 服务之间可以独立部署,微服务架构让持续部署成为可能;
  • 每个服务可以各自进行x扩展和z扩展,而且,每个服务可以根据自己的需要部署到合适的硬件服务器上;
  • 容易扩大开发团队,可以针对每个服务(service)组件开发团队;
  • 提高容错性(fault isolation),一个服务的内存泄露并不会让整个系统瘫痪;
  • 系统不会被长期限制在某个技术栈上。

2. 缺点

《人月神话》中讲到:没有银弹,意思是只靠一把锤子是盖不起摩天大楼的,要根据业务场景选择设计思路和实现工具。我们看下为了换回上面提到的好处,我们付出(trade)了什么?

  • 开发人员要处理分布式系统的复杂性;开发人员要设计服务之间的通信机制,对于需要多个后端服务的user case,要在没有分布式事务的情况下实现代码非常困难;涉及多个服务直接的自动化测试也具备相当的挑战性;
  • 服务管理的复杂性,在生产环境中要管理多个不同的服务的实例,这意味着开发团队需要全局统筹(PS:现在docker的出现适合解决这个问题
  • 应用微服务架构的时机如何把握?对于业务还没有理清楚、业务数据和处理能力还没有开始爆发式增长之前的创业公司,不需要考虑微服务架构模式,这时候最重要的是快速开发、快速部署、快速试错。

四、微服务架构的关键问题

1. 微服务架构的通信机制

(1)客户端与服务器之间的通信

在巨石型架构下,客户端应用程序(web或者app)通过向服务端发送HTTP请求;但是,在微服务架构下,原来的巨石型服务器被一组微服务替代,这种情况下客户端如何发起请求呢?

如图4中所示,客户端可以向micro service发起RESTful HTTP请求,但是会有这种情况发生:客户端为了完成一个业务逻辑,需要发起多个HTTP请求,从而造成系统的吞吐率下降,再加上无线网络的延迟高,会严重影响客户端的用户体验。

Fig4 – calling services directly

为了解决这个问题,一般会在服务器集群前面再加一个角色:API gateway,由它负责与客户度对接,并将客户端的请求转化成对内部服务的一系列调用。这样做还有个好处是,服务升级不会影响到客户端,只需要修改API gateway即可。加了API gateway之后的系统架构图如图5所示。

Fig5 – API gateway

(2)内部服务之间的通信

内部服务之间的通信方式有两种:基于HTTP协议的同步机制(REST、RPC);基于消息队列的异步消息处理机制(AMQP-based message broker)。

Dubbo是阿里巴巴开源的分布式服务框架,属于同步调用,当一个系统的服务太多时,需要一个注册中心来处理服务发现问题,例如使用ZooKeeper这类配置服务器进行服务的地址管理:服务的发布者要向ZooKeeper发送请求,将自己的服务地址和函数名称等信息记录在案;服务的调用者要知道服务的相关信息,具体的机器地址在ZooKeeper查询得到。这种同步的调用机制足够直观简单,只是没有“订阅——推送”机制。

AMQP-based的代表系统是kafkaRabbitMQ等。这类分布式消息处理系统将订阅者和消费者解耦合,消息的生产者不需要消费者一直在线;消息的生产者只需要把消息发送给消息代理,因此也不需要服务发现机制。

两种通信机制都有各自的优点和缺点,实际中的系统经常包含两种通信机制。例如,在分布式数据管理中,就需要同时用到同步HTTP机制和异步消息处理机制。

2. 分布式数据管理

(1)处理读请求

在线商店的客户账户有限额,当客户试图下单时,系统必须判断总的订单金额是否超过他的信用卡额度。信用卡额度由CustomerService管理、下订单的操作由OrderService负责,因此Order Service要通过RPC调用向Customer Service请求数据;这种方法能够保证每次Order Service都获取到准确的额度,单缺点是多一次RPC调用、而且Customer Service必须保持在线。

还有一种处理方式是,在OrderService这边存放一份信用卡额度的副本,这样就不需要实时发起RPC请求,但是还需要一种机制保证——当Customer Service拥有的信用卡额度发生变化时,要及时更新存放在Order Service这边的副本。

(2)处理更新请求

当一份数据位于多个服务上时,必须保证数据的一致性。

  • 分布式事务(Distributed transactions)
    使用分布式事务非常直观,即要更新Customer Service上的信用卡额度,就必须同时更新其他服务上的副本,这些操作要么全做要么全不做。使用分布式事务能够保证数据的强一致,但是会降低系统的可用性——所有相关的服务必须始终在线;而且,很多现代的技术栈并不支持事务,例如REST、NoSQL数据库等。
  • 基于事件的异步更新(Event-driven asynchronous updates)
    Customer Service中的信用卡额度改变时,它对外发布一个事件到“message broker(消息代理人)”;其他订阅了这个事件的服务受到提示后就更新数据。事件流如图6所示。
    Fig 6 – replicating the credit limit using events

五、重构巨石型应用

在实际工作中,很少有机会参与一个全新的项目,需要处理的差不多都是存在这样那样问题的复杂、大型应用。这时候如何在维护老服务的同时,将系统渐渐重构为微服务架构呢?

  1. 不要让事情更坏,有新的需求过来时,如果可以独立开发为一个服务,就单独开发,然后为老服务和新服务直接编写胶水代码(Glue Code)——这个过程不容易,但这是分解巨型服务的第一步,如图7所示;
    Fig-7 – extracting a service
  2. 识别巨石型应用中的可以分离出来当做单独服务的模块,一般适合分离的模块具有如下特点:两个模块对资源的需求是冲突的(一个是CPU密集型、一个是IO密集型);授权鉴定层也适合单独分离出一个服务。每分离出一个服务,就需要编写对应的胶水代码来与剩下的服务通信,这样,在逐渐演进过程中,就完成了整个系统的架构更新。

关于重构,有篇文章推荐大家阅读——推倒重来的讲究,关于重构有很多可以写的,希望我能快速进步,多写点总结与大家分享。

总结

微服务并不是治百病的良药,也不是什么新的技术,我从中学到的最大的一点就是scale cube,从这个坐标轴出发去考虑大规模系统的构建比较容易分析和实践。

 

文/杜琪(简书作者)
原文链接:http://www.jianshu.com/p/546ef242b6a3
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

Microsoft Visual Studio 2013 Serial Numbers

Visual Studio 2013 Keys 备用:

Microsoft Visual Studio Ultimate  2013

BWG7X-J98B3-W34RT-33B3R-JVYW9

============================

Microsoft Visual Studio Professional 2013

XDM3T-W3T3V-MGJWK-8BFVD-GVPKY

============================

Microsoft Visual Studio Premium 2013

FBJVC-3CMTX-D8DVP-RTQCT-92494

Vagrant 的配置

Linux/Mac/Windows 三系系统都可以使用 Vagrant 来搭建开发环境,并且一次配置,到处都可以使用,不需要额外再去配置新环境,所以用起来很方便,下面就将配置方法做一记录,以备不时之需

安装 Vagrant 可以从这里 https://www.vagrantup.com/  下载对应平台的 Vagrant ,安装完成之后还需要安装 Virtualbox 可以从这里下载 https://www.virtualbox.org/wiki/Downloads 并安装

接下来要下载系统,你也可以自己安装系统,这里使用已经做好的系统镜像 http://www.vagrantbox.es/ ,可以在这里选择你喜欢的操作系统

然后就可以打命令初始化了

这一步会进行下载,如果觉得下载很慢的话,可以用下载工具进行下载,如果你用迅雷的话记得一定要从原始站点下载,否则可能会导致不能用
vagrant init hashicorp/precise32
下载完成后就可以打开虚拟机了
vagrant up

当然也可以手工的初始化

vagrant init 这一步完成之后会在当前目录下生成一个 Vagrantfile ,里面可以进行配置

具体配置可以参考这里 https://docs.vagrantup.com/v2/vagrantfile/index.html

vagrant 的几个常用命令

vagrant up 开机
vagrant reload 重启
vagrant halt 关机
vagrant box add 添加虚拟机
vagrant box list 虚拟机列表
vagrant box remove 删除一台虚拟机
vagrant package 如果在配置完虚拟机没有进行导出的话,那么你的 box 文件移动到别的地方里面的配置是不会带过来的

 

在 ArchLinux 下构建 Objective-C 2.0 环境

网上有许多关于 Ubuntu 下构建 Objective-C 2.0 环境的例子,我现在只是换了一个发行版—— ArchLinux

首先先要安装所需要的编译器和库

这里先要安装 gcc-objc 、gnustep-back 、gnustep-base 、gnustep-gui 、gnustep-make 这几样东西 ,只是看 Ubuntu 说会安装所有关于 gnustep 东西 ,我用 yaourt 看了一下,基本上只有这4个

Command:

sudo pacman -S gcc-objc gnustep-back gnustep-base gnustep-gui gnustep-make

在安装完成后,我们写一小段代码先来测试一下能否正确编译和使用

 创建一个叫 Hello.m 文件,写上如下代码:

#import <Foundation/Foundation.h>

int main(int argc, const char *argv[]) {
    NSLog(@"Hello world NSLOG");
    return 0;
}

然后使用 gcc 命令进行编译,那么如果直接用 gcc 编译 hello.m 文件,是可能会出错的

所以我们使用如下命令进行编译

gcc `gnustep-config –objc-flags` main.m -o main.out -lgnustep-base -lobjc

那么,如果最后编译正确的话,你所在的目录下应该会出现一个叫  main.out 的可执行文件

最后,你就可以愉快的执行它了,看一看它的执行结果

./main.out
2015-06-29 23:36:59.038 main.out[22410] Hello world NSLOG

gVim For windows 的配置文件

set rtp+=$VIM\vimfiles\bundle\vundle\
call vundle#rc('$VIM/vimfiles\bundle\')

"Bundle
Bundle 'bling/vim-airline'
Bundle 'tpope/vim-fugitive'
Bundle 'vim-scripts/AutoComplPop'
Bundle 'msanders/snipmate.vim'
Bundle 'edsono/vim-matchit'
Bundle 'vim-scripts/Conque-Shell'
Bundle "mattn/emmet-vim"
Bundle 'ack'
Bundle 'NERD_tree'
Bundle 'bclose'
Bundle 'ctrlp'
"ENd Bundle

let mapleader=","           "Changes Leader key into a comma instead of a backslash
set nocompatible            "Prefents VIM from being nerfed into acting like VI
set viminfo='1000,f1,:1000,/1000
set history=500

au FileType php set omnifunc=phpcomplete#CompletePHP

"------  Visual Options  ------
"set guioptions=egmt         "remove toolbar, scrollbars
syntax on                   "Enables syntax highlighting
set nu                      "Enable Line Numbers
set wrap                  	"Enable word wrap
set noswapfile				"Disable swap file
"set nobackup				"Disable backup file
set backupdir=~/.vim/backupfile/

set novb                      "Visual bell instead of beeps
set ruler                   "Displays cursor position on bottom right of screen
set autochdir
"set statusline=2
let g:buftabs_only_basename=1
let g:buftabs_marker_modified = "+"
"------  Behavior  ------ 
set tabstop=4               
"tab = 4 spaces 
set shiftwidth=4            "Indent to four spaces
set hidden                  "Switch between unsaved buffers w/o needing to save, preserves history
filetype indent on          "Syntax Highlight
filetype plugin on          "Needed for snipMate
set autoindent              "Autoindent
set expandtab               "Use spaces instead of tabs "Ignore these files when completing names
set wildignore=.svn,CVS,.git,*.o,*.a,*.class,*.mo,*.la,*.so,*.obj,*.swp,*.jpg,*.png,*.xpm,*.gif,node_modules/*

"------  Special Coffee Behavior ------
au BufNewFile,BufReadPost *.coffee set shiftwidth=2 softtabstop=2 expandtab
autocmd BufNewFile,BufRead *.coffee set filetype=coffee
au BufWritePost *.coffee silent make!
autocmd QuickFixCmdPost * nested cwindow | redraw!
autocmd BufEnter * lcd %:p:h

"------  Searching  ------
set incsearch               "Search while typing
set ignorecase              "Case Insensitive Searching
set smartcase               "Lowercase = case insensitive, any uppercase = case sensitive
set hlsearch                "Highlight all search results
"Following line clears the search highlights when pressing Lb
nnoremap b :nohlsearch
" http://www.vim.org/scripts/script.php?script_id=2572
noremap a :Ack 
noremap A jcl
let g:ackprg="ack -H --nocolor --nogroup --column --type-add php=.tpl"

"------  Replacing ------
"type S, then type what you're looking for, a /, and what to replace it with
nmap S :%s//g
vmap S :s//g

"------  NERDTree Options  ------
let NERDTreeIgnore=['CVS','\.dSYM$']
let NERDTreeChDirMode=2     "setting root dir in NT also sets VIM's cd
noremap  n :NERDTreeToggle
" These prevent accidentally loading files while in the NERDTree panel
autocmd FileType nerdtree noremap   
autocmd FileType nerdtree noremap   
autocmd FileType nerdtree noremap   
autocmd FileType nerdtree noremap   

"------  Tagbar Options  ------
" http://adamyoung.net/Exuberant-Ctags-OS-X
" http://www.vim.org/scripts/script.php?script_id=273
"let g:tagbar_width=26
"noremap  y :TagbarToggle

"------  Buffers  ------
" Ctrl Left & Right move between buffers
noremap   :bprev
noremap   :bprev
noremap   :bnext
noremap   :bnext
" Closes the current buffer
nnoremap  q :Bclose

" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! %!sudo tee > /dev/null %

" Closes the current window
nnoremap  Q c

"------  Fugitive  ------ 
"https://github.com/tpope/vim-fugitive
nnoremap gs :Gstatus
nnoremap gr :Gremove
nnoremap gl :Glog
nnoremap gb :Gblame
nnoremap gm :Gmove 
nnoremap gp :Ggrep 
nnoremap gR :Gread
nnoremap gg :Git 
nnoremap gd :Gdiff

"------  Moving Between Windows  ------
nnoremap h h
nnoremap l l
nnoremap j j
nnoremap k k
nnoremap wo o
nnoremap wv vl
nnoremap ws s
nnoremap ww 

" Opens an edit command with the path of the currently edited file filled in Normal mode: ee
map ee :e =expand("%:p:h") . "/" 

" Opens a tab edit command with the path of the currently edited file filled in
" Normal mode: t
map et :tabe =expand("%:p:h") . "/" 

" Edit and Reload .vimrc files
nmap  ev :e $MYVIMRC
nmap  es :so $MYVIMRC

" When pressing cd switch to the directory of the open buffer
"map cd :cd %:p:h
" ,ct = Builds ctags
map ct :! /usr/local/bin/ctags -R *

" F2 = Paste Toggle (in insert mode, pasting indented text behavior changes)
set pastetoggle=
" ,T = Delete all Trailing space in file
map T :%s/\s\+$//
" ,U = Deletes Unwanted empty lines
map U :g/^$/d
" ,R = Converts tabs to spaces in document
map R :retab
" ,p = Runs PHP lint checker on current file
map p :! php -l %
" ,P = Runs PHP and executes the current file
map P :! php -q %
" ,L = Toggle line numbers
map L :set invnumber
" ,v = Paste
map v "+gP
" ,c = Copy
map c "+y

" Deletes trailing space in file upon write
" autocmd BufWritePre * :%s/\s\+$//e

map ? :Helptags

"vim for Terminator
map ts 	:ConqueTermSplit zsh
map tn 	:ConqueTerm zsh
let g:ConqueTerm_Syntax	= 'conque'

" AirLine
let g:airline#extensions#tabline#enabled = 1
let g:airline_section_b = '%{strftime("%c")}'
"let g:airline_powerline_fonts = 1
let g:airline_enable_branch=1
let g:airline_enable_syntastic=1
let g:airline_detect_paste=1
let g:airline_theme='molokai'

if has("gui_running")
    set cursorline                  "Highlight background of current line
    "autocmd VimEnter * NERDTree     "run nerdtree
    "autocmd VimEnter * TagbarOpen
	colorscheme molokai
	set background=dark

    " Show tabs and newline characters with ,s
    nmap s :set list!
	"set listchars=tab:▸\ ,trail:·,extends:❯,precedes:❮,nbsp:×,eol:¬
    "Invisible character colors
    highlight NonText guifg=#4a4a59
    highlight SpecialKey guifg=#4a4a59
	
	set guicursor=i:block

	set guioptions-=m " 隐藏菜单栏 
	set guioptions-=T " 隐èPTfallback—工具栏 
	set guioptions-=L " 隐藏左侧滚动条 
	set guioptions-=r " 隐藏右侧滚动条 
	set guioptions-=b " 隐藏底部滚动杀XPTfallback¡
	set showtabline=0 " 隐藏Tab栏	
	set guifont=YaHei\ Consolas\ Hybrid\ 11
	set laststatus=2
	" Ctrl + Shift + C and Ctrl + Shift + V for copying and pasting OS Buffer
	" Vim can't do Ctrl + Shift :'(
	" which means C-V overwrites visual select (C-v)
	"map  "+y
	"map  "+gp
	map  :call system("wmctrl -r :ACTIVE: -b toggle,fullscreen")
else
    set t_Co=256
    colorscheme Mustang             "This theme actually works in 256, ir_black doesn't
	set mouse=a						"This allows mouse scrolling in terminal, and selection of text
endif

if has("gui_macvim") "Use Experimental Renderer option must be enabled for transparency
	"set guifont=Monaco:h14
	set guifont=Monaco:h10
	set noantialias
	set transparency=15
    " Swipe to move between bufers :D
    map  :bprev
    map  :bnext
	" OS X probably has ctags in a weird place
	let g:tagbar_ctags_bin='/usr/local/bin/ctags'

		    
endif

if filereadable($HOME.'/.vimrc_local')
    source $HOME/.vimrc_local
endif


基于 github vim-php-ide.git 项目,这个配置文件可以在 Linux ,Windows ,Mac OS X 下用,Linux ,Mac 下,请改为

set rtp+=~/.vim/bundle/vundle/
call vundle#rc()

配置文件下载链接,适用于 vim7.4

http://pan.baidu.com/s/1eQo2Pc2