线程是进程内部的一个执行流,也就是线程在进程的地址空间内运行。
一个进程内的所有线程共享进程资源
线程是CPU调度的基本单位(CPU调度是按照PCB进行调度的)
创建,销毁一个线程相较创建,销毁一个进程成本要低(创建进程要创建PCB,虚拟地址空间,创建页表,维护映射,把硬盘的代码数据加载到内存,文件描述符等等,而创建线程只需要一个PCB指向进程的虚拟地址空间即可,同样销毁一个线程只需要销毁PCB即可)
线程间的切换相比于进程间的切换容易的多(进程间的切换,PCB切换,页表切换等等,线程切换PCB切换,页表不切换)
进程是拥有一个执行流,或多个执行流的线程组。
进程是一个能独立运行的基本单位,同时也是系统分配资源基本单位。(独立性)
进程是动态执行的程序(创建一个进程要创建PCB描述进程,为进程分配资源,进程可以被调度,被执行。而程序就只是静静躺在硬盘上)(动态性)
任何进程都可以同其他进程一起并发执行(并发性)(并发:一个CPU多个进程,分时切换)
进程间的相互制约,进程具有执行的间断性,进程按照各自独立不可预知的速度向前推进(异步性)(异步性:指进程以不可预知的速度向前推进,内存中的每个进程何时执行,何时暂停,以怎样的速度向前推进,要用多长时间完成等都是不可预知的)
进程状态
等待 就绪 运行 阻塞
先来先去服务:
优点:有利于长作业以及CPU繁忙的作业
缺点:不利于短作业以及I/O繁忙的作业
短作业优先:
优点:比FCFS改善平均周转时间和平均带权周转时间,缩短作业的等待时间;提高系统的吞吐量;
缺点:对长作业非常不利,可能长时间得不到执行;未能依据作业的紧迫程度来划分执行的优先级;难以准确估计作业(进程)的执行时间,从而影响调度性能。
时间片轮转:
优点:兼顾长短作业;
缺点:平均等待时间较长,上下文切换较费时。适用于分时系统。
高响应比优先调度算法:
优点:兼顾长短作业,
缺点:计算响应比开销大,适用于批处理系统。
协程是程序员控制的,协程是串行的
协程的实现,无非是你要维护一组局部状态,在重新进入协程前,保证这些状态不被改变,你能顺利定位到之前的位置。你平时所写的一些逻辑控制代码,经典如状态机或对象等
生产者消费者问题
https://www.cnblogs.com/hckblogs/p/7858545.html
让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。
Ps: java多线程编程中常用的关键字 synchronized (给方法加锁) synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchronized可以保证一个线程的变化可见(可见性)synchronized是volatile的升级版。
Synchronized和volatile的区别。
哲学家就餐问题
https://baike.baidu.com/item/%E5%93%B2%E5%AD%A6%E5%AE%B6%E5%B0%B1%E9%A4%90%E9%97%AE%E9%A2%98/10929794?fr=aladdin
哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。
哲学家从来不交谈,这就很危险,可能产生死锁,每个哲学家都拿着左手的餐叉,永远都在等右边的餐叉(或者相反)。即使没有死锁,也有可能发生资源耗尽。例如,假设规定当哲学家等待另一只餐叉超过五分钟后就放下自己手里的那一只餐叉,并且再等五分钟后进行下一次尝试。这个策略消除了死锁(系统总会进入到下一个状态),但仍然有可能发生“活锁”。如果五位哲学家在完全相同的时刻进入餐厅,并同时拿起左边的餐叉,那么这些哲学家就会等待五分钟,同时放下手中的餐叉,再等五分钟,又同时拿起这些餐叉。
必要条件:1.互斥 涉及的资源是非共享的,即一次只有一个进程使用。如果有另外一个进程申请该资源,那么申请必须等待。2.不剥夺条件。进程所获得的资源在未使用完毕之前不能被其他进程抢占。3.占有并等待。进程每次申请他需要的一部分资源,在等待新一批资源的时候继续占用已有资源不释放。4.环路条件。存在一种进程的循环链,链中的每一个进程已获得的资源通是被链中下一个进程所请求。
解决策略:1.采用资源分配的方式【静态(一次分配完所有需要的资源),动态(否定环路,有环路就不分配资源)】2.检测死锁并修复3.忽略死锁,鸵鸟策略、
数据库中解决死锁的方式:一般有两类方法,一类是预防一类是允许发生死锁,但采用一定手段诊断系统中有无死锁并解除;
【预防】:1.一次封锁法(每个事务必须将 所有需要使用的资源全部加锁)2.顺序封锁法(预先对所有数据对象规定一个封锁顺序,所有事务按顺序封锁。Java里面也有这个解决策略)ps:第一种降低了并发度,第二种成本很高,实现很难。
【诊断和解除(普遍采用)】:1.超时法 一个事务等待时间超过了规定时间就认为发生了死锁。2.等待图法。等待图是一个有向图G=(T,U),T为点集,每个节点代表正在运行的事务,U为边集,每条边代表等待情况,若T1指向T2说明T1等待T2.等待图动态反映了所有事务的等待情况。并发控制子系统周期性的生成等待图并进行检测,如果途中出现了回路这表示系统发生了死锁。死锁发生后通常采用撤销一个代价最小的事务,释放其持有的所有锁。
特点
1.由内核维护一个共享的内存区域,其它进程把自己虚拟地址映射到这块内存,多个进程之间就可以共享这块内存了。
2.这种进程间通信的好处是不需要信息复制,是进程间通信最快的一种方式。
3.但这种通信方式会面临同步的问题,需要与其它通信方式配合,最合适的就是信号。
消息队列,是消息的链接表,存放在 内核中。一个消息队列由一个标识符(即队列ID)来标识。
特点
1.消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
2.消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
3.消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
特点:
a、信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
b、信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
c、每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
d、支持信号量组。
PV操作
P操作负责把当前进程由运行状态转换为阻塞状态,直到另外一个进程唤醒它。操作为:申请一个空闲资源(把信号量减1),若成功,则退出;若失败,则该进程被阻塞;
V操作负责把一个被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息。操作为:释放一个被占用的资源(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒之。
对于信号量,可以认为是一个仓库,有两个概念,容量和当前的货物个数。
P操作从仓库拿货,如果仓库中没有货,线程一直等待,直到V操作,往仓库里添加了货物,为了避免P操作一直等待下去,会有一个超时时间。V操作往仓库送货,如果仓库满了,线程等待,直到有P操作,从仓库中拿走货物,有空的位置。
P操作:货物个数减1,减过之后,货物个数大于等于0,说明已经拿到货物,线程继续。否者线程阻塞。
V操作:货物个数加1,加过之后,货物个数小于等于容量,说明添加成功,线程继续。否者线程阻塞。
项目中的使用场景:
客户端使用提供的SDk与服务交互,为了提高效率,客户端发送一个请求后,SDK异步回调给客户端。但是,有些请求,客户端希望同步,等待回复。这个时候,建立一个map,以req的sequence为key,value为信号量的指针,信号量的容量设置为1,可用的货物为0,对信号量进行TimeoutP操作,货物个数为-1,阻塞在这里。异步回调,收到回复的sequence,根据map找到信号量指针,进行V操作,货物个数为0,通知前面TimeoutP的线程继续执行下去,这个时候,TimeoutP的线程,把回复消息取出来,返回给客户端。
网络通信就是不同机器的进程间通信方式。
应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要 通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字 (Socket)的接口,区分不同应用程序进程间的网络通信和连接。
管道,通常指无名管道,是 UNIX 系统IPC最古老的形式。
特点:
a、它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
b、它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
c、它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于 其他任何文件系统,并且只存在于内存中.
特点
FIFO可以在无关的进程之间交换数据,与无名管道不同。
FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
虚拟内存允许将大逻辑地址空间映射到小的物理内存。虚拟内存允许极大的进程运行,且提高了多道程序的程序,增加CPU使用率。再者,它使得程序员不必考虑内存可用性。另外,虚拟内存允许进程共享系统库与内存。当父子进程共享内存页时,虚拟内存也允许采用写时复制来创建进程。
虚拟内存通常采用按需调页方式来实现。纯按需调页只有再引用页时才调入页。第一次引用就会使操作系统产生页错误。操作系统检查内部表以确定该页再备份仓库上的位置。接着,它找到空闲帧并从备份仓库中读入页。更新页表以反映这一修改,并重新执行产生页错误的指令。这种方法允许一个进程运行,即使完整内存影像不能同时在内存中。只要页错误率足够低,那么性能就可以被接受。
LRU最久未使用淘汰算法。
Redis是一个高性能的key-value数据库(非关系型)。
Memcached 是一个高性能的分布式内存对象缓存系统
这两个都一般用作缓存,因为数据存在内存中,速度快,并发高,
补充:HyperLogLog,计算基数(大量数据中计算不重复的元素的个数)比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。
将redis当作使用LRU的缓存来使用
补充:Memcached是一个高性能的分布式内存对象缓存系统,提供了操作hash表的接口。你可以用它来缓存数据,从而避免每次到数据库里取数据,因此能提高系统的速度。不过所有的数据都在内存里,因此关机后数据就丢失了。 相应的,有人在Memcached的基础上实现了数据持久化,这就类似于数据库的一部分功能了。但它和数据库没什么必然的联系!Memcached可以作为 缓存(提高速度)的中间层(服务接口和DB之间)。
页是信息的物理单位,段是逻辑单位
页的大小固定且由系统决定,段是长度不固定
inode是什么呢Block是记录文件内容的区域,inode则是记录该文件的属性及其放置在哪个Block之内的信息。所
以,每个文件都会占用一个inode。当Linux系统要查找某个文件时,它会先搜索inode table找到这个文件的属性及数据存放地点,然后再查找数据存放的Block进而将数据取出。
恢复原理:有个日志,删除的时候在日志里面还拷贝了一份inode信息。在 ext3 和 ext4 文件系统中,每个文件都是通过 inode 来描述其数据存放的具体位置,当文件被删除以后,inode 的数据指针部分被清零,文件目录区没有太多变化。文件的读写都是通过 inode 来实现,当 inode 数据指针被清零以后,即便文件内容还在,也没有办法把文件内容组合出来。当 ext3 和 ext4 文件系统中的元数据 metadata 发生变化时,相应的元数据 metadata 在日志文件会有一份拷贝。比如一个文件被删除了,它的 inode 信息会在日志文件中先保存一份,然后把要删除文件 inode 相关信息清零。这个日志文件是循环使用的,当操作过多时,删除的文件的 inode 日志记录会被新的数据替换,这就彻底丧失了根据 inode 找回数据的机会了。如果是大量文件的删除,这个日志文件会被反复循环利用多次,只留给最后删除的那些文件的恢复机会。
软连接相当于快捷方式,硬连接是相当于共享文件。
删除源文件,软连接不可用,硬连接可用。
修改硬链接文件,源文件也会更新。
僵尸进程:一个子进程在其父进程还没有来得及调用wait()或waitpid()来获取子进程的信号状态的情况下退出,那么这个子进程就是僵尸进程。子进程结束后会向父进程发出SIGCHLD信号。
如果进程不调用wait()或waitpid()的话,那么保留的信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。
外部解决办法:
kill掉父进程,使僵尸进程变为孤儿进程。
内部解决办法:
1、父进程处理SIGCHLD信号,在信号处理函数中调用wait处理僵尸进程。
2、fork两次:借助一个中间进程,父进程只wait中间进程,让中间进程再fork出孙进程。孙进程结束后会变成僵尸进程,等中间进程一结束,孙进程就成孤儿进程了。
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。所以孤儿进程没什么危害,系统会接管他。
应用层相当于老板,定义了应用进程间通信和交互的规则。(DNS,HTTP,SMTP)
运输层就相当于传达室,负责向两台主机之间的通信提供通用的数据传输服务。(TCP,UDP)端到端通信
网络层相当于邮局,网络层负责为分组交换网上的不同主机提供通信服务。功能就两个:1.根据目的ip地址找下一条路由。2.连接异构的网络。(ip协议)是点到点的通信
数据链路层相当于快递员,吧网络层下来的ip数据包封装成帧,在相邻两个节点间的链路上传送帧。
物理层就是搬运工,(网卡)
以太网是一种 星形拓扑 结构的局域网
早期使用 集线器 进行连接,集线器是一种物理层设备, 作用于 比特 而不是帧,当一个比特到达接口时,集线器重新生成这个比特,并将其能量强度放大,从而扩大网络的传输距离,之后再将这个比特发送到其它所有接口。如果集线器同时收到两个不同接口的帧,那么就发生了碰撞。(集线器属于 物理层设备,作用于比特)
目前以太网使用交换机替代了集线器,交换机是一种链路层设备,它不会发生碰撞,能根据 MAC 地址进行存储转发(交换机具有自学习的功能,学习的内容为 mac 地址与交换机端口的映射表)
mac帧:
目的地址6字节 |
源地址6字节 | 类型2字节 | 数据字段46-1500字节 | 帧校验序列4字节 |
ICMP 报文分为 差错报告报文 和 询问报文
网际控制报文协议ICMP。为了更有效地转发IP数据包和提高交付成功的机会,在网际层使用了网际控制报文协议ICMP,ICMP允许主机或路由器报告差错情况和提供有关异常情况的报告。ICMP是装在IP数据报中,作为其数据部分的。
Ping
Traceroute
udp 无连接不可靠速度快
tcp面向连接 可靠
三次握手
A:我有东西要给你。B:我知道你有东西给我 。A:我知道你知道我要给东西你了那我开始给东西你吧。
四次挥手
A:我发完了不发了。B:好,我知道你发完了。B:我也发完了不发了。A:好我知道你发完了。
TIME_WAIT作用:
在A确认后,tcp连接还没释放掉,必须等待TIME_WAIT设置的2MSL后,A才进入CLOSED状态。理由如下:1.为了保证A发送到最后一个确认报文段能到达B。2.防止已失效的连接请求报文段出现在本连接中。
首先发送端发送一个文件信息报文,这个报文就是最简单的UDP报文,但是里面的信息很重要,记录着文件的大小,被分隔成的报文数,文件序号。发完这个信息包,发送端阻塞,等待接收端的回复报文才能继续。文件信息包被接收端接受以后使用确认机制确定是否接受这个文件,并把决定回馈给发送端。此时,发送端如果收到的是“确定接受”的结果,将会把这个文件的整组数据报全部发送过去,这里我们并不像最传统的可靠传输协议TCP协议一样,对于每个每个报文都要确认接受完才会对下一个报文进行处理,太没效率,遵守本协议的接受端在接受这组报文的时候将遵守错序重排机制,来对收到的这组报文进行按序号排序,期间可能序号不联系不过没关系,接受过程只要保证序号从小到大即可。发送端发完所有报文延迟一点时间再发送一个结束报文,延迟时间是为了减少结束报文比数据报文还早被接受的情况,当然即使这种情况出现也不会破坏可靠性,只不过在在结束报文之后的数据报文会被当做丢失的包被要求重发,降低效率。接受端接受到结束报文后按照一开始的文件信息包的信息和序列号做对比,把没有的序列号的报文的信息传回给发送端,要求重新发送这些报文。发送端接到信息以后重发丢失的数据包。直到接收端拿到的报文和信息匹配,接受端就可以发回一个“接受完毕”的报文。这样发送端接受端再进行下一次文件传输。
1. TCP 拥塞控制的作用
2. 具体原理
TCP 主要通过四个算法来进行拥塞控制:慢开始 、拥塞避免 、快重传、快恢复。
发送方需要维护一个叫做 拥塞窗口(cwnd) 的状态变量,注意拥塞窗口与发送方窗口的区别:拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口。
3. 慢开始与拥塞避免
发送的最初执行慢开始,令 cwnd = 1,发送方只能发送 1 个报文段;当收到确认后,将 cwnd 加倍,因此之后发送方能够发送的报文段数量为:2、4、8 …
注意到慢开始每个轮次都将 cwnd 加倍,这样会让 cwnd 增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh,当 cwnd >= ssthresh 时,进入 拥塞避免 ,每个轮次只将 cwnd 加 1。
如果出现了超时,则令 ssthresh = cwnd / 2,然后重新执行慢开始
4. 快重传与快恢复
在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。
在发送方,如果收到 三个重复确认 ,那么可以知道下一个报文段 丢失 ,此时执行快重传,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。
在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,令 ssthresh = cwnd / 2 ,cwnd = ssthresh,注意到此时 直接进入拥塞避免 。
慢开始和快恢复的快慢指的是 cwnd 的 设定值 ,而 不是 cwnd 的增长速率 。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。
GET 用于获取资源,而 POST 用于传输实体主体。
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。
GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。
幂等的 HTTP 方法,同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。所有的安全方法也都是幂等的。在正确实现的条件下,GET,HEAD,PUT 和 DELETE 等方法都是幂等的,而 POST 方法不是。
请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEAD,但是 PUT 和 DELETE 不可缓存,POST 在多数情况下不可缓存的。
cookie分为二种
1,以文件方式存在硬盘空间上的长期性的cookie
2,停留在浏览器所占内存中的临时性的cookie
浏览网站时,你会经常发现网站登录的地方,会有提示,问你是不是要记住自己的登录状态,像这种情况,登录时填写的一些信息会被以文件的方式存放在客户端的硬盘上。
当用户登录后,session会在cookie端产生一个session_id,这个session_id是存于浏览器所占用的内存当中。当你关闭浏览器后,session_id也要消失了。
cookie采用的是在客户端保持状态的方案,它是客户端的会话状态的一种储存机制。它是服务器在本地机器上存储的小段文本或者是内存中的一段数据,并随每一个请求发送至同一个服务器。IETF RFC 2965 HTTP State Management Mechanism 是通用cookie规范。网络服务器用HTTP头信息向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,或者本地内存中数据,它会自动将同一服务器的任何请求缚上这些cookies,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制借助于cookie机制来达到保存标识的目的,这样就可以解决HTTP协议无状态的缺陷。
session是一种服务器端的信息管理机制,它把这些文件信息以文件的形势存放在服务器的硬盘空间上。
当客户端向服务器发出请求时,要求服务器端产生一个session时,服务器端会先检查一下,客户端的cookie里面有没有session_id,是否已经过期。如果有这样的session_id的话,服务器端会根据cookie里的session_id把服务器的session检索出来。如果没有这样的session_id的话,服务器端会重新建立一个。PHPSESSID是一串加了密的字符串,它的生成按照一定的规则来执行。同一客户端启动二次session_start的话,session_id是不一样的。
session更安全。
定义:
短连接:例如普通的web请求,在三次握手之后建立连接,发送数据包并得到服务器返回的结果之后,通过客户端和服务端的四次握手进行关闭断开。
长连接:区别于短连接,由于三次握手链接及四次握手断开,在请求频繁的情况下,链接请求和断开请求的开销较大,影响效率。采用长连接方式,执行三次握手链接后,不断开链接,保持客户端和服务端通信,直到服务器超时自动断开链接,或者客户端主动断开链接。
适用场景:
短连接:适用于网页浏览等数据刷新频度较低的场景。
长连接:适用于客户端和服务端通信频繁的场景,例如聊天室,实时游戏等。
经过个人实践,证明子查询效率特别低,而一般的子查询都可以由关连查询来实现相同的功能,关联查询的效率要提高很多,所以建议在数据查询时避免使用子查询(尤其是在记录很多时),而最好用关联查询来实现。
drop直接删掉表 truncate删除表中数据,再插入时自增长id又从1开始 delete删除表中数据,可以加where字句。
用TRUNCATE替代DELETE
TRUNCATE不记录日志,DELETE记录日志,所以TRUNCATE要快于DELETE
但是一旦用TRUNCATE进行删除就不能进行恢复,TRUNCATE是删除整张表的数据
更详细的区别
ps:mysql删除末尾数据后,再插入新数据id不连续解决方案
视图就相当于一个select语句,把结果集保存起来了,当成一个临时的表。
基本表的行列子集视图一般是可更新的。若视图的属性来自集合函数,表达式,则该视图肯定是不可以更新的。
存储过程就是把常用的sql封装起来,下次用的时候直接call,方便快捷。
触发器是一种用来保障参照完整性的特殊的存储过程,它维护不同表中数据间关系的有关规则。当对指定的表进行某种特定操作(如:Insert,Delete或Update)时,触发器产生作用。触发器可以调用存储过程。