使用 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