
暂无个人介绍
能力说明:
掌握封装、继承和多态设计Java类的方法,能够设计较复杂的Java类结构;能够使用泛型与集合的概念与方法,创建泛型类,使用ArrayList,TreeSet,TreeMap等对象掌握Java I/O原理从控制台读取和写入数据,能够使用BufferedReader,BufferedWriter文件创建输出、输入对象。
阿里云技能认证
详细说明J2SE基础: 九种基本数据类型的大小,以及他们的封装类。 byte,short,int,long,float,double,boolen,char,void 基本类型所占的存储空间是不变的:这种不变性也是java具有可移植性的原因之一。 基本类型是放在栈中,直接存储值。 所有数值类型都有正负号,没有无符号的数值类型。 Switch能否用string做参数? 在 Java 7之前,switch 只能支持 byte、short、char、int或者其对应的封装类以及 Enum 类型。在 Java 7中,String支持被加上了。 equals与==的区别。 equals比较两个对象的内容是否相同 == 比较两个对象是否是同一对象。 Object有哪些公用方法? protected Object clone()创建并返回此对象的一个副本。 boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。 protected void finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。 Class<?> getClass()返回此 Object 的运行时类。 int hashCode()返回该对象的哈希码值。 void notify()唤醒在此对象监视器上等待的单个线程。 void notifyAll()唤醒在此对象监视器上等待的所有线程。 String toString()返回该对象的字符串表示。 void wait()在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。 void wait(long timeout)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。 void wait(long timeout, int nanos)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。 Java的四种引用,强弱软虚,用到的场景. null Hashcode的作用。 1、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的; 2、如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同; 3、如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点; 4、两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。 ArrayList、LinkedList、Vector的区别。 ArrayList Vector都使用数组式存储数据数组元素数于实际存储数据便增加插入元素都允许直接按序号索引元素插入元素要涉及数组元素移等内存操作所索引数据快插入数据慢Vector由于使用synchronized(线程安全)通性能较ArrayList差LinkedList使用双向链表实现存储按序号索引数据需要进行前向或向遍历插入数据需要记录本项前项即所插入速度较快 String、StringBuffer与StringBuilder的区别。 1、String,StingBuffer,StringBuilder是字符串变量还是常量? String ----> 字符串常量 StringBuffer ----> 字符串变量(线程安全的) StringBuilder ----> 字符串变量(非线程安全的) 2、String,StingBuffer,StringBuilder效率如何呢? 从高到底的顺序依次是:StringBuilder > StingBuffer > String 有上知道了String是字符串常量,所以他的效率自然而然是最低的。对于StringBuffer和StringBuilder它们属于变量,是可以改变的对象,每次对字符串的操作,实际上实在一个对象上操作,所以效率更高一些。StringBuffer是线程安全的,考虑到安全问题,相对他的性能会更低一点。由此知道了从效率的角度看,StringBuilder最高,其次是StringBuffer,最后是String字符串常量。 总结: 当多个线程使用字符串缓冲区时,使用StringBuffer保证正确的操作,如果是单线程的,建议使用StringBuiler效率更高一些。 Map、Set、List、Queue、Stack的特点与用法。[Collection和Map常用类的比较 ](https://zhuanlan.zhihu.com/p/30086934) list 和set 有共同的父类 它们的用法也是一样的 唯一的不太就是set中不能有相同的元素 list中可以 list和set的用途非常广泛 list可以完全代替数组来使用 map 是独立的合集 它使用键值对的方式来储存数据 键不能有重复的 值可以用 map不像上边两种集合那个用的广泛 不过在servlet 和jsp中 map可是绝对的重中之重 页面之间传值全靠map List是集合类的接口,子类有ArraryList 和LinkList,通常在Android开发中我们常用的是arrayList,来将数据进行插入和移除。 其次map也是一个集合映射,不过是键值对的映射,也就是key , value形式,比如当我们需要查询其中的某个对象时,只需要查询其key便能直接获取到他的value(值),就像一个小型的数据库,也有类似于hashmap , Linkedhashmap ,treemap等方法来进一步实现和拓展,并且提高他的性能。 Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。 Set接口主要实现了两个实现类: HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快 TreeSet :TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。 Set的功能方法 Set具有与Collection完全一样的接口,因此没有任何额外的功能,不像前面有两个不同的List。实际上Set就是Collection,只 是行为不同。(这是继承与多态思想的典型应用:表现不同的行为。)Set不保存重复的元素(至于如何判断元素相同则较为负责) Set : 存入Set的每个元素都必须是唯一的,因为Set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。 HashSet:为快速查找设计的Set。存入HashSet的对象必须定义hashCode()。 TreeSet: 保存次序的Set, 底层为树结构。使用它可以从Set中提取有序的序列。 LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。 Queue用于模拟"队列"这种数据结构(先进先出 FIFO)。队列的头部保存着队列中存放时间最长的元素,队列的尾部保存着队列中存放时间最短的元素。新元素插入(offer)到队列的尾部, 访问元素(poll)操作会返回队列头部的元素,队列不允许随机访问队列中的元素。结合生活中常见的排队就会很好理解这个概念 3.1) PriorityQueue PriorityQueue并不是一个比较标准的队列实现,PriorityQueue保存队列元素的顺序并不是按照加入队列的顺序,而是按照队列元素的大小进行重新排序,这点从它的类名也可以 看出来 3.2) Deque Deque接口代表一个"双端队列",双端队列可以同时从两端来添加、删除元素,因此Deque的实现类既可以当成队列使用、也可以当成栈使用 3.2.1) ArrayDeque 是一个基于数组的双端队列,和ArrayList类似,它们的底层都采用一个动态的、可重分配的Object[]数组来存储集合元素,当集合元素超出该数组的容量时,系统会在底层重新分配一个Object[]数组来存储集合元素 3.2.2) LinkedList HashMap和HashTable的区别。 HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式 区别1: HashMap可以存放 null Hashtable不能存放null 区别2: HashMap不是线程安全的类 Hashtable是线程安全的类 HashTable已经被淘汰了 如果需要线程安全使用ConcurrentHashMap HashMap和ConcurrentHashMap的区别,HashMap的底层源码。null null TreeMap、HashMap、LindedHashMap的区别。 LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。 Collection包结构,与Collections的区别。 Collection是集合类的上级接口,子接口主要有Set 和List、Map。 Collections是针对集合类的一个帮助类,提供了操作集合的工具方法:一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。 try catch finally,try里有return,finally还执行么? 肯定会执行。finally{}块的代码只有在try{}块中包含遇到System.exit(0);之类的导致Java虚拟机直接退出的语句才会不执行。 1.影响返回结果的前提是在 非 finally 语句块中有 return 且非基本类型 2.不影响返回结果 的前提是 非 finally 块中有return 且为基本类型 究其本质 基本类型在栈中存储,返回的是真实的值,而引用类型返回的是其浅拷贝堆地址.所以才会改变。 Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。 oom: 1、全称为OutOfMemoryError异常,如果虚拟机在扩展栈时无法申请足够的内存空间,抛出它; 2、Java heap异常:java.lang.OutOfMemoryError:Java heap Space; 3、虚拟机栈和本地方法溢出; 4、运行时常量池溢出异常信息:java.lang.OutOfMemoryError:PermGen Space; 如果要向运行时常量池添加内容,简单的做法就是使用String.intern()这个Native方法; 5、方法区溢出,方法区用于存放class的相关信息,如类名,常量池,字段描述,方法描述等。 异常信息为:java.lang.OutofMemoryError:PermGen Space; 6、引起OOM主要有2个原因:内存泄露和内存溢出(即堆、栈溢出); SOF: 1、全称为StackOverFlowError异常; 2、如果线程请求的栈深度大于虚拟机所允许的深度,抛出该异常; 3、主要发生在递归调用中; Java面向对象的三个特征与含义。(封装,继承,多态)[http://www.cnblogs.com/chenssy/p/3351835.html] Override和Overload的含义去区别。 重载 (Overload) 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数、类型或顺序不同)。 重写 (Override) 表示子类中的方法可以与父类中的某个方法的名称 和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那 个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。(备注:子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常 的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法 是 private 类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。) Interface与abstract类的区别。 抽象类 抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用作子类的超类。抽象类是被用来创建继承层级里子类的模板。以JDK中的GenericServlet为例: 接口 接口是抽象方法的集合。如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。接口只是一种形式,接口自身不能做任何事情。以Externalizable接口为例: 什么时候使用抽象类和接口 如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。 Static class 与non static class的区别。 内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。 java多态的实现原理。继承,重写,向上转型 实现多线程的两种方法:Thread与Runable。 线程同步的方法:sychronized、lock、reentrantLock等。 git 锁的等级:方法锁、对象锁、类锁。 锁 写出生产者消费者模式。 (1)wait() / notify()方法 (2)await() / signal()方法 (3)BlockingQueue阻塞队列方法 ThreadLocal的设计理念与作用。 线程的局部变量 static put ThreadPool用法与优势。 线程池 Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。 1:本例介绍一个特殊的队列:BlockingQueue,如果BlockingQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒,同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间时才会被唤醒继续操作。 2:BlockingQueue有四个具体的实现类, ArrayBlockingQueue:规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小。其所含的对象是以FIFO(先入先出)顺序排序的。 LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定。其所含的对象是以FIFO顺序排序的。 PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。 SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的。 CountDownLatch是减计数方式,计数==0时释放所有等待的线程;CyclicBarrier是加计数方式,计数达到构造方法中参数指定的值时释放所有等待的线程。 wait()和sleep()的区别。 1:wait是Object类中,与notify和notifyAll搭配使用,sleep属于Thread类中的;1.CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。 2.CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。 2:wait的时候放弃锁,而sleep的时候不放弃锁,但是在sleep的时候,可以调用interrupt函数来中断该线程; 3:suspend将当前线程挂起,要等到线程调用resume方法,该线程才能重新执行。 foreach与正常for循环效率对比。 1:foreach在使用的过程中,会创建额外的iterator方法,而每次调用哪个hasNext,和next方法,增加了更多的操作,对于访问数组的话for的效率要高于foreach;而且在foreach中,还要检查mod_count,避免导致快速失败,所以效率上会降低,但是由此可以看出foreach是线程安全的,而for不是线程安全的 2:什么时候使用:在多线程中,则使用foreach,如果是在方法中读局部变量的操作,则使用for。 Java IO与NIO。 nio 重点 反射的作用于原理。 泛型常用特点,List能否转为List 泛型只是在编译时起作用,最后都是会被擦除的。如果你是做的一个工具类的话,都用Object和不用泛型其实是一回事,建议工具类或者方法使用泛型来定义,再调用时再决定使用什么类型。 Java与C++对比。java 去除了 c++ 一些复杂难以理解的特性,去除了指针 Java1.7与1.8新特性。 设计模式:单例、工厂、适配器、责任链、观察者等等。[设计模式]() JNI的使用。 什么是HashMap 重点: hashcode算法,默认初始16,因为0X1111,可以让数据均匀分配 可以为null,数组+链表(头插法) 1.8链表优化成红黑树 HashMap高并发下的危险 重点:1.Hashmap在插入元素过多的时候需要进行Resize,Resize的条件是HashMap.Size >= Capacity * LoadFactor(0.75f)2.Hashmap的Resize包含扩容和ReHash两个步骤,ReHash在并发的情况下可能会形成链表环。 resize的时候多个线程同时操作 e = entry next = e2 e2.next = e3 e3.next = e2 环状链表 此时再去get,程序呢陷入死循环 如何判断链表是环状结构 重点: hashset的查找时间复杂度是O(1) 最好的方法是用两个指针,一开始都在起点,但是第二个指针每次循环是两个数据节点,如果是环状的,必定两个指针会指向同一个点时间复杂度O(n),空间复制度O(1) 多线程 JVM: 内存模型以及分区,需要详细到每个区放什么。 栈,堆,方法,计数器 堆里面的分区:Eden,survival from to,老年代,各自的特点。 对象创建方法,对象的内存分配,对象的访问定位。 GC的两种判定方法:引用计数与引用链。 GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路? GC收集器有哪些?CMS收集器与G1收集器的特点。 Minor GC与Full GC分别在什么时候发生?内存满时 几种常用的内存调试工具:jmap、jstack、jconsole。 类加载的五个过程:加载、验证、准备、解析、初始化。 双亲委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。 分派:静态分派与动态分派。 总体来说java考察内容包括以下这些: 面向对象的一些基本概念:继承,多态之类的 抽象类和接口 静态类,内部类 Java集合类,同步和非同步 Java类加载机制 Java内存模型和垃圾回收算法 线程同步机制(voliate,synchronized,重入锁,threadlocal),线程间通信(wait,notify) 异常处理 多线程同步问题,生产者消费者,读者写者,哲学家就餐,用java实现 了解java中设计模式的思想,用了哪些设计模式,有什么好处 百度一面 1、给一个函数,返回 0 和 1,概率为 p 和 1-p,请你实现一个函数,使得返回 01 概率一样。2、10 亿个 url,每个 url 大小小于 56B,要求去重,内存 4G。3、把一个 bst 转化成一个双向链表。4、http 和 https 区别,https 在请求时额外的过程,https 是如何保证数据安全的。5、IP 地址子网划分。6、POST 和 GET 区别。7、硬链接和软连接区别。8、DNS 解析过程。9、kill 用法,某个进程杀不掉的原因(进入内核态,忽略 kill 信号)。10、linux 用过的命令。11、系统管理命令(如查看内存使用、网络情况)。12、管道的使用。13、grep 的使用,一定要掌握,每次都会问在文件中查找。14、shell 脚本。15、find 命令。16、awk 使用。 百度二面 1、Linux 下的一些指令,$(进程 id),$?(上一条命令退出时状态),怎么查看进程,按照内存大小,CPU 占用排序等等。(大写 M 和大写 P)。2、http 的 get 和 post 方法。3、介绍下你所了解的 epoll。4、数据库 sql 的了解程度。5、项目中遇到的问题,自己咋解决的等等。6、手写一个全排列。7、B树和B+树。8、介绍一下 Hash,怎么解决冲突。9、进程间的通信,共享内存方式的优缺点。 百度三面 1、说下你平时看的一些技术博客,书籍。2、linux 下的一些指令。3、工作中你觉得最不爽的事情是什么。4、说下你的优缺点。5、有没有想过去创业公司。6、写个 strcpy 函数。7、说说你自己的性格。8、给你一个系统(面试官好像是无人车部门的),后台的逻辑已经实现了,但是前端加载很慢,怎么检测。9、以后可能要学习很多新技术,你怎么看。10、项目中遇到的困难(提前想好,并且把实现或者优化方法说清楚)。11、系统的量级、pv、uv 等。12、应对高并发的解决办法(分布式)。13、在项目中主要负责了哪些工作。14、nginx 的负载均衡。15、分布式缓存的一致性,服务器如何扩容(哈希环)。 redis sharding 增加节点时,为什么会有key丢失?
在任意地方编辑文本,比如 ~/.ssh/wx #!/usr/bin/expect -f set port 2121 set user root set host 172.16.10.71 set password mima123456 set timeout -1 spawn ssh -p$port $user@$host expect "*assword:*" send "$password\r" interact expect eof command+,打开设置
添加依赖在build.gradle中添加 configurations { mybatisGenerator } 注意把前面的compile group改成mybatisGenerator mybatisGenerator 'org.mybatis.generator:mybatis-generator-core:1.3.6' mybatisGenerator 'mysql:mysql-connector-java:5.1.45' mybatisGenerator 'tk.mybatis:mapper:3.5.2' 设置数据库信息 在 resources 下,新建 mybatis 文件夹,并新建 config.properties 和 generatorConfig.xml,文件结构如下: # JDBC 驱动类名 jdbc.driverClassName=com.mysql.jdbc.Driver # JDBC URL: jdbc:mysql:// + 数据库主机地址 + 端口号 + 数据库名 jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8 # JDBC 用户名及密码 jdbc.username=root jdbc.password=123456 # 生成实体类所在的包 package.model=com.yy.boot.domain # 生成 mapper 类所在的包 package.mapper=com.yy.boot.dao # 生成 mapper xml 文件所在的包,默认存储在 resources 目录下 package.xml=mybatis/mapper generator.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!--MyBatis3Simple或者MyBatis3,生成的xml文件略有不同--> <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat"> <commentGenerator> <property name="suppressAllComments" value="true"></property> <property name="suppressDate" value="true"></property> <property name="javaFileEncoding" value="utf-8"/> </commentGenerator> <jdbcConnection driverClass="${driverClass}" connectionURL="${connectionURL}" userId="${userId}" password="${password}"> </jdbcConnection> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <javaModelGenerator targetPackage="${modelPackage}" targetProject="${src_main_java}"> <property name="enableSubPackages" value="true"></property> <property name="trimStrings" value="true"></property> </javaModelGenerator> <sqlMapGenerator targetPackage="${sqlMapperPackage}" targetProject="${src_main_resources}"> <property name="enableSubPackages" value="true"></property> </sqlMapGenerator> <!-- type=ANNOTATEDMAPPER表示不生成xml文件 这里我用XMLMAPPER --> <javaClientGenerator targetPackage="${mapperPackage}" targetProject="${src_main_java}" type="XMLMAPPER"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!-- sql占位符,表示所有的表 这里只用city表 --> <!--<table tableName="%">--> <!--<generatedKey column="id" sqlStatement="Mysql" identity="true" />--> <!--</table>--> <table tableName="city" domainObjectName="City" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> </context> </generatorConfiguration> 在build.gradle中添加 def getDbProperties = { def properties = new Properties() file("src/main/resources/mybatis/config.properties").withInputStream { inputStream -> properties.load(inputStream) } properties } task mybatisGenerate << { def properties = getDbProperties() ant.properties['targetProject'] = projectDir.path ant.properties['driverClass'] = properties.getProperty("jdbc.driverClassName") ant.properties['connectionURL'] = properties.getProperty("jdbc.url") ant.properties['userId'] = properties.getProperty("jdbc.username") ant.properties['password'] = properties.getProperty("jdbc.password") ant.properties['src_main_java'] = sourceSets.main.java.srcDirs[0].path ant.properties['src_main_resources'] = sourceSets.main.resources.srcDirs[0].path ant.properties['modelPackage'] = properties.getProperty("package.model") ant.properties['mapperPackage'] = properties.getProperty("package.mapper") ant.properties['sqlMapperPackage'] = properties.getProperty("package.xml") ant.taskdef( name: 'mbgenerator', classname: 'org.mybatis.generator.ant.GeneratorAntTask', classpath: configurations.mybatisGenerator.asPath ) ant.mbgenerator(overwrite: true, configfile: 'src/main/resources/mybatis/generatorConfig.xml', verbose: true) { propertyset { propertyref(name: 'targetProject') propertyref(name: 'userId') propertyref(name: 'driverClass') propertyref(name: 'connectionURL') propertyref(name: 'password') propertyref(name: 'src_main_java') propertyref(name: 'src_main_resources') propertyref(name: 'modelPackage') propertyref(name: 'mapperPackage') propertyref(name: 'sqlMapperPackage') } } }
推送远程仓库 git remote add orign git@github.com:yejunyu/javashop.git git push -u orign master 分支开发 git checkout -b v1.0 orign/master git push orign HEAD -u merge git push git merge orign v1.0 tag # 推送一个tag,记录当前的代码状态,一般是一个节点时间 git tag tag-dev-initial git push origin tag-dev-initial 打标签 git tag -a v1.01 -m "Relase version 1.01" 注解:git tag 是打标签的命令,-a 是添加标签,其后要跟新标签号,-m 及后面的字符串是对该标签的注释。 提交标签到远程仓库 git push origin --tags 注解:就像git push origin master 把本地修改提交到远程仓库一样,--tags可以把本地的打的标签全部提交到远程仓库。 删除标签 git tag -d v1.01 注解:-d 表示删除,后面跟要删除的tag名字 删除远程标签 git push origin :refs/tags/v1.01 注解:就像git push origin :branch_1 可以删除远程仓库的分支branch_1一样, 冒号前为空表示删除远程仓库的tag。 查看标签 git tag 或者 git tag -l
正常流程: git add . git commit -m "comment" git push 查看修改 已修改未暂存,代码在工作区 git diff 已暂存未提交,代码在暂存区 git diff --cached 已提交未推送,代码在本地仓库 git diff master origin/master 撤销修改 代码还没 add, 代码在工作区 git checkout . 或者 git reset --hard 已暂存未提交,代码在暂存区 git reset git checkout . 或者 git reset --hard 已提交,未推送,代码在本地仓库 git reset --hard origin/master 已经推送,代码已经在远程仓库了 所以首先要把本地仓库代码撤销,然后再强制推送 git reset --hard HEAD^ // 本地仓库撤销操作 git push -f // 强制推送到远程仓库
explain使用 explain select ... explain 还有两个变种 EXPLAIN EXTENDED SELECT…… 以上命令将执行计划“反编译”成SELECT语句, 运行SHOW WARNINGS可得到被MySQL优化器优化后的查询语句 EXPLAIN PARTITIONS SELECT…… 以上命令用于分区表的EXPLAIN命令。 结果解释 type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、index和ALL type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 一般来说,得保证查询至少达到range级别,最好能达到ref。 possible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句 key: 实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引 key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好 ref:显示索引的哪一列被使用了,如果可能的话,是一个常数 rows:MYSQL认为必须检查的用来返回请求数据的行数 Extra:关于MYSQL如何解析查询的额外信息。将在表4.3中讨论,但这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,结果是检索会很慢 extra列返回的描述的意义 Distinct:一旦MYSQL找到了与行相联合匹配的行,就不再搜索了 Not exists: MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了 Range checked for each Record(index map:#):没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一 Using filesort: 看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行 Using index: 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候 Using temporary 看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上 Where used 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题不同连接类型的解释(按照效率高低的顺序排序) system 表只有一行:system表。这是const连接类型的特殊情况 const:表中的一个记录的最大值能够匹配这个查询(索引可以是主键或惟一索引)。因为只有一行,这个值实际就是常数,因为MYSQL先读这个值然后把它当做常数来对待 eq_ref:在连接中,MYSQL在查询时,从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用 ref:这个连接类型只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好 range:这个连接类型使用索引返回一个范围中的行,比如使用>或<查找东西时发生的情况 index: 这个连接类型对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据) ALL:这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免 先看一个例子: mysql> explain select * from t_order; +----+-------------+---------+------+---------------+------+---------+------+--------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+------+---------------+------+---------+------+--------+-------+ | 1 | SIMPLE | t_order | ALL | NULL | NULL | NULL | NULL | 100453 | | +----+-------------+---------+------+---------------+------+---------+------+--------+-------+ 1 row in set (0.03 sec) 加上extended后之后: mysql> explain extended select * from t_order; +----+-------------+---------+------+---------------+------+---------+------+--------+----------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------+---------------+------+---------+------+--------+----------+-------+ | 1 | SIMPLE | t_order | ALL | NULL | NULL | NULL | NULL | 100453 | 100.00 | | +----+-------------+---------+------+---------------+------+---------+------+--------+----------+-------+ 1 row in set, 1 warning (0.00 sec) 有必要解释一下这个长长的表格里每一列的含义: | id | SELECT识别符。这是SELECT的查询序列号 || select_type | SELECT类型,可以为以下任何一种: SIMPLE:简单SELECT(不使用UNION或子查询) PRIMARY:最外面的SELECT UNION:UNION中的第二个或后面的SELECT语句 DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询 UNION RESULT:UNION 的结果 SUBQUERY:子查询中的第一个SELECT DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询 DERIVED:导出表的SELECT(FROM子句的子查询) || table | 输出的行所引用的表 || type | 联接类型。下面给出各种联接类型,按照从最佳类型到最坏类型进行排序: system:表仅有一行(=系统表)。这是const联接类型的一个特例。 const:表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const表很快,因为它们只读取一次! eq_ref:对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。 ref:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。 ref_or_null:该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。 index_merge:该联接类型表示使用了索引合并优化方法。 unique_subquery:该类型替换了下面形式的IN子查询的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。 index_subquery:该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr) range:只检索给定范围的行,使用一个索引来选择行。 index:该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。 ALL:对于每个来自于先前的表的行组合,进行完整的表扫描。 || possible_keys | 指出MySQL能使用哪个索引在该表中找到行 || key | 显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。 || key_len | 显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。 || ref | 显示使用哪个列或常数与key一起从表中选择行。 || rows | 显示MySQL认为它执行查询时必须检查的行数。多行之间的数据相乘可以估算要处理的行数。 || filtered | 显示了通过条件过滤出的行数的百分比估计值。 || Extra | 该列包含MySQL解决查询的详细信息 Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。 Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。 range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。 Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。 Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。 Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。 Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。 Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。 Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查 询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。 explain的局限 EXPLAIN不会告诉你关于触发器、 存储过程的信息或用户自定义函数对查询的影响情况。 EXPLAIN不考虑各种Cache。 EXPLAIN不能显示MySQL在执行查询时所做的优化工作。 部分统计信息是估算的, 并非精确值 MySQL 5.6之前EXPALIN只能解释SELECT操作, 其他操作需要重写为SELECT后才能查看执行计划 如果FROM子句里有子查询, 那么MySQL可能会执行这个子查询, 如果有昂贵的子查询或使用了临时表的视图, 那么EXPLAIN其实会有很大的开销。
镜像常用命令 docker search docker pull docker images --all -a 列出所有镜像 --digests 显示摘要 --quiet -q 只显示镜像ID docker rmi docker save ocker save busybox > busybox.tar docker save --output busybox.tar busybox docker load docker load < busybox.tar.gz docker load --input fedora.tar docker build docker build -t yyyejunyu/nginx:test . 容器常用命令 docker run docker run -d -p 91:80 nginx docker ps docker stop docker kill docker start docker restart docker inspect 进入容器 docker attach 784fd3b294d7 docker exec -it 容器id /bin/bash docker rm 删除所有容器 docker rm -f $(docker ps -a -q) docker export docker export red_panda > latest.tar docker export --output="latest.tar" red_panda docker import docker import nginx2.tar nginx 容器备份 1. 生成容器快照 docker commit -p 30b8f18f20b4(容器id) container-backup 会生成一个镜像 2. 打包 docker save -o ~/container-backup.tar container-backup 容器恢复 docker load -i ~/container-backup.tar docker run -d -p 80:80 container-backup
安装 # step 1: 安装必要的一些系统工具 sudo apt-get update sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common # step 2: 安装GPG证书 curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add - # Step 3: 写入软件源信息 sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" # Step 4: 更新并安装 Docker-CE sudo apt-get -y update sudo apt-get -y install docker-ce docker run hello-world 其他系统看阿里加速器 docker-ce是docker社区版 docker-compose sudo curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose docker-compose --version docker-compose version 1.19.0, build 1719ceb 第一个docker 安装好docker之后# docker run -d -p 80:80 httpd其过程可以简单的描述为: 从 Docker Hub 下载 httpd 镜像。镜像中已经安装好了 Apache HTTP Server。 启动 httpd 容器,并将容器的 80 端口映射到 host 的 80 端口。 docker-compose docker-compose.yml只需要定义配置文件即可按照配置运行容器,比docker更方便简单教程 docker 启动 nginx 一、HTTP $ docker container run \ -d \ -p 127.0.0.2:8080:80 \ --rm \ --name mynginx \ nginx 上面命令下载并运行官方的 Nginx image,默认是最新版本(latest),当前是 1.13.9。如果本机安装过以前的版本,请删掉重新安装,因为只有 1.13.9 才开始支持 server push。 上面命令的各个参数含义如下。 -d:在后台运行 -p :容器的80端口映射到127.0.0.2:8080 --rm:容器停止运行后,自动删除容器文件 --name:容器的名字为mynginx 如果没有报错,就可以打开浏览器访问 127.0.0.2:8080 了。正常情况下,显示 Nginx 的欢迎页。然后,把这个容器终止,由于--rm参数的作用,容器文件会自动删除。$ docker container stop mynginx 二、映射网页目录 网页文件都在容器里,没法直接修改,显然很不方便。下一步就是让网页文件所在的目录/usr/share/nginx/html映射到本地。 首先,新建一个目录,并进入该目录。 $ mkdir nginx-docker-demo $ cd nginx-docker-demo 然后,新建一个html子目录。 $ mkdir html 在这个子目录里面,放置一个index.html文件,内容如下。<h1>Hello World</h1>接着,就可以把这个子目录html,映射到容器的网页文件目录/usr/share/nginx/html。 $ docker container run \ -d \ -p 127.0.0.2:8080:80 \ --rm \ --name mynginx \ --volume "$PWD/html":/usr/share/nginx/html \ nginx 打开浏览器,访问 127.0.0.2:8080,应该就能看到 Hello World 了。 三、拷贝配置 修改网页文件还不够,还要修改 Nginx 的配置文件,否则后面没法加 SSL 支持。 首先,把容器里面的 Nginx 配置文件拷贝到本地。$ docker container cp mynginx:/etc/nginx .上面命令的含义是,把mynginx容器的/etc/nginx拷贝到当前目录。不要漏掉最后那个点。 执行完成后,当前目录应该多出一个nginx子目录。然后,把这个子目录改名为conf。$ mv nginx conf 现在可以把容器终止了。 $ docker container stop mynginx 四、映射配置目录 重新启动一个新的容器,这次不仅映射网页目录,还要映射配置目录。 $ docker container run \ --rm \ --name mynginx \ --volume "$PWD/html":/usr/share/nginx/html \ --volume "$PWD/conf":/etc/nginx \ -p 127.0.0.2:8080:80 \ -d \ nginx 上面代码中,--volume "$PWD/conf":/etc/nginx表示把容器的配置目录/etc/nginx,映射到本地的conf子目录。 浏览器访问 127.0.0.2:8080,如果能够看到网页,就说明本地的配置生效了。这时,可以把这个容器终止。 $ docker container stop mynginx 五、自签名证书 现在要为容器加入 HTTPS 支持,第一件事就是生成私钥和证书。正式的证书需要证书当局(CA)的签名,这里是为了测试,搞一张自签名(self-signed)证书就可以了。 下面,我参考的是 DigitalOcean 的教程。首先,确定你的机器安装了 OpenSSL,然后执行下面的命令。 $ sudo openssl req \ -x509 \ -nodes \ -days 365 \ -newkey rsa:2048 \ -keyout example.key \ -out example.crt 上面命令的各个参数含义如下。 req:处理证书签署请求。 -x509:生成自签名证书。 -nodes:跳过为证书设置密码的阶段,这样 Nginx 才可以直接打开证书。 -days 365:证书有效期为一年。 -newkey rsa:2048:生成一个新的私钥,采用的算法是2048位的 RSA。 -keyout:新生成的私钥文件为当前目录下的example.key。 -out:新生成的证书文件为当前目录下的example.crt。执行后,命令行会跳出一堆问题要你回答,比如你在哪个国家、你的 Email 等等。 其中最重要的一个问题是 Common Name,正常情况下应该填入一个域名,这里可以填 127.0.0.2。 Common Name (e.g. server FQDN or YOUR name) []:127.0.0.2回答完问题,当前目录应该会多出两个文件:example.key和example.crt。 conf目录下新建一个子目录certs,把这两个文件放入这个子目录。 $ mkdir conf/certs $ mv example.crt example.key conf/certs 六、HTTPS 配置 有了私钥和证书,就可以打开 Nginx 的 HTTPS 了。 首先,打开conf/conf.d/default.conf文件,在结尾添加下面的配置。 server { listen 443 ssl http2; server_name localhost; ssl on; ssl_certificate /etc/nginx/certs/example.crt; ssl_certificate_key /etc/nginx/certs/example.key; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; location / { root /usr/share/nginx/html; index index.html index.htm; }} 然后,启动一个新的 Nginx 容器。 $ docker container run \ --rm \ --name mynginx \ --volume "$PWD/html":/usr/share/nginx/html \ --volume "$PWD/conf":/etc/nginx \ -p 127.0.0.2:8080:80 \ -p 127.0.0.2:8081:443 \ -d \ nginx 上面命令中,不仅映射了容器的80端口,还映射了443端口,这是 HTTPS 的专用端口。 打开浏览器,访问 https://127.0.0.2:8081/ 。因为使用了自签名证书,浏览器会提示不安全。不要去管它,选择继续访问,应该就可以看到 Hello World 了。 至此,Nginx 容器的 HTTPS 支持就做好了。有了这个容器,下一篇文章,我就来试验 HTTP/2 的 server push 功能。
ADD 复制文件 ADD 'src' 'dest'ADD microservice-discovery-eureka-0.0.1-SNAPSHOT.jar app.jar src必须在构建的上下文内,不能使用例如:ADD ../somethine /something 这样的命令,因为docker build 命令首先会将上下文路径和其子目录发送到docker daemon。 如果src是一个URL,同时dest不以斜杠结尾,dest将会被视为文件,src对应内容文件将会被下载到dest。 如果src是一个URL,同时dest以斜杠结尾,dest将被视为目录,src对应内容将会被下载到dest目录。 如果src是一个目录,那么整个目录下的内容将会被拷贝,包括文件系统元数据。 如果文件是可识别的压缩包格式,则docker会自动解压。 ARG 设置构建参数 ARG指令用于设置构建参数,类似于ENV。和ARG不同的是,ARG设置的是构建时的环境变量,在容器运行时是不会存在这些变量的。 ARG <name>[=<default value>]ARG user1=someuser CMD 容器启动命令 CMD指令用于为执行容器提供默认值。每个Dockerfile只有一个CMD命令,如果指定了多个CMD命令,那么只有最后一条会被执行,如果启动容器的时候指定了运行的命令,则会覆盖掉CMD指定的命令。 CMD echo "This is a test." | wc - COPY 复制文件 复制本地端的src到容器的dest。COPY指令和ADD指令类似,COPY不支持URL和压缩包。 COPY <src>... <dest> ENTRYPOINT 入口点 ENTRYPOINT和CMD指令的目的一样,都是指定Docker容器启动时执行的命令,可多次设置,但只有最后一个有效。ENTRYPOINT不可被重写覆盖。 ENTRYPOINT command param1 param2 ENV 设置环境变量 ENV <key> <value>ENV JAVA_HOME /path/to/java EXPOSE 声明暴露的端口 EXPOSE指令用于声明在运行时容器提供服务的端口,格式为:EXPOSE <port> [<port>...] # 声明暴露一个端口示例 EXPOSE port1 # 相应的运行容器使用的命令 docker run -p port1 image # 也可使用-P选项启动 docker run -P image # 声明暴露多个端口示例 EXPOSE port1 port2 port3 # 相应的运行容器使用的命令 docker run -p port1 -p port2 -p port3 image # 也可指定需要映射到宿主机器上的端口号 docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image FROM 指定基础镜像 支持三种格式: FROM <image> FROM <image>:<tag> FROM <image>@<digest> LABEL 为镜像添加元数据(取代MAINTAINER) LABEL "com.example.vendor"="ACME Incorporated" LABEL com.example.label-with-value="foo" LABEL version="1.0" LABEL description="This text illustrates \ that label-values can span multiple lines." RUN 执行命令 RUN <command> RUN ["executable", "param1", "param2"]RUN <command> 在shell终端中运行,在Linux中默认是/bin/sh -c ,在Windows中是 cmd /s /c ,使用这种格式,就像直接在命令行中输入命令一样。 RUN ["executable", "param1", "param2"] 使用exec执行,这种方式类似于函数调用。指定其他终端可以通过该方式操作,例如:RUN ["/bin/bash", "-c", "echo hello"] ,该方式必须使用双引号[“]而不能使用单引号[‘],因为该方式会被转换成一个JSON 数组。 VOLUME 指定挂载点 该指令使容器中的一个目录具有持久化存储的功能,该目录可被容器本身使用,也可共享给其他容器。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。格式为: VOLUME ["/data"] FROM nginx VOLUME /tmp # 容器ID是第一个容器的ID,镜像是第二个容器所使用的镜像。 docker run -volume-from 容器ID 镜像名称 WORKDIR 指定工作目录 WORKDIR /path/to/workdir切换目录指令,类似于cd命令,写在该指令后的RUN,CMD以及ENTRYPOINT指令都将该目录作为当前目录,并执行相应的命令。
关闭图形界面 切换方法 # 命令模式 systemctl set-default multi-user.target # 图形模式 systemctl set-default graphical.target 配置yum源 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo yum makecache 关闭防火墙 systemctl stop firewalld & systemctl disable firewalld 关闭swap # 临时关闭 swapoff -a # 永久关闭 /etc/fstab,找到swap,注释重启 或 sed -i '/ swap / s/^/#/' /etc/fstab 关闭安全组 setenforce 0 docker和docker-compose(略)
转载:http://www.jianshu.com/p/2f3be7781451# 序 Python易用,但用好却不易,其中比较头疼的就是包管理和Python不同版本的问题,特别是当你使用Windows的时候。为了解决这些问题,有不少发行版的Python,比如WinPython、Anaconda等,这些发行版将python和许多常用的package打包,方便pythoners直接使用,此外,还有virtualenv、pyenv等工具管理虚拟环境。 个人尝试了很多类似的发行版,最终选择了Anaconda,因为其强大而方便的包管理与环境管理的功能。该文主要介绍下Anaconda,对Anaconda的理解,并简要总结下相关的操作。 Anaconda概述 Anaconda是一个用于科学计算的Python发行版,支持 Linux, Mac, Windows系统,提供了包管理与环境管理的功能,可以很方便地解决多版本python并存、切换以及各种第三方包安装问题。Anaconda利用工具/命令conda来进行package和environment的管理,并且已经包含了Python和相关的配套工具。 这里先解释下conda、anaconda这些概念的差别。conda可以理解为一个工具,也是一个可执行命令,其核心功能是包管理与环境管理。包管理与pip的使用类似,环境管理则允许用户方便地安装不同版本的python并可以快速切换。Anaconda则是一个打包的集合,里面预装好了conda、某个版本的python、众多packages、科学计算工具等等,所以也称为Python的一种发行版。其实还有Miniconda,顾名思义,它只包含最基本的内容——python与conda,以及相关的必须依赖项,对于空间要求严格的用户,Miniconda是一种选择。 进入下文之前,说明一下conda的设计理念——conda将几乎所有的工具、第三方包都当做package对待,甚至包括python和conda自身!因此,conda打破了包管理与环境管理的约束,能非常方便地安装各种版本python、各种package并方便地切换。 Anaconda的安装 Anaconda的下载页参见官网下载,Linux、Mac、Windows均支持。 安装时,会发现有两个不同版本的Anaconda,分别对应Python 2.7和Python 3.5,两个版本其实除了这点区别外其他都一样。后面我们会看到,安装哪个版本并不本质,因为通过环境管理,我们可以很方便地切换运行时的Python版本。(由于我常用的Python是2.7和3.4,因此倾向于直接安装Python 2.7对应的Anaconda) 下载后直接按照说明安装即可。这里想提醒一点:尽量按照Anaconda默认的行为安装——不使用root权限,仅为个人安装,安装目录设置在个人主目录下(Windows就无所谓了)。这样的好处是,同一台机器上的不同用户完全可以安装、配置自己的Anaconda,不会互相影响。 对于Mac、Linux系统,Anaconda安装好后,实际上就是在主目录下多了个文件夹(~/anaconda)而已,Windows会写入注册表。安装时,安装程序会把bin目录加入PATH(Linux/Mac写入~/.bashrc,Windows添加到系统变量PATH),这些操作也完全可以自己完成。以Linux/Mac为例,安装完成后设置PATH的操作是 # 将anaconda的bin目录加入PATH,根据版本不同,也可能是~/anaconda3/bin echo 'export PATH="~/anaconda2/bin:$PATH"' >> ~/.bashrc # 更新bashrc以立即生效 source ~/.bashrc 配置好PATH后,可以通过which conda或conda --version命令检查是否正确。假如安装的是Python 2.7对应的版本,运行python --version或python -V可以得到Python 2.7.12 :: Anaconda 4.1.1 (64-bit),也说明该发行版默认的环境是Python 2.7。 Conda的环境管理 Conda的环境管理功能允许我们同时安装若干不同版本的Python,并能自由切换。对于上述安装过程,假设我们采用的是Python 2.7对应的安装包,那么Python 2.7就是默认的环境(默认名字是root,注意这个root不是超级管理员的意思)。 假设我们需要安装Python 3.4,此时,我们需要做的操作如下: # 创建一个名为python34的环境,指定Python版本是3.4(不用管是3.4.x,conda会为我们自动寻找3.4.x中的最新版本) conda create --name python34 python=3.4 # 安装好后,使用activate激活某个环境 activate python34 # for Windows source activate python34 # for Linux & Mac # 激活后,会发现terminal输入的地方多了python34的字样,实际上,此时系统做的事情就是把默认2.7环境从PATH中去除,再把3.4对应的命令加入PATH # 此时,再次输入 python --version # 可以得到`Python 3.4.5 :: Anaconda 4.1.1 (64-bit)`,即系统已经切换到了3.4的环境 # 如果想返回默认的python 2.7环境,运行 deactivate python34 # for Windows source deactivate python34 # for Linux & Mac # 删除一个已有的环境 conda remove --name python34 --all 用户安装的不同python环境都会被放在目录~/anaconda/envs下,可以在命令中运行conda info -e查看已安装的环境,当前被激活的环境会显示有一个星号或者括号。 说明:有些用户可能经常使用python 3.4环境,因此直接把~/anaconda/envs/python34下面的bin或者Scripts加入PATH,去除anaconda对应的那个bin目录。这个办法,怎么说呢,也是可以的,但总觉得不是那么elegant…… 如果直接按上面说的这么改PATH,你会发现conda命令又找不到了(当然找不到啦,因为conda在~/anaconda/bin里呢),这时候怎么办呢?方法有二:1. 显式地给出conda的绝对地址 2. 在python34环境中也安装conda工具(推荐)。 Conda的包管理 Conda的包管理就比较好理解了,这部分功能与pip类似。 例如,如果需要安装scipy: # 安装scipy conda install scipy # conda会从从远程搜索scipy的相关信息和依赖项目,对于python 3.4,conda会同时安装numpy和mkl(运算加速的库) # 查看已经安装的packages conda list # 最新版的conda是从site-packages文件夹中搜索已经安装的包,不依赖于pip,因此可以显示出通过各种方式安装的包 conda的一些常用操作如下: # 查看当前环境下已安装的包 conda list # 查看某个指定环境的已安装包 conda list -n python34 # 查找package信息 conda search numpy # 安装package conda install -n python34 numpy # 如果不用-n指定环境名称,则被安装在当前活跃环境 # 也可以通过-c指定通过某个channel安装 # 更新package conda update -n python34 numpy # 删除package conda remove -n python34 numpy 前面已经提到,conda将conda、python等都视为package,因此,完全可以使用conda来管理conda和python的版本,例如 # 更新conda,保持conda最新 conda update conda # 更新anaconda conda update anaconda # 更新python conda update python # 假设当前环境是python 3.4, conda会将python升级为3.4.x系列的当前最新版本 补充:如果创建新的python环境,比如3.4,运行conda create -n python34 python=3.4之后,conda仅安装python 3.4相关的必须项,如python, pip等,如果希望该环境像默认环境那样,安装anaconda集合包,只需要: # 在当前环境下安装anaconda包集合 conda install anaconda # 结合创建环境的命令,以上操作可以合并为 conda create -n python34 python=3.4 anaconda # 也可以不用全部安装,根据需求安装自己需要的package即可 设置国内镜像 如果需要安装很多packages,你会发现conda下载的速度经常很慢,因为Anaconda.org的服务器在国外。所幸的是,清华TUNA镜像源有Anaconda仓库的镜像,我们将其加入conda的配置即可: # 添加Anaconda的TUNA镜像 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ # TUNA的help中镜像地址加有引号,需要去掉 # 设置搜索时显示通道地址 conda config --set show_channel_urls yes 执行完上述命令后,会生成~/.condarc(Linux/Mac)或C:\Users\USER_NAME\.condarc文件,记录着我们对conda的配置,直接手动创建、编辑该文件是相同的效果。 总结 Anaconda具有跨平台、包管理、环境管理的特点,因此很适合快速在新的机器上部署Python环境。总结而言,整套安装、配置流程如下: 下载Anaconda、安装 配置PATH(bashrc或环境变量),更改TUNA镜像源 创建所需的不用版本的python环境 Just Try! cheat-sheet 下载:Conda cheat sheet * 参考资料 Anaconda Homepage Anaconda Documentation Conda Docs