目录html
# web 服务器中,部署的方式大体相似,主要就是使用Nginx 实现分流,转发,负载均衡,以及分担服务器的压力。Nginx部署简单,内存消耗少,成本低。Nginx既能够作正向代理,也能够作反向代理 #正向代理:请求通过代理服务器从局域网发出,而后到达互联网上的服务器 特色:服务端不知道真正的客户端是谁 做用:1.访问原本没法访问的服务器 2.加速访问服务器 3.cache做用(正向/反向都是用缓存技术):若是用户A访问服务器B上的某数据J以前,已经有人经过代理服务器获得数据J,那么代理服务器就会把数据保存一段时间,这是代理服务器就会把缓存的数据直接发送给用户A,专业术语(cache命中) # 反向代理:请求从互联网出发,先进入代理服务器,在转发给局域网内的服务器 特色:客户端并不知道真正的服务端是谁 做用:1.保护和隐藏原始资源服务器:(如图2.1)用户A始终认为他访问的是原始服务器B而不是代理服务器Z,但实际上反向代理服务器接收用户A的应答,从原始资源服务器B中取得用户A的需求资源,而后发送给用户A,因为防火墙的做用,只容许代理服务器A访问原始资源服务器B,尽管这个虚拟环境下,防火墙和反向代理的共同做用保护了原始资源服务器B,可是用户A不知道 2.负载均衡:(如图2.2)当反向代理服务器不知一个的时候,咱们甚至能够把他们作成集群,让不一样的代理服务器Z去应答不一样的用户,而后发送不一样用户须要的资源 固然反向代理服务器像正向代理服务器同样拥有CACHE的做用,它能够缓存原始资源服务器B的资源,而不是每次都要向原始资源服务器B请求数据,特别是一些静态的数据,好比图片和文件,若是这些反向代理服务器可以作到和用户X来自同一个网络,那么用户X访问反向代理服务器X,就会获得很高质量的速度。(CDN的核心技术就是用反向代理) 反向代理的结论:与正向代理正好相反,对于客户端而言它就是原始服务器,而且任何特别的设置。客户端向反向代理的命名空间发送普通请求,接着反向代理将判断向原始服务器转交请求,并将获取的内容返回给客户端,就像这些内容原本就是它本身的 基本上,网上作正反向代理的程序不少,能作正向代理的软件大部分也能够作反向代理。开源软件中最流行的就是squid,既能够作正向代理,也有不少人用来作反向代理的前端服务器。另外MS ISA也能够用来在WINDOWS平台下作正向代理。反向代理中最主要的实践就是WEB服务,近些年来最火的就是Nginx了。网上有人说NGINX不能作正向代理,实际上是不对的。NGINX也能够作正向代理,不过用的人比较少了。 #区别:正向代理的对象是客户端,反向代理的对象是服务端 # 透明代理:客户端根本不须要知道有代理服务器的存在,它改编了你的request fields(报文),并会传送真实IP,加密的透明代理是属于匿名代理,意思是不用设置代理了实践的例子:不少公司使用行为管理软件 用户A和用户B并不知道行为管理设备充当透明代理行为,当用户A或用户B向服务器A或服务器B提交请求的时候,透明代理设备根据自身策略拦截并修改用户A或B的报文,并做为实际的请求方,向服务器A或B发送请求,当接收信息回传,透明代理再根据自身的设置把容许的报文发回至用户A或B,如图(3.1),若是透明代理设置不容许访问服务器B,那么用户A或者用户B就不会获得服务器B的数据。
#进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫作程序,进程是系统资源分配的最小单位,进程拥有本身独立的内存空间,因此进程间数据不共享,开销大 # 多进程的使用使用场景:适合在CPU密集型操做(CPU操做指令比较多,好比:浮点运算) 进程:并行(同一时刻多个任务同时运行) 实现并行的库:mulitprocessing #线程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在,一个进程至少有一个线程,多核线程共享内存(数据共享,共享全局变量),从而极大的提升了程序的运行效率 # 多线程的使用场景:适合在IO密集型操做(读写数据操做比较多的,好比爬虫) 线程:并发(在同一时间段内多个任务都在运行,可是不会在同一时刻同时运行,存在交替执行的状况) 实现并发的库:threading #协程:是一种用户态的轻量级线程,协程的调度彻底由用户控制,协程拥有本身的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其余地方,在切回来的时候,恢复先前保存的寄存器上下问和栈,直接操做栈则基本没有内核切换的开销,能够不加锁的访问全局变量,因此上下文的切换很是快
线程是非独立的,同一个进程里面线程是数据共享的,当各个线程访问数据资源时,会出现竞争状态时,数据几乎同步会被多个线程占用,形成数据混乱,形成线程不安全,就是多线程竞争
# 怎么解决多线程竞争问题?--锁 # 锁的好处:确保了某段关键代码(共享数据资源)只能由一个线程从头至尾完整地执行,能够解决多线程资源竞争下的原子操做问题 #锁的坏处:组织了多线程并发执行,包含锁的偶段代码实际只能以单线程模式执行,效率就大大地降低了 锁的致命问题:死锁 解释一下什么是锁? #锁(Lock):Python提供的对线程控制的对象。有互斥锁,死锁,可重入锁 死锁:若是若干个子线程在系统资源竞争时,都在等待对方某部分资源接触占用状态,结果是都不肯意先解锁,程序就没法执行下去,这就是死锁(程序并无挂掉) GIL锁:全局解释器锁(只有在Cpython中里面有) 做用:限制多线程同时执行,保证同一时间只有一个线程执行,因此Cpython里面的多线程实际上是伪多线程,因此python里面经常用协程技术来代替多线程, #进程和线程的切换由系统决定的,而协程是由哦咱们本身决定的,而模块gevent下切换是遇到耗时操做才会切换到 三者的关系:进程里面有线程,线程里面有协程
每一个对象对应于一个可称为“互斥锁”的标记,这个标记用来包保证在任一时刻只能由一个线程访问该对象 同一个进程中的多线程之间是共享系统资源的,多个线程同时对一个对象进行操做,一个线程操做还没有结束,另外一个已经对其进行操做,致使最终结果出现错误,慈此时须要对被操做对象添加互斥u哦,保证每一个线程对该对象的操做都获得正确的结果
内存:计算机内存储器, 硬盘是属于计算机外存储器, CPU一般只和内存交换户据,断电后数据会丢失 硬盘首先读取这个文件,将数字发送到内存中,内存将数据发送到CPU中进行数据处理,处理完成后发送到内存,再发送到硬盘中展现
# 1. 在浏览器中输入URL URL: 统一资源定位符,用于定位互联网的资源,主要包括:协议,网络地址,资源路径 # 2. 域名解析 浏览器不知道baidu.com是什么东西,须要查找百度所在服务器的IP地址,才能找到目标 #为何咱们要使用域名而不是直接访问IP地址?(很简单:很差记) 域名解析的流程: 浏览器缓存--浏览器有百度DNS则会缓存DNS,若没有转至下面 系统缓存--从Host文件中查找对应的百度域名和IP,若没有转至下面 路由器缓存--通常路由器也会缓存域名信息 ISP DNS缓存 -- 例如到电信的DNS上查找缓存,若是没有找到则会向 根域名服务器查找域名对应IP # 3. 在本地dns服务器向顶级域.com发起请求,顶级域接收到请求,告诉本地dns服务器域名的解释服务器的地址,并非告诉本地服务器域名和IP地址的对应关系 # 4. 本地dns服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不只要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,能够直接返回结果,加快网络访问。 # 5. IP地址返回给本地服务器处理请求,服务器通常都会安装一个用于接收处理请求的应用—web server常见的web server产品有apache、nginx等而且决定采用哪一种方式来处理这个请求,读取请求,而后造成html响应。 # 6. 客户端浏览器开始处理,解析渲染页面可视化
返回的结果集选取了两个表中全部相匹配的数据,舍弃了不匹配的数据。因为内链接是从结果表中删除与其余链接表中没有匹配的全部行,因此内链接可能会形成信息的丢失。内链接语法以下: select fieldlist from table1 [inner] join table2 on table1.column = table2.column 外链接不只包含符合链接条件的行,还包含左表(左链接时)、右表(右链接时)或两个边接表(全外链接)中的全部数据行。SQL外链接共有三种类型:左外链接(关键字为LEFT OUTER JOIN)、右外链接(关键字为RIGHT OUTER JOIN)和全外链接(关键字为FULL OUTER JOIN)。外链接的用法和内链接同样,只是将INNER JOIN关键字替换为相应的外链接关键字便可。 内链接只显示符合链接条件的记录,外链接除了显示符合条件的记录外,还显示表中的记录,例如,若是使用左外链接,还显示左表中的记录。 SELECT XXX FROM XXX LEFT [OUTER] JOIN XXX ON XXX
在具体描述这几种数据类型以前,咱们先经过一张图了解下Redis内部内存管理中是如何描述这些不一样数据类型的: 首先Redis内部使用一个redisObject对象来表示全部的key和value,redisObject最主要的信息如上图所示: type表明一个value对象具体是何种数据类型, encoding是不一样数据类型在redis内部的存储方式, 好比:type=string表明value存储的是一个普通字符串,那么对应的encoding能够是raw或者是int,若是是int则表明实际redis内部是按数值型类存储和表示这个字符串的,固然前提是这个字符串自己能够用数值表示,好比:"123" "456"这样的字符串。 这里须要特殊说明一下vm字段,只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的,该功能会在后面具体描述。经过上图咱们能够发现Redis使用redisObject来表示全部的key/value数据是比较浪费内存的,固然这些内存管理成本的付出主要也是为了给Redis不一样数据类型提供一个统一的管理接口 #String #Hash #List #Set #Sorted set #pub/sub #Transactions
#REST: 是一种架构风格,一种Web Service能够知足REST的几个条件,一般就成这个系统是Resrful的 #条件:C/S架构,无状态,能够cache,分层 # REST的三要素: 1.惟一的天然标识 2.简单的方法 3.必定的表达方式 REST 是以 资源 为中心, 名词即资源的地址, 动词即施加于名词上的一些有限操做, 表达是对各类资源形态的抽象. 以HTTP为例, 名词即为URI(统一资源标识), 动词包括POST, GET, PUT, DELETE等(还有其它不经常使用的2个,因此 整个动词集合是有限的), 资源的形态(如text, html, image, pdf等) RPC与REST的区别 RPC:通常采用TCP通讯协议,性能高,灵活性低 以动词为中心的(就是一些方法:get、post) 当你要须要加入新功能时,你必需要添加更多的动词, 这时候服务器端须要实现 相应的动词(方法), 客户端须要知道这个新的动词并进行调用. REST:通常采用HTTP通讯协议,性能相对较低,灵活性高 以名词为中心(一些资源的地址:URL) 假使我请求的是 hostname/index/, 不管这个URI对应的服务怎么变化,客户端是无需 关注和更新的,而这种变化对客户端也是透明的. 至于其它的区别,如对实现语言的依赖, 耦合性等,这些都是上面提到的这个根本区别所衍生的. 当你天天使用HTTP冲浪时,你都在使用 REST 与远程的服务器进行亲密接触. 当你使用Gtalk和同事朋友沟通时,你则是在享受着 RPC 的便利.
HTTPS和HTTP的区别主要以下: 1.HTTPS须要ca申请证书,通常免费证书较少,所以须要必定费用 2.HTTP是超文本传输协议,信息是铭文传输,HTTPS则是具备安全性的ssl加密传输协议 3.HTTP和HTTPS使用的是彻底不一样的连接方式,用的端口不同,前者是80 后者是443 4.http的连接很简单是无状态的,HTTPS协议是SSL+http协议构建的能够进行加密传输,身份认证的网络协议,比http安全 HTTP属于TCP/IP模型中的运用层协议,因此通讯的过程实际上是对应数据的入栈和出栈。 1、HTTP和HTTPS的基本概念 HTTP:是互联网上应用最为普遍的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可使浏览器更加高效,使网络传输减小。 HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,所以加密的详细内容就须要SSL。 HTTPS协议的主要做用:1.创建一个信息安全通道,来保证数据传输的安全;2.确认网站的真实性 HTTP特色:1.支持客户/服务器模式(C/S) 2.简单快速:客户端请求服务时,只须要发送请求方法和路径,请求方法有GET/POST/HEAD,每种防范规定了客户与服务器练习的类型不一样,因为HTTP协议简单,使得http服务器的程序规模小,通讯速度快 3.灵活:http容许传输任意类型的数据对象 4.无链接:含义是显示每次连接只能处理一个请求,服务器处理完客户端的请求,并接受到客户的应答后,即断开连接,节省传输时间 5.无状态:http协议就是无状态协议,无状态是指协议对于事物处理没有记忆功能,缺乏状态意味着若是后续处理须要前面的信息,则它必须重传,这样可能致使每次链接传送的数据量增大。另外一方面,在服务器不须要先前信息时它的应答就较快 HTTP工做流程: 第一步:创建TCP/IP链接,客户端与服务器经过Socket三次握手进行链接 第二步:客户端向服务端发起HTTP请求(例如:POST/login.html http/1.1) 第三步:客户端发送请求头信息,请求内容,最后会发送一空白行,标示客户端请求完毕 第四步:服务器作出应答,表示对于客户端请求的应答,例如:HTTP/1.1 200 OK 第五步:服务器向客户端发送应答头信息 第六步:服务器向客户端发送请求头信息后,也会发送一空白行,标示应答头信息发送完毕,接着就以Content-type要求的数据格式发送数据给客户端 第七步:服务端关闭TCP链接,若是服务器或者客户端增Connection:keep-alive就表示客户端与服务器端继续保存链接,在下次请求时能够继续使用此次的链接 HTTPS的特色:HTTPS是HTTP协议的修改,它加密数据并确保其机密性。其配置可保护用户在与网站交互时免于窃取我的信息和计费数据。 优势:提供优质的保密的信息,保证了用户户据的安全性,同时必定成度上保护了服务端,使用恶意攻击和假装数据的成本大大提升 缺点:1.https的技术门槛高 2. 大多数网站并不关心数据的安全性和保密性 3. https加剧了服务器的复古但 4.http网站任然大鬼哦没的使用 HTTPS的工做流程 第一步:客户使用https的URL访问Web服务器,要求与Web服务器创建SSL链接。 第二步:Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。 第三步:客户端的浏览器与Web服务器开始协商SSL链接的安全等级,也就是信息加密的等级。 第四步:客户端的浏览器根据双方赞成的安全等级,创建会话密钥,而后利用网站的公钥将会话密钥加密,并传送给网站。 第五步:Web服务器利用本身的私钥解密出会话密钥。 第六步:Web服务器利用会话密钥加密与客户端之间的通讯。
一下为http通过的几层模型前端
栈## 栈是一种动态集合,它是一种LIFO(last in first out后进先出)结构 栈的实现: (1)数组 (2)链表 栈要记录的数据: (1)栈顶位置top 注意这个top有两种理解方式,一种是表示栈的最后一个数据的位置,另外一种是表示栈的最后一个数据的下一个位置,这两种理解对栈的操做代码有必定的影响 (2)栈最大大小size 栈的操做: (1)STACK_EMPTY():判断栈是否为空 (2)PUSH(X):向栈中添加一个值,注意栈是否为满的 (3)POP():从栈中弹出一个值,注意栈是否为空 栈的简要实现:github栈 栈的应用: (1)括号匹配问题 队列## 与栈不一样,它是一种FIFO(first in first out先进先出)结构 队列的实现: (1)数组 (2)链表 队列要记录的数据: (1)队首位置head:第一个元素位置 (2)队尾位置tail:下一个元素要插入的位置(最后一个元素的下一个位置) (3)队列最大大小size 队列的操做: (1)ENQUEUE(x):入队 (2)DEQUEUE():出队 (3)EMPTY():队列为空,head=tail (4)FULL():队列为满,head=(tail+1)%size 队列的简要实现:github队列 队列的应用: (1) 链表## 与数组中元素地址连续不一样,链表中两个元素地址不必定连续,而是由专门的一个指针指明该元素的后一个(前一个)元素的地址。 链表种类: (1)单向链表:只有指向后一个元素的指针 (2)双向链表:有指向后一个和前一个元素的指针 (3)循环链表:链表内存在一个环 链表节点(Node)记录的数据: (1)要存储的数据data (2)下一个节点地址Node* next (3)如果双向链表还要存储前一个节点地址Node prev 链表(LinkedList)记录的数据: (1)链表的头指针Node head (2)可能还记录链表的尾指针 Node* tail 链表的操做: (1)SEARCH(x):链表的搜索 (2)INSERT(i,x):链表的插入,在第i个位置插入x (3)DELETE(x):链表的删除 哨兵(sentinel): 为了减小边界条件的判断(是否为空链表等等),引入哨兵,使得链表永远不为“空”。 指针和对象的实现: 有些语言好比Java没有指针(C中就存在指针),这时咱们须要考虑指针的替代实现方式。 (1)用二维数组表示指针 咱们能够设置一个n*3的数组记录n个节点,那个3就表示存储的数据、前一个元素的坐标(index)和后一个元素的坐标。 (2)用一维数组表示指针 树## 树的种类: (1)二叉树 二叉树要存储4个数据,分别是节点携带的信息和其父节点、左右子节点的指针。 (2)分支无限制的有根树: 上面二叉树每一个节点最多有两个子节点,而分支无限制的有根数则没有这个限制,可能有3个、5个甚至更多子节点。因此存储这种数据结构的问题在于咱们事先并不知道应该设置多少个child指针,若设置的少了不能知足要求,设置的过多又会浪费空间。因此这里提出一种新的描述这种数据结构的方法——左孩子右兄弟表示法,这种方法每一个节点设置3个指针:父指针、从左数第一个孩子的指针、其右侧相邻的兄弟指针,以下图所示 堆## 堆其实是以数组形式存储的二叉树 堆须要存储的数据: (1)数组的大小max-size (2)堆元素个数size,这里size要小于max-size 堆中元素经过坐标来肯定父节点、左右子节点,具体来讲: 一个节点i的父节点:[i/2] 一个节点i的左子节点:[i2] 一个节点i的右子节点:[i2+1] 堆的分类: (1)最大堆 知足全部节点都比其父节点值小(小于等于)的堆 A[i/2]>=A[i] (2)最小堆 知足全部节点都比其父节点值大(大于等于)的堆 A[i/2]<=A[i] 堆的操做: (1)维护堆的性质(HEAPIFY) 这里指维护最大堆或最小堆的性质。假设一个数组中下标为i的节点的子节点知足最大(小)堆性质,但自身不必定知足这个性质,这时就须要HEAPIFY,具体来讲是要比较这个节点和其两个子节点的大小,将其中的大(小)的和该节点位置交换,这样这个节点及其两个子节点就知足最大(小)堆的性质了,可是可能交换后子节点不知足堆的性质,因此这里要递归调用HEAPIFY,直到达到最下层节点,这样就维护了堆的性质。HEAPIFY耗时O(lgn) (2)建堆(BUILD-HEAPIFY) 从中间那个元素开始到第一个元素,逐一调用HEAPIFY函数,便可完成建堆。 逐一从中间那个元素开始递减而不是从第一个元素递增,这时为了保证每次调用HEAPIFY都能保证该节点的子节点都知足最大(小)堆的性质,不然没法调用HEAPIFY。中间那个元素是第一个可能不知足最大(小)堆性质的节点,因此从这里开始维护(HEAPIFY)。一个建堆的例子以下所示:[5,3,17,10,84,19,6,22,9] 建堆 建堆的指望时间为O(n) 堆的应用: (1)堆排序(详见排序算法) (2)优先队列
## python中实现双链表,栈,队列 1.双链表 class Node(object): def __init__(self, value=None): self._prev = None self.data = value self._next = None def __str__(self): return "Node(%s)" %s self.data class DoubleLinkedlist(object): def __init__(self): self._head = None() def insert(self, value): element = Node(value) element._next = self._head self._head._prev = element self._head = element def search(self, value): if not self._head._next: raise ValueError("the linked list is empty") temp = self._head while temp.data != value: temp = temp._next return temp def delete(self, value): element = self.search(value) if not element: raise ValueError('delete error: the value not found') element._prev._next = element._next element._next._prev = element._prev return element.data def __str__(self): values = [] temp = self._head while temp and temp.data: values.append(temp.data) temp = temp._next return "DoubleLinkedList(%s)"%values 2.栈 class Stack(object): def __init__(self): self._top = 0 self._stack = [] def put(self, data): self._stack.insert(self._top, data) self._top += 1 def pop(self): if self.isEmpty(): raise ValueError('stack 为空') self._top -= 1 data = self._stack[self._top] return data def isEmpty(self): if self._top == 0: return True else: return False def __str__(self): return "Stack(%s)"%self._stack 3.队列 class Queue(object): def __init__(self, max_size=float('inf')): self._max_size = max_size self._top = 0 self._tail = 0 self._queue = [] def put(self, value): if self.isFull(): raise ValueError("the queue is full") self._queue.insert(self._tail, value) self._tail += 1 def pop(self): if self.isEmpty(): raise ValueError("the queue is empty") data = self._queue.pop(self._top) self._top += 1 return data def isEmpty(self): if self._top == self._tail: return True else: return False def isFull(self): if self._tail == self._max_size: return True else: return False def __str__(self): return "Queue(%s)"%self._queue
Ajax = 异步 JavaScript 和XML。 Ajax是一种用于建立快速动态网页的技术。 经过在后台与服务器进行少许数据交换,Ajax可使网页实现异步更新。这意味着能够在不从新加载整个网页的状况下,对网页的某部分进行更新。 传统的网页(不使用 Ajax)若是须要更新内容,必需重载整个网页面。 发送请求的四个步骤: (1)初始化XMLHTTPRequest对象。 (2)为XMLHTTPRequest对象指定一个回调函数,用于对返回结果进行处理。 (3)建立一个与服务器的链接。 (4)向服务器发送请求。
经过软件模拟具备湾镇反硬件系统功能的,运行在一个彻底隔离环境中的完整的计算机系统
权重java
mongdo 使用内存上限python
方法一: 1. a = a+b 2. b = a-b 3. a = a-b 方法二: 1. a = a^b 2. b =b^a 3. a = a^b 方法三: 1. a,b = b,a
print 方法默认调用sys.stdout.write 方法,即往控制台打印字符串。
1. class Parent(object): 2. x = 1 3. class Child1(Parent): 4. pass 5. class Child2(Parent): 6. pass 7. print Parent.x, Child1.x, Child2.x 8. Child1.x = 2 9. print parent.x, Child1.x, Child2.x 10. parent.x = 3 11. print Parent.x, Child1.x, Child2.x 结果为: 1 1 1 #继承自父类的类属性x,因此都同样,指向同一块内存地址。 1 2 1 #更改Child1,Child1 的x 指向了新的内存地址。 3 2 3 #更改Parent,Parent 的x 指向了新的内存地址。
在Python3 中,input()获取用户输入,不论用户输入的是什么,获取到的都是字符串类型的。 在Python2 中有raw_input()和input(), raw_input()和Python3 中的input()做用是同样的, input()输入的是什么数据类型的,获取到的就是什么数据类型的。
1. A0 = dict(zip(('a','b','c','d','e'),(1,2,3,4,5))) 2. A1 = range(10) 3. A2 = [i for i in A1 if i in A0] 4. A3 = [A0[s] for s in A0] 5. A4 = [i for i in A1 if i in A3] 6. A5 = {i:i*i for i in A1} 7. A6 = [[i,i*i] for i in A1]\ ............ 结果是: 1. A0 = {'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4} 2. A1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 3. A2 = [] 4. A3 = [1, 3, 2, 5, 4] 1. A4 = [1, 2, 3, 4, 5] 2. A5 = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81} 3. A6 = [[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36],[7, 49],[8, 64], [9,81]]
目前再python3版本种xrange已经被取消mysql
二者用法相同,不一样的是range 返回的结果是一个列表,而xrange 的结果是一个生成器,前者是直接开辟一块内存空间来保存列表,后者是边循环边使用,只有使用时才会开辟内存空间,因此当列表很长时,使用xrange 性能要比range 好。linux
1. l = [] 2. for i in xrange(10): 3. l.append({‘num’:i}) 4. print l ############ 1. l = [] 2. a = {‘num’:0} 3. for i in xrange(10): 4. a[‘num’] = i 5. l.append(a) 6. print l 以上两段代码的运行结果是否相同,若是不相同,缘由是什么? 上方代码的结果: 1. [{‘num’:0},{‘num’:1},{‘num’:2},{‘num’:3},{‘num’:4},{‘num’:5},{‘num’:6},{‘num’:7},{‘num’:8}, {‘num’:9}] 下方代码结果: 1. [{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9}, {‘num’:9}] 缘由是:字典是可变对象,在下方的l.append(a)的操做中是把字典a 的引用传到列表l 中,当后 续操做修改a[‘num’]的值的时候,l 中的值也会跟着改变,至关于浅拷贝。
方法一: 能够经过生成器,分屡次读取,每次读取数量相对少的数据(好比500MB)进行处理,处理结束后 在读取后面的500MB 的数据。 方法二: 能够经过linux 命令split 切割成小文件,而后再对数据进行处理,此方法效率比较高。能够按照行 数切割,能够按照文件大小切割。
1. def get_lines(): 2. l = [] 3. with open(‘file.txt’,‘rb’) as f: 4. for eachline in f: 5. l.append(eachline) 6. return l 7. if __name__ == ‘__main__’: 8. for e in get_lines(): 9. process(e) #处理每一行数据 如今要处理一个大小为10G 的文件,可是内存只有4G,若是在只修改get_lines 函数而其余代码保持不变的状况下,应该如何实现?须要考虑的问题都有哪些? 1. def get_lines(): 2. l = [] 3. with open(‘file.txt’,’rb’) as f: 4. data = f.readlines(60000) 5. l.append(data) 6. yield l 要考虑到的问题有: 内存只有4G 没法一次性读入10G 的文件,须要分批读入。分批读入数据要记录每次读入数据的位置。分批每次读入数据的大小,过小就会在读取操做上花费过多时间。
read:读取整个文件。
readline:读取下一行,使用生成器方法。
readlines:读取整个文件到一个迭代器以供咱们遍历。nginx
except: #捕获全部异常
except: <异常名> : #捕获指定异常
except:<异常名1, 异常名2> : 捕获异常1 或者异常2
except: <异常名> , <数据> :捕获指定异常及其附加的数据
except:<异常名1,异常名2>: <数据> :捕获异常名1 或者异常名2,及附加的数据
git
os 操做系统,time 时间,random 随机,pymysql 链接数据库,threading 线程,multiprocessing进程,queue 队列。
第三方库:django 和flask 也是第三方库,requests,virtualenv, selenium,scrapy,xadmin,celery,re,hashlib,md5。
经常使用的科学计算库(如Numpy,Scipy,Pandas)。程序员
1、赋值
在Python 中,对象的赋值就是简单的对象引用,这点和C++不一样,以下所示:github
16.a = [1,2,"hello",['python', 'C++']] 17.b = a
在上述状况下,a 和b 是同样的,他们指向同一片内存,b 不过是a 的别名,是引用。咱们可使用b is a 去判断,返回True,代表他们地址相同,内容相同,也可使用id()函数来查看两个列表的地址是否相同。
赋值操做(包括对象做为参数、返回值)不会开辟新的内存空间,它只是复制了对象的引用。也就是说除了b 这个名字以外,没有其余的内存开销。修改了a,也就影响了b,同理,修改了b,也就影响了a。
2、浅拷贝(shallow copy)
浅拷贝会建立新对象,其内容非原对象自己的引用,而是原对象内第一层对象的引用。 浅拷贝有三种形式:切片操做、工厂函数、copy 模块中的copy 函数。 好比上述的列表a; 切片操做:b = a[:] 或者b = [x for x in a]; 工厂函数:b = list(a); copy 函数:b = copy.copy(a); 一、b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象仍是指向统一对象(是引用)。
3、深拷贝(deep copy)
深拷贝只有一种形式,copy 模块中的deepcopy()函数。 深拷贝和浅拷贝对应,深拷贝拷贝了对象的全部元素,包括多层嵌套的元素。所以,它的时间和空间开销要高。 二、b = copy.deepcopy(a): 深度拷贝, a 和 b 彻底拷贝了父对象及其子对象,二者是彻底独立的。
init 在对象建立后,对对象进行初始化。
new 是在对象建立以前建立一个对象,并将该对象返回给init。
在Python 中用于生成随机数的模块是random,在使用前须要import. 以下例子能够酌情列 举: random.random():生成一个0-1 之间的随机浮点数; random.uniform(a, b):生成[a,b]之间的浮点数; random.randint(a, b):生成[a,b]之间的整数; random.randrange(a, b, step):在指定的集合(a,b)中,以step为基数随机取一个数; random.choice(sequence):从特定序列中随机取一个元素,这里的序列能够是字符串,列表,元组等。
1. import datetime 2. def dayofyear(): 3. year = input("请输入年份:") 4. month = input("请输入月份:") 5. day = input("请输入天:") 6. date1 = datetime.date(year=int(year),month=int(month),day=int(day)) 7. date2 = datetime.date(year=int(year),month=1,day=1) 8. return (date1 - date2 + 1).days
1. import random 2. random.shuffle(alist)
os.path 主要是用于对系统路径文件的操做。
sys.path 主要是对Python 解释器的系统环境参数的操做(动态的改变Python 解释器搜索路径)。
os.remove()删除文件
os.rename()重命名文件
os.walk()生成目录树下的全部文件名
os.chdir()改变目录
os.mkdir/makedirs 建立目录/多层目录
os.rmdir/removedirs 删除目录/多层目录
os.listdir()列出指定目录的文件
os.getcwd()取得当前工做目录
os.chmod()改变目录权限
os.path.basename()去掉目录路径,返回文件名
os.path.dirname()去掉文件名,返回目录路径
os.path.join()将分离的各部分组合成一个路径名
os.path.split()返回(dirname(),basename())元组
os.path.splitext()(返回filename,extension)元组os.path.getatime\ctime\mtime 分别返回最近访问、建立、修改时间
os.path.getsize()返回文件大小
os.path.exists()是否存在
os.path.isabs()是否为绝对路径
os.path.isdir()是否为目录
os.path.isfile()是否为文件
sys.argv 命令行参数List,第一个元素是程序自己路径 sys.modules.keys() 返回全部已经导入的模块列表 sys.exc_info() 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback 当前处理的异常详细信息 sys.exit(n) 退出程序,正常退出时exit(0) sys.hexversion 获取Python 解释程序的版本值,16 进制格式如:0x020403F0 sys.version 获取Python 解释程序的版本信息 sys.maxint 最大的Int 值 sys.maxunicode 最大的Unicode 值 sys.modules 返回系统导入的模块字段,key 是模块名,value 是模块 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH 环境变量的值 sys.platform 返回操做系统平台名称 sys.stdout 标准输出 sys.stdin 标准输入 sys.stderr 错误输出 sys.exc_clear() 用来清除当前线程所出现的当前的或最近的错误信息 sys.exec_prefix 返回平台独立的python 文件安装的位置 sys.byteorder 本地字节规则的指示器,big-endian 平台的值是'big',little-endian 平台的值是'little' sys.copyright 记录python 版权相关的东西 sys.api_version 解释器的C 的API 版本 sys.version_info 元组则提供一个更简单的方法来使你的程序具有Python 版本要求功能
在Python 中,unittest 是Python 中的单元测试框架。它拥有支持共享搭建、自动测试、在测试中暂停代码、将不一样测试迭代成一组,等的功能。
在Python 中,模块是搭建程序的一种方式。每个Python 代码文件都是一个模块,并能够引用其余的模块,好比对象和属性。
一个包含许多Python 代码的文件夹是一个包。一个包能够包含模块和子文件夹。
Python 是强类型的动态脚本语言。
强类型:不容许不一样类型相加。
动态:不使用显示数据类型声明,且肯定一个变量的类型是在第一次给它赋值的时候。
脚本语言:通常也是解释型语言,运行代码只须要一个解释器,不须要编译。
计算机不能直接理解高级语言,只能直接理解机器语言,因此必需要把高级语言翻译成机器语言,
计算机才能执行高级语言编写的程序。
解释性语言在运行程序的时候才会进行翻译。
编译型语言写的程序在执行以前,须要一个专门的编译过程,把程序编译成机器语言(可执行文件)。
有日志。 Python 自带logging 模块,调用logging.basicConfig()方法,配置须要的日志等级和相应的参数, Python 解释器会按照配置的参数生成相应的日志。
内建函数封装了各类转换函数,可使用目标类型关键字强制类型转换,进制之间的转换能够用 int(‘str’,base=’n’)将特定进制的字符串转换为十进制,再用相应的进制转换函数将十进制转换 为目标进制。 可使用内置函数直接转换的有: list---->tuple tuple(list) tuple---->list list(tuple)
1) 核心类差别
在Python 中,全部的名字都存在于一个空间中,它们在该空间中存在和被操做——这就是命名空间。它就好像一个盒子,每个变量名字都对应装着一个对象。当查询变量的时候,会从该盒子里面寻找相应的对象。
PEP8 规范。
两个前导下划线会致使变量在解释期间被改名。这是为了不内置变量和其余变量产生冲突。用户定义的变量要严格避免这种风格。以避免致使混乱。
sorted(d.items(),key = lambda x:x[1])
有三种不一样的含义:
一、转义字符二、路径名中用来链接路径名三、编写太长代码手动软换行。
alist [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}]
def sort_by_age(list1):
return sorted(alist, key=lambda x:x["age"],reverse=True)
列表.extend(Iterable):将可迭代对象中的元素追加到列表。
1.# 有两个列表a 和b a.extend(b) 会将b 中的元素追加到列表a 中 2.In [10]: a = [11, 22, 33] 3.In [11]: b = [44, 55, 66] 4.In [12]: a.extend(b) 5.In [13]: a 6.Out[13]: [11, 22, 33, 44, 55, 66]# 有列表c 和字符串d c.extend(d) 会将字符串d 中的每一个字符拆开做为元素插入到列表 c 7.In [14]: c = ['j', 'a', 'v', 'a'] 8.In [15]: d = "python" 9.In [16]: c.extend(d) 10.In [17]: c 11.Out[17]: ['j', 'a', 'v', 'a', 'p', 'y', 't', 'h', 'o','n']
3)删除
del 列表名[index]:删除指定索引的数据。
1.In [25]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu"]# 删除索引是1 的数据 2.In [26]: del name_list[1] 3.In [27]: name_list 4.Out[27]: ['zhangsan', 'wangwu', 'zhaoliu']
列表名.remove(数据):删除第一个出现的指定数据。
5.In [30]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu", "lisi"]# 删除第一次出现的lisi 的数据 6.In [31]: name_list.remove("lisi") 7.In [32]: name_list 8.Out[32]: ['zhangsan', 'wangwu', 'zhaoliu', 'lisi']
列表名.pop():删除末尾的数据,返回值: 返回被删除的元素。 9.In [33]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu"]# 删除最后一个元素zhaoliu 并将元素zhaoliu 返回 10.In [34]: name_list.pop() 11.Out[34]: 'zhaoliu' 12.In [35]: name_list 13.Out[35]: ['zhangsan', 'lisi', 'wangwu'] 列表名.pop(index):删除指定索引的数据,返回被删除的元素。 14.In [36]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu"]# 删除索引为1 的数据lisi 15.In [37]: name_list.pop(1) 16.Out[37]: 'lisi' 17.In [38]: name_list 18.Out[38]: ['zhangsan', 'wangwu', 'zhaoliu'] 列表名.clear():清空整个列表的元素。 19.In [40]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu"] 20.In [41]: name_list.clear() 21.In [42]: name_list 22.Out[42]: [] 4)排序 列表名.sort():升序排序从小到大。 23.In [43]: a = [33, 44, 22, 66, 11] 24.In [44]: a.sort() 25.In [45]: a 26.Out[45]: [11, 22, 33, 44, 66] 列表名.sort(reverse=True):降序排序从大到小。 27.In [46]: a = [33, 44, 22, 66, 11] 28.In [47]: a.sort(reverse=True) 29.In [48]: a 30.Out[48]: [66, 44, 33, 22, 11] 列表名.reverse():列表逆序、反转。 31.In [50]: a = [11, 22, 33, 44, 55] 32.In [51]: a.reverse() 33.In [52]: a 34.Out[52]: [55, 44, 33, 22, 11] 5)统计相关 len(列表名):获得列表的长度。 35.In [53]: a = [11, 22, 33, 44, 55] 36.In [54]: len(a) 37.Out[54]: 5 列表名.count(数据):数据在列表中出现的次数。 38.In [56]: a = [11, 22, 11, 33, 11] 39.In [57]: a.count(11) 40.Out[57]: 3 列表名.index(数据):数据在列表中首次出现时的索引,没有查到会报错。 41.In [59]: a = [11, 22, 33, 44, 22] 42.In [60]: a.index(22) 43.Out[60]: 1 if 数据in 列表: 判断列表中是否包含某元素。 44.a = [11, 22, 33, 44 ,55] 45.if 33 in a: 46. print("找到了....")
3.1 下面代码的输出结果将是什么?(2018-3-30-lxy) 1. list = ['a', 'b', 'c', 'd', 'e'] 2. print list[10:] 下面的代码将输出[],不会产生IndexError 错误。就像所指望的那样,尝试用超出成员的个数的index来获取某个列表的成员。 例如,尝试获取list[10]和以后的成员,会致使IndexError。 然而,尝试获取列表的切片,开始的index 超过了成员个数不会产生IndexError,而是仅仅返回一个空列表。这成为特别让人恶心的疑难杂症,由于运行的时候没有错误产生,致使bug 很难被追踪到。
1. print([x*11 for x in range(10)])
1. list1 = [1,2,3] 2. list2 = [3,4,5] 3. set1 = set(list1) 4. set2 = set(list2) 5. print(set1&set2) 6. print(set1^set2)
比较容易记忆的是用内置的set: 1. l1 = ['b','c','d','b','c','a','a'] 2. l2 = list(set(l1)) 3. print l2 若是想要保持他们原来的排序: 用list 类的sort 方法: 1. l1 = ['b','c','d','b','c','a','a'] 2. l2 = list(set(l1)) 3. l2.sort(key=l1.index) 4. print l2 也能够这样写: 1. l1 = ['b','c','d','b','c','a','a'] 2. l2 = sorted(set(l1),key=l1.index) 3. print l2 也能够用遍历: 1. l1 = ['b', 'c', 'd', 'b', 'c', 'a', 'a'] 2. l2 = [] 3. for i in l1: 4. if not i in l2: 5. l2.append(i) 6. print l2
1. def f1(lIn): 2. l1 = sorted(lIn) 3. l2 = [i for i in l1 if i<0.5] 4. return [i*i for i in l2] 5. 6. 7. def f2(lIn): 8. l1 = [i for i in l1 if i<0.5] 9. l2 = sorted(l1) 10. return [i*i for i in l2] 11. 12. 13. def f3(lIn): 14. l1 = [i*i for i in lIn] 15. l2 = sorted(l1) 16. return [i for i in l1 if i<(0.5*0.5)] 按执行效率从高到低排列:f二、f1 和f3。要证实这个答案是正确的,你应该知道如何分析本身代码的性能。Python中有一个很好的程序分析包,能够知足这个需求。 1. import random 2. import cProfile 3. lIn = [random.random() for i in range(100000)] 4. cProfile.run('f1(lIn)') 5. cProfile.run('f2(lIn)') 6. cProfile.run('f3(lIn)')
快速去除列表中的重复元素 1.In [4]: a = [11,22,33,33,44,22,55] 2. 3.In [5]: set(a) 4.Out[5]: {11, 22, 33, 44, 55} 交集:共有的部分 1.In [7]: a = {11,22,33,44,55} 2.In [8]: b = {22,44,55,66,77} 3.In [9]: a&b 4.Out[9]: {22, 44, 55} 并集:总共的部分 1.In [11]: a = {11,22,33,44,55} 2.In [12]: b = {22,44,55,66,77} 3.In [13]: a | b 4.Out[13]: {11, 22, 33, 44, 55, 66, 77} 差集:另外一个集合中没有的部分 1.In [15]: a = {11,22,33,44,55} 2.In [16]: b = {22,44,55,66,77} 3.In [17]: b - a 4.Out[17]: {66, 77} 对称差集(在a 或b 中,但不会同时出如今两者中) 1.In [19]: a = {11,22,33,44,55} 2.In [20]: b = {22,44,55,66,77} 3.In [21]: a ^ b 4.Out[21]: {11, 33, 66, 77}
Python语言和C++,java等其余编程语言相比,他是一种解释型脚本语言,代码在执行时,会一行一行的解释成CPU能理解的机器码,同时它又是跨平台的,能够容许windows,linux,mac等系统上,一样的程序逻辑,可能C语言须要1000行代码,java有100行,可是python实现可能只须要20行,这极大程度上提高了企业的项目开发效率, 记得以前就有一篇权威报道,到2014年为止,麻省、哈弗等顶尖高校都已经使用python做为教学语言,如今国内的高校,也开始设置python的专业课程,如今对于企业项目后台开发而言,不是说必定要用python开发,但如今语言自己的性能差距在实际开发的过程当中,相对于业务功能合理设计、代码编写架构质量等,语言底层形成的性能损失愈来愈能够忽略不计,针对于一些特定的功能模块,python当前也出现了pypy,JIT等大幅度提升python程序运行效率的相关技术,可以知足大多数功能的需求业务场景 具体选用python后,新项目推荐使用python3,08年python3版本发布后,十几年来python3生态圈第三方库已经很是具有完备和弃权,而官方已经宣布python2在2020年将不在维护,另外python3自己性能也和相较于python2有必定的提高
ls -F 在显示名称的时候会在文件夹后添加“/”,在文件后面加“*”。
日志以文本能够存储在“/var/log/”目录下后缀名为.log。
netstat命令参数:
-t : 指明显示TCP端口
-u : 指明显示UDP端口
-l : 仅显示监听套接字(所谓套接字就是使应用程序可以读写与收发通信协议(protocol)与资料的程序)
-p : 显示进程标识符和程序名称,每个套接字/端口都属于一个程序。
-n : 不进行DNS轮询,显示IP(能够加速操做)
便可显示当前服务器上全部端口及进程服务,于grep结合可查看某个具体端口及服务状况··
netstat -ntlp //查看当前全部tcp端口·
netstat -ntulp |grep 80 //查看全部80端口使用状况·
netstat -an | grep 3306 //查看全部3306端口使用状况·
查看一台服务器上面哪些服务及端口
netstat -lanp
查看一个服务有几个端口。好比要查看mysqld
ps -ef |grep mysqld
查看某一端口的链接数量,好比3306端口
netstat -pnt |grep :3306 |wc
查看某一端口的链接客户端IP 好比3306端口
netstat -anp |grep 3306
netstat -an 查看网络端口 lsof -i :port,使用lsof -i :port就能看见所指定端口运行的程序,同时还有当前链接。 nmap 端口扫描netstat -nupl (UDP类型的端口)netstat -ntpl (TCP类型的端口)netstat -anp 显示系统端口使用状况
直接修改/etc/rc0.d ~ /etc/rc6.d 和/etc/rcS.d 文件夹的内容,添加需启动的程序,S 开头的表示启动,K 开头的表示不启动。
一、重定向>
Linux 容许将命令执行结果重定向到一个文件,本应显示在终端上的内容保存到指定文件中。如:ls >test.txt ( test.txt 若是不存在,则建立,存在则覆盖其内容)。
二、重定向>>
这个是将输出内容追加到目标文件中。若是文件不存在,就建立文件;若是文件存在,则将新的内容追加到那个文件的末尾,该文件中的原有内容不受影响。
软链接相似Windows 的快捷方式,当删除源文件时,那么软连接也失效了。硬连接能够理解为源文件的一个别名,多个别名所表明的是同一个文件。当rm 一个文件的时候,那么此文件的硬连接数减1,当硬连接数为0 的时候,文件被删除。
pwd 显示工做路径
ls 查看目录中的文件
cd /home 进入'/ home' 目录'
cd .. 返回上一级目录
cd ../.. 返回上两级目录
mkdir dir1 建立一个叫作'dir1' 的目录'
rm -f file1 删除一个叫作'file1' 的文件',-f 参数,忽略不存在的文件,从不给出提示。
rmdir dir1 删除一个叫作'dir1' 的目录'
groupadd group_name 建立一个新用户组
groupdel group_name 删除一个用户组
tar -cvf archive.tar file1 建立一个非压缩的tarball
tar -cvf archive.tar file1 file2 dir1 建立一个包含了'file1', 'file2' 以及'dir1'的档案文件
tar -tf archive.tar 显示一个包中的内容
tar -xvf archive.tar 释放一个包
tar -xvf archive.tar -C /tmp 将压缩包释放到/tmp 目录下
tar -cvfj archive.tar.bz2 dir1 建立一个bzip2 格式的压缩包
tar -xvfj archive.tar.bz2 解压一个bzip2 格式的压缩包
tar -cvfz archive.tar.gz dir1 建立一个gzip 格式的压缩包
tar -xvfz archive.tar.gz 解压一个gzip 格式的压缩包
reboot 从新启动操做系统
shutdown –r now 从新启动操做系统,shutdown 会给别的用户提示
shutdown -h now 马上关机,其中now 至关于时间为0 的状态
shutdown -h 20:25 系统在今天的20:25 会关机
shutdown -h +10 系统再过十分钟后自动关机
init 0 关机 init 6 重启
一、git merge 冲突了,根据提示找到冲突的文件,解决冲突若是文件有冲突,那么会有相似的标记
二、修改完以后,执行git add 冲突文件名
三、git commit 注意:没有-m 选项进去相似于vim 的操做界面,把conflict 相关的行删除掉
直接push 就能够了,由于刚刚已经执行过相关merge 操做了。
首先,建立分支dev,切换到dev分支 $ git checkout -b dev Switched to a new branch 'dev' git checkout命令加上-b参数表示建立并切换,至关于如下两条命令: $ git branch dev $ git checkout dev Switched to branch 'dev' 而后,用git branch命令查看当前分支: $ git branch * dev master git branch命令会列出全部分支,当前分支前面会标一个*号。 而后,咱们就能够在dev分支上正常提交,好比对readme.txt作个修改,加上一行: Creating a new branch is quick. 而后提交: $ git add readme.txt $ git commit -m "branch test" [dev b17d20e] branch test 1 file changed, 1 insertion(+) 如今,dev分支的工做完成,咱们就能够切换回master分支: $ git checkout master Switched to branch 'master' 切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!由于那个提交是在dev分支上,而master分支此刻的提交点并无变: 如今,咱们把dev分支的工做成果合并到master分支上: $ git merge dev Updating d46f35e..b17d20e Fast-forward readme.txt | 1 + 1 file changed, 1 insertion(+) git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就能够看到,和dev分支的最新提交是彻底同样的。 注意到上面的Fast-forward信息,Git告诉咱们,此次合并是“快进模式”,也就是直接把master指向dev的当前提交,因此合并速度很是快。 固然,也不是每次合并都能Fast-forward,咱们后面会讲其余方式的合并。 合并完成后,就能够放心地删除dev分支了: $ git branch -d dev Deleted branch dev (was b17d20e). 删除后,查看branch,就只剩下master分支了: $ git branch * master 建立与合并分支 阅读: 9909301 在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来讲不是指向提交,而是指向master,master才是指向提交的,因此,HEAD指向的就是当前分支。 一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能肯定当前分支,以及当前分支的提交点: git-br-initial 每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也愈来愈长。 当咱们建立新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上: git-br-create 你看,Git建立一个分支很快,由于除了增长一个dev指针,改改HEAD的指向,工做区的文件都没有任何变化! 不过,从如今开始,对工做区的修改和提交就是针对dev分支了,好比新提交一次后,dev指针往前移动一步,而master指针不变: git-br-dev-fd 假如咱们在dev上的工做完成了,就能够把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并: git-br-ff-merge 因此Git合并分支也很快!就改改指针,工做区内容也不变! 合并完分支后,甚至能够删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,咱们就剩下了一条master分支: git-br-rm 真是太神奇了,你看得出来有些提交是经过分支完成的吗? 下面开始实战。 首先,咱们建立dev分支,而后切换到dev分支: $ git checkout -b dev Switched to a new branch 'dev' git checkout命令加上-b参数表示建立并切换,至关于如下两条命令: $ git branch dev $ git checkout dev Switched to branch 'dev' 而后,用git branch命令查看当前分支: $ git branch * dev master git branch命令会列出全部分支,当前分支前面会标一个*号。 而后,咱们就能够在dev分支上正常提交,好比对readme.txt作个修改,加上一行: Creating a new branch is quick. 而后提交: $ git add readme.txt $ git commit -m "branch test" [dev b17d20e] branch test 1 file changed, 1 insertion(+) 如今,dev分支的工做完成,咱们就能够切换回master分支: $ git checkout master Switched to branch 'master' 切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!由于那个提交是在dev分支上,而master分支此刻的提交点并无变: git-br-on-master 如今,咱们把dev分支的工做成果合并到master分支上: $ git merge dev Updating d46f35e..b17d20e Fast-forward readme.txt | 1 + 1 file changed, 1 insertion(+) git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就能够看到,和dev分支的最新提交是彻底同样的。 注意到上面的Fast-forward信息,Git告诉咱们,此次合并是“快进模式”,也就是直接把master指向dev的当前提交,因此合并速度很是快。 固然,也不是每次合并都能Fast-forward,咱们后面会讲其余方式的合并。 合并完成后,就能够放心地删除dev分支了: $ git branch -d dev Deleted branch dev (was b17d20e). 删除后,查看branch,就只剩下master分支了: $ git branch * master 由于建立、合并和删除分支很是快,因此Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工做效果是同样的,但过程更安全。 小结 Git鼓励大量使用分支: 查看分支:git branch 建立分支:git branch <name> 切换分支:git checkout <name> 建立+切换分支:git checkout -b <name> 合并某分支到当前分支:git merge <name> 删除分支:git branch -d <name>