《现代操作系统(中文第四版)》第二章 进程与线程

news2024/11/15 4:23:55

第二章、进程与线程

操作系统最核心的概念就是进程,这是对正在运行程序的一个抽象。进程是操作系统提供的最古老的也是最重要的抽象概念之一,即使可以使用的cpu只有一个,他们也具有支持并发操作的能力,它们将一个单独的cpu变换成多个虚拟的cpu。

2.1 进程

伪并行:严格的说,在一瞬间,CPU只能运行一个进程,但在一秒内,它可能运行多个进程,这样就产生并行的错觉。

2.1.1 进程模型

在进程模型中,计算机上所有可运行的软件,通常也包括操作系统、被组织成若干顺序进程,简称进程。

一个进程就是一个正在执行的程序的实例,包括程序计数器(PC)、寄存器、变量的当前值。为了更好理解,本章我们假设计算机只有一个CPU。下图是对多个进程在CPU上运行的理解:在观察足够长的一段时间后,所有的进程都运行了,但在任何一个给定的瞬间仅有一个进程真正在运行。

在这里插入图片描述

进程和程序间的区别是很微妙的,但非常重要。用一个比喻可以更容易理解这一点,想象一位有一手好厨艺的计算机科学家正在为他的女儿烘制生日蛋糕。他有做生日蛋糕的食谱,厨房里有所需的原料:面粉、鸡蛋、糖等。在这个比喻中,做蛋糕的食谱就是程序(即用适当形式描述的算法),计算机科学家就是处理器(cpu),而做蛋糕的各种原料就是输入数据。进程就是厨师阅读食谱、取来各种原料以及烘制蛋糕等一系列动作的总和。现在假设计算机科学家的儿子哭着跑进来,说他的头被蜜蜂蛰了。计算机科学家就记录下他照着食谱做到哪一步了(保存进程的当前状态),然后拿出一本急救手册,按照其中的指示处理伤口。这里,处理机从一个进程(做蛋糕)切换到另一个高优先级的进程(实施医疗救治),每个进程都有各自的程序(食谱和急救手册)。当蜜蜂蛰伤处理完后,这位计算机科学家又回来做蛋糕,从他离开的那一步继续做。

关键思想:一个进程是某种类型的一个活动,他有程序、输入、输出以及状态。
如果一个程序运行了两边,则算作两个进程。

2.1.2 进程的创建

四种主要事件会导致进程创建:

  • 1.系统初始化
  • 2.正在运行的程序执行了创建进程的系统调用
  • 3.用户请求创建一个进程
  • 4.一个批处理作业的初始化
    从技术上看,在所有的这些情形中,新进程都是由于一个已存在的进程执行了一个用于创建进程的系统调用而创建的。

启动操作系统时,通常会创建若干个进程,其中有些是前台进程,也就是同用户交互并且替他们完成工作的那些进程。其他的是后台进程。
停留在后台处理诸如电子邮件、Web页面、新闻、打印之类活动的进程称为守护进程。

在UNIX和Windows中,进程创建之后,父进程和子进程有各自不同的地址空间。

2.1.3 进程的终止

四种主要事件会导致进程的终止:

1.正常退出(自愿的)
2.出错退出(自愿的)
3.严重错误(非自愿)
4.被其他进程杀死(非自愿)

2.1.4 进程的层次结构

UNIX系统中,进程创建另一个进程后,父进程和子进程就以某种形式继续保持联系,子进程自身可以创建更多的进程,组成一个进程的层次结构。进程只有一个父进程,但可以有多个子进程。

Windows中没有进程层次的概念,所有进程都是地位相等的。在创建进程时,父进程得到一个令牌(称为句柄),该句柄可以用来控制子进程,但父进程有权把这个令牌传递给其他进程,这样,就不存在进程层次了。

2.1.5 进程的状态(三种状态)

进程有三种状态: 1.运行(该时刻进程实际占用CPU); 2.就绪(可运行,但因因为其他进程正在运行而暂时停止);3.阻塞(除非某种外部事件发生,否则进程不能运行)。在这里插入图片描述
转换2和3是由进程调度程序引起的。调度程序的主要工作就是决定应当运行哪个进程,何时运行以及它应该允许多长时间。

操作系统的最底层是调度程序,在它上面有许多进程。所有关于中断处理、启动进程和停止进程的具体细节都隐藏在调度程序中。
在这里插入图片描述

2.1.6 进程的实现

为了实现进程模型,操作系统维护一张表格,即进程表,每个进程占用一个进程表项 (有的作者称这个表项为进程控制块),该表项包含了进程状态的重要信息,包括程序计数器,堆栈指针,内存分配状态,所打开文件的状态,账号和调度信息,以及其他在进程由运行态转换到就绪态或阻塞态时必须保存的信息,从而保证该进程随后能再次启动。
在这里插入图片描述
所有的中断都是从保存寄存器开始,对于当前进程而言,通常是保存在进程表项中, 中断的处理和调度过程如图:
在这里插入图片描述

2.1.7 多道程序设计模型

CPU利用率 = 1 - p^n. p为一个进程等待I/O操作的时间与其在内存中时间的比值,n为程序的数量。

2.2 线程

2.2.2 经典的线程模型

在线程中有一个程序计数器,用来记录接着要执行哪一条指令。线程拥有寄存器,用来保存线程当前的工作变量。线程还拥有一个堆栈,用来记录执行历史。
进程用于把资源集中到一起,线程则是在cpu上被调度执行的实体。在同一个进程环境中,允许彼此之间有较大独立性的多个线程执行。在同一个进程中并行运行多个线程,是对在同一台计算机上并行运行多个进程的模拟。在这种情形下,多个线程共享同一个地址空间和其他资源
线程有时被称为轻量级进程

在这里插入图片描述
在第一个图,每一个线程都在不同的地址空间中运行,而在第二个图中,三个线程都在相同的地址空间中运行。

每个线程都有完全一样的地址空间,意味着他们共享同样的全局变量,线程之间是没有保护的。
在这里插入图片描述

线程可以处于若干种状态的任何一个:运行、阻塞、就绪或终止。
每个线程有自己的堆栈,每个线程的堆栈有一帧,供各个被调用但是还没有从中返回的过程使用。存放了相应过程的局部变量以及过程调用完成之后使用的返回地址。

thread_yield,它允许线程自动放弃cpu从而让另一个线程运行。

2.2.3–2.2.5 用户线程和内核线程

在这里插入图片描述

用户线程:在用户空间实现线程,内核对线程一无所知, 内核依然按照正常的方式管理,把进程当做单线程进程。

用户线程优缺点:

优点:

  1. 用户级线程包可以在不支持线程的操作系统上实现
  2. 线程切换不用陷入内核,不需要上下文切换,所以线程切换速度很快;
    2、允许每个进程有自己定制的调度算法。
    3、

缺点:

1、在如何实现阻塞系统调用上实现有困难,而如果采用非阻塞方案,需要修改原有的操作系统;
2、如果一个线程开始运行,那么该进程中其他线程就无法运行,除非第一个线程放弃CPU,那么线程的调度又是一个问题;

内核线程:在内核空间实现线程。

内核的线程表保存每个线程的寄存器、状态和其他信息。所有能够阻塞线程的调用都以系统调用的形式实现,这与运行时系统过程相比,代价是相当可观的。
由于在内核中创建和撤销线程的代价比较大,某些系统采取环保的处理方式,回收线程。当某个线程被撤销时,就把他标志为不可运行的,但是其内核数据结构没有受到影响。

混合实现

将用户级线程和内核级线程结合起来的方法。
1.使用内核级线程,然后将用户级线程与某些或者全部内核线程多路复用起来。

在这里插入图片描述

2.调度程序激活

**当使用调度程序激活机制时,内核给每个进程安排一定数量的虚拟处理器,并且让(用户空间)运行时系统将线程分配到处理器上。**这一机制也可以用在多处理器中,此时虚拟处理器可能成为真实的CPU。分配给一个进程的虚拟处理器的初始数量是一个,但是该进程可以申请更多的处理器并且在不用时退回。内核也可以取回已经分配出去的虚拟处理器,以便把它们分给需要更多处理器的进程。

使该机制工作的基本思路是,当内核了解到一个线程被阻塞之后(例如,由于执行了一个阻塞系统调用或者产生了一个页面故障),内核通知该进程的运行时系统并且在堆栈中以参数形式传递有问题的线程编号和所发生事件的一个描述。内核通过在一个已知的起始地址启动运行时系统,从而发出了通知,这是对UNIX中信号的一种粗略模拟。这个机制称为上行调用(upcall)

一旦如此激活,运行时系统就重新调度其线程,这个过程通常是这样的:把当前线程标记为阻塞并从就绪表中取出另一个线程,设置其寄存器,然后再启动之。稍后,当内核知道原来的线程又可运行时(例如,原先试图读取的管道中有了数据,或者已经从磁盘中读入了故障的页面),内核就又一次上行调用运行时系统,通知它这一事件。此时该运行时系统按照自己的判断,或者立即重启动被阻塞的线程,或者把它放入就绪表中稍后运行。

弹出式进程

一个消息的到达倒是系统创建一个处理该消息的线程,这种线程称为弹出式线程。
在这里插入图片描述

2.3进程间通信

竞争条件,多个进程读写某些共享数据时,可能会产生问题,最后结果取决于进程运行的精确时序。
我们对共享内存进行访问的程序片段称为临界区。
对于临界区有以下的要求:

  • 1、任何两个进程不能同时处于临界区
  • 2、与CPU的速度和数量无关
  • 3、临界区外的进程不得阻塞其他进程
  • 4、进程不能无限期等待

2.3.3忙等待互斥

互斥:当一个进程在临界区中更新内存时,其他进程不会进入其临界区,也不会带来任何麻烦。
实现方案:
1.屏蔽中断
在每个检查刚刚进入临界区后立即屏蔽所有中断,并在就要离开之前再打开中断。
但在一个多核系统中,屏蔽一个cpu的中断不会阻止其他cpu干预第一个cpu的操作。
2.锁变量
有一个共享锁变量,其初始值为0,当一个进程进入临界区时,它首先测试这把锁,如果该锁的值为0,则该进程将其设置为1并进入临界区。若已经为1,则该进程等待其值变为0.
但是,这种想法也包含了与假脱机目录一样的疏漏。假设一个进程读出锁变量的值并发现它为0,而恰好在它将其值设置为1之前,另一个进程被调度运行,将该锁变量设置为1。当第一个进程再次运行时,它同样也将该锁设置为1,则此时同时有两个进程进入临界区中。
3.严格轮换法
在下图中,整型变量turn,初始值为0,用于记录轮到哪个进程进入临界区,并检查或更新共享内存。开始时,进程0检查turn,发现其值为0,于是进入临界区。进程1也发现其值为0,所以在一个等待循环中不停地测试turn,看其值何时变为1。连续测试一个变量直到某个值出现为止,称为忙等待(busywaiting)。由于这种方式浪费CPU时间,所以通常应该避免。只有在有理由认为等待时间是非常短的情形下,才使用忙等待。用于忙等待的锁,称为自旋锁(spin lock)。
在这里插入图片描述
忙等待违反了条件3,进程0被一个临界区外的进程阻塞。
4.Peterson解法
在这里插入图片描述
现在考虑两个进程几乎同时调用enter_region的情况。它们都将自己的进程号存入turn,但只有后被保存进去的进程号才有效,前一个因被重写而丢失。假设进程1是后存入的,则turn为1。当两个进程都运行到while语句时,进程0将循环0次并进入临界区,而进程1则将不停地循环且不能进入临界区,直到进程0退出临界区为止。
TSL指令
需要硬件支持的一种方案:
TSL RX,LOCK
称为测试并加锁。
它将一个内存字lock读到寄存器RX中,然后在该内存地址上存一个非零值。读字和写字的操作保证是不可分割的,即在该指令结束之前其他处理器不允许访问该内存字,执行TSL指令的cpu将锁住内存总线,禁止其他cpu在本指令结束之前访问内存。

在这里插入图片描述

这条指令如何防止两个进程同时进入临界区呢?
解决方案如图2-25所示。
假定存在如下共4条指令的汇编语言子程序**。第一条指令将lock 原来的值复制到寄存器中并将lock 设置为1,随后这个原来的值与0相比较。如果它非零,则说明以前已被加锁,则程序将回到开始并再次测试。**经过或长或短的一段时间后,该值将变为0(当前处于临界区中的进程退出临界区时),于是过程返回,此时已加锁。要清除这个锁非常简单,程序只需将0存入lock即可,不需要特殊的同步指令。

一个可替代TSL的指令是XCHG,它原子性地交换了两个位置的内容,例如,一个寄存器与一个存储器字。代码如图2-26所示,而且就像可以看到的那样,它本质上与TSL的解决办法一样。所有的Intelx86 CPU在低层同步中使用XCHG指令。

2.3.4睡眠与唤醒

Peterson解法和TSL或XCHG的解法都是正确的,但他们都有忙等待的缺点。这些解法在本质上是这样的:当一个进程进入临界区时,先检查是否允许,若不允许,则进程原地等待,知道允许为止。

进程间的通信原语:
sleep:引起调用进程阻塞的系统调用,即被挂起。
wakeup:有一个参数,即要被唤醒的进程。

生产者消费者问题:
在这里插入图片描述

2.3.5信号量

Dijkstra建议设立两种操作:down和up(分别为一般化后的sleep和wakeup)。

down操作(P)

对一信号量执行down操作,则是检查其值是否大于0。若该值大于0,则将其值减1(即用掉一个保存的唤醒信号)并继续;若该值为O,则进程将睡眠,而且此时down操作并未结束。检查数值、修改变量值以及可能发生的睡眠操作均作为一个单一的、不可分割的原子操作完成。保证一旦一个信号量操作开始,则在该操作完成或阻塞之前,其他进程均不允许访问该信号量。
这种原子性对于解决同步问题和避免竞争条件是绝对必要的。所谓原子操作,是指一组相关联的操作要么都不间断地执行,要么都不执行。

up操作(V)

up操作对信号量的值增1。
如果一个或多个进程在该信号量上睡眠,无法完成一个先前的down操作,则由系统选择其中的一个(如随机挑选)并允许该进程完成它的down操作。于是,对一个有进程在其上睡眠的信号量执行一次up操作之后,该信号量的值仍旧是0,但在其上睡眠的进程却少了一个。
信号量的值增1和唤醒一个进程同样也是不可分割的。不会有某个进程因执行up而阻塞,

用信号量解决生产者-消费者问题
该解决方案使用了三个信号量:一个称为full,用来记录充满的缓冲槽数目;一个称为empty
记录空的缓冲槽数目,一个称为mutex,用来确保生产者和消费者不会同时访问缓冲区。full的初值为0,empty的初值为缓冲区中槽的数目,mutex初值为1。供两个或多个进程使用的信号量,其初值为1,保证同时只有一个进程可以进入临界区,称作二元信号量(binary semaphore)。如果每个进程在进入临界区前都执行一个down操作,并在刚刚退出时执行一个up操作,就能够实现互斥。
在这里插入图片描述

2.3.6 互斥量

mutex_lock和enter_region的区别
enter_region在进程上运行时,如果进入临界区失败,会忙等待,但是由于时钟超时的作用,会调度其他进程运行,这样迟早拥有锁的进程会进入运行并释放锁。
但是在线程上,由于没有时钟停止运行时间过长的线程。结果就是通过忙等待的方式试图获得锁的线程永远循环下去。
而后者取锁失败时,会调用thread_yield将cpu放弃给另一个线程,这样,就没有忙等待。

1.快速用户区互斥量futex
实现了基本的锁,但避免陷入内核

2.pthread中的互斥量
pthread提供许多可以同来同步线程的函数。

2.3.7管程

特性:任意时刻管程中只有一个活跃进程。 一个管程是一个由过程、变量以及数据结构等组成的一个集合,他们组成一个特殊的模块或软件包。

当一个进程调用管程过程时,该过程中的前几条指令将检查在管程中是否有其他的活跃进程。如果有,调用进程将被挂起,直到另一个进程离开管程将其唤醒。如果没有活跃进程在使用管程,则该调用进程可以进入。
wait和signal操作和sleep和wakeup关键区别:
sleep和wakeup之所以失败是因为当一个进程想睡眠时另一个进程试图去唤醒它。使用管程则不会发生这种情况。对管程过程的自动互斥保证了这一点:
如果管程过程中的生产者发现缓冲区满,它将能够完成wait操作而不用担心调度程序可能会在wait完成之前切换到消费者。甚至,在wait执行完成而且把生产者标志为不可运行之前,根本不会允许消费者进入管程。

2.3.9屏障

通常用于进程组,把他们的执行划分了不同阶段,每个阶段末尾设置一个屏障,只有所有进程都到达屏障,才能继续运行下一个阶段。

在这里插入图片描述

2.4 调度

多个进程同时竞争CPU,应该选择哪一个进程执行,这就由操作系统的调度程序完成,它内部实现了调度算法。

进程切换:
首先用户态必须切换到内核态;然后要保存当前进程的状态,包括在进程表中存储寄存器值以便以后重新装载。在许多系统中,内存映像(例如,页表内的内存访问位)也必须保存﹔
接着,通过运行调度算法选定一个新进程;之后,应该将新进程的内存映像重新装入MMU;最后新进程开始运行。
除此之外,进程切换还要使整个内存高速缓存失效,强迫缓存从内存中动态重新装入两次(进入内核一次,离开内核一次)。
总之,如果每秒钟切换进程的次数太多,会耗费大量CPU时间,所以有必要提醒注意。

在这里插入图片描述
何时调度

  1. 一个进程退出时
  2. 一个进程阻塞时
  3. I/O中断发生时

非抢占式系统:调度算法挑一个去运行,直到该进程阻塞或自动释放CPU。
抢占式系统:抢占式调度算法挑一个进程,让其运行某个固定时段的最大值,如果时段结束时还在运行,则挂起等待下一次运行,而调度程序挑选另一个进程运行。

调度算法目标如下:
在这里插入图片描述

批处理系统中的调度算法:

  • 1、非抢占式的先来先服务:按照请求CPU的顺序使用CPU。
  • 2、非抢占式最短作业优先:优先调度执行时间最短的
  • 3、最短剩余时间优先(抢占式最短作业优先):每次找到剩余运行时间最短的进程运行,当一个新的作业到达时,如果新的进程比当前运行进程需要更少时间,就运行新的进程。

交互式系统
1、轮转调度:每一个进程分配一个时间段,时间片结束时该进程还在运行,则剥夺cpu并分配给另一个进程,如果该进程在时间片结束前阻塞或结束,则cpu立即进行切换。

2、优先级调度:每个进程被赋予一个优先级,允许优先级最高的可运行进程先运行。
3、多级队列:举个例子,高优先级的进程先运行一个时间片,然后是次高级队列每个进程运行2个时间片,然后再次一级运行四个时间片。每个进程运行一次后,优先级降低一级。
3、多级队列:设立优先级类。属于最高优先级类的进程运行一个时间片,属于次高优先级类的进程运行2个时间片,再次一级运行4个时间片,以此类推。当一个进程用完分配的时间片后,它被移到下一类。

4、最短进程优先:选取执行时间最短的进程

5、保证调度:是向用户做出明确的性能保证,然后去实现它。一个简单的保证是:若系统工作时有n个用户登录,则每个用户获得1/n的CPU处理能力。同理,对于一个含有n个进程的系统,若所有进程都是等价的,则每个进程获得1/n的CPU时间。

6、彩票调度:其基本思想是向进程提供各种系统资源的彩票。一旦需要作出一项调整决策时就随机抽取一张彩票,拥有该彩票的进程获得资源。

7、公平分享调度:以上讲的各个进程调度算法关注的都是进程本身,并没有关注进程的所有者是谁。假如一个系统有两个用户,其中一个有9个进程,另一个只有一个进程。如果按照上述调度算法,用户1将获得90%的CPU实践,用户2只获得10%的时间。为了避免这种情形,操作系统必须考虑这一因素,定义一个公平策略。例如每个用户分得50%的CPU时间保证,无论用户有多少个进程存在,每个用户都会得到应有的CPU份额。
实时系统的调度

硬实时调度:在绝对截止时间前完成

软实时调度:在某个时间附近完成调度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/735349.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【azcopy】

azcopy 下载使用输出 下载 https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10#download-azcopy使用 cd /Users/YJY/Downloads/azcopy_darwin_amd64_10.19.0./azcopy copy https://tapvqacaption.blob.core.windows.net/data/save /Users/YJY/D…

多元分类预测 | Matlab 灰狼算法(GWO)优化xgboost的分类预测模型,多特征输入模型,GWO-xgboost分类预测

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元分类预测 | Matlab 灰狼算法(GWO)优化xgboost的分类预测模型,多特征输入模型,GWO-xgboost分类预测 多特征输入单输出的二分类及多分类模型。程序内注释详细,直接替换数据就可以用。程序语言为matlab,程序可…

【分布式应用】zabbix:代理服务器、及监控其它应用

目录 一、部署 zabbix 代理服务器1.环境配置1.2设置 zabbix 的下载源,安装 zabbix-proxy1.3部署数据库1.4在 Web 页面配置 agent 代理1.5 配置 agent 使用 proxy 二、Zabbix 监控 Windows 系统三、zabbix监控java应用3.1、客户端开启 java jmxremote 远程监控功能3.…

C语言程序设计——数据在内存中的存储

一、数据类型介绍 1.基本内置类型 char // 字符数据类型 1 B short // 短整型 2 B int // 整型 4 B long // 长整型 4 or 8 B long long //更长的整型 8 B float //单精度浮点型 4 B double //双精…

自动化漏洞挖掘方式

自动化漏洞挖掘方式 一、Goby安装使用1.1、goby简介1.2、goby下载安装1.3、简单扫描1.4、Goby插件 二、Xray安装使用2.1、XRAY简介2.2、Xray安装2.3、Xray使用2.4、爬虫模式(主动扫描)2.5、被动扫描2.6、BurpSuite联动Xray2.7、Rad联动Xray 一、Goby安装…

X、Y、Z轴上旋转角度的Eigen::Vector3d对象转换为一个旋转矩阵

#include <iostream> #include <Eigen/Core> #include <Eigen/Geometry>using namespace std; using namespace Eigen;

django框架中使用ORM设计数据库的模型

ORM关联数据的逻辑是&#xff1a; Django 中常见的模型字段类型及其含义&#xff1a; AutoField&#xff1a;一个自动递增的整型字段&#xff0c;添加记录时它会自动增长。BigAutoField&#xff1a;一个自动递增的 biginteger字段&#xff0c;添加记录时它会自动增长。CharFie…

数据结构之图

7 图的存储 &#xff08;1&#xff09;图的邻接矩阵存储 对于无向图&#xff0c;邻接矩阵第i行/列上非零元素个数是顶点vi的度。 对于有向图&#xff0c;邻接矩阵第i行上非零元素个数是顶点vi的出度&#xff0c;第i列 上非零元素个数是顶点vi的入度。 对于带权有向图有边则…

常见面试题之垃圾收回

1. 简述Java垃圾回收机制&#xff1f;&#xff08;GC是什么&#xff1f;为什么要GC&#xff1f;&#xff09; 为了让程序员更专注于代码的实现&#xff0c;而不用过多的考虑内存释放的问题&#xff0c;所以&#xff0c;在Java语言中&#xff0c;有了自动的垃圾回收机制&#x…

javaUDP数据报套接字编程

0.前言 对于UDP协议来说&#xff0c;具有无连接&#xff0c;面向数据报的特征&#xff0c;即每次都是没有建立连接&#xff0c;并且一次发送全部数 据报&#xff0c;一次接收全部的数据报。 java中使用UDP协议通信&#xff0c;主要基于 DatagramSocket 类来创建数据报套接字&a…

探索人工智能的奇妙世界:解密AI技术的未来发展

作为一名热爱技术的开发者&#xff0c;当谈到人工智能&#xff08;AI&#xff09;和焦虑商业化时&#xff0c;我总会面临一个困境&#xff1a;到底是愁眉苦脸&#xff0c;还是开怀大笑&#xff1f;让我带你走进这个有趣又争议的话题。 首先我们需要面对AI的自学能力。这些智能…

Django4.0+使用rest_framework_jwt的问题

问题描述 python版本&#xff1a;3.10 Django版本&#xff1a;4.1 djangorestframework-jwt版本&#xff1a;1.11.0 在写jwt认证功能时&#xff0c;发现run的时候会报以下错误 from django.utils.translation import ugettext as _ ImportError: cannot import name ugettext…

day69_Vue进阶

今日内容 零、 复习昨日 零、 复习昨日 nginx 静态服务器(动静分离)反向代理服务器(代理后端服务器)负载均衡异步 前端工程化 —> java代码工程 一、使用Vue-Cli搭建Vue项目 1.1 什么是vue-cli cli: Command Line 命令行工具&#xff0c;vue-cli就是vue的命令行工具&#xf…

ThreadPoolExecutor 线程池源码学习

ThreadPoolExecutor 线程池源码学习 1.阅读源码 1.ThreadPoolExecutor.execute public void execute(Runnable command) {if (command null)throw new NullPointerException();// ctl 高三位记录线程状态。低29位记录线程池中线程数int c ctl.get();//位运算获取工作线程数 …

wireshark抓包实践

目录 ifconfig ( network interfaces configuring )tcpdump 命令tcpdump&wireshark例子 ifconfig ( network interfaces configuring ) eth0表示网卡UP代表网卡开启状态RUNNING代表网卡的网线被接上mtu1500: MTU&#xff08;最大传输单元&#xff09;是指在网络中传输数据时…

【javaEE面试题(五)在JMM(Java Memory Model (Java 内存模型))下谈volatile的作用】

volatile的作用 JMM下volatile作用 volatile 能保证内存可见性 volatile 修饰的变量, 能够保证 “内存可见性”. 代码在写入 volatile 修饰的变量的时候 改变线程工作内存中volatile变量副本的值将改变后的副本的值从工作内存刷新到主内存 代码在读取 volatile 修饰的变量的时…

B067-基础环境-抽取Basegit

目录 抽取base抽取domain和querymapper接口抽取service抽取 Git优点&#xff1a;Git安装及操作Git Bash命令行操作图形化客户端TortoiseGit操作Git集成Idea操作idea会把workspace作为本地仓库gitee操作idea解决代码冲突 抽取base 抽取domain和query domain&#xff1a;所有实体…

Nodejs 依赖包的存放路径设置(按其他博客修改路径后,安装路径仍在C盘的解决办法)

Nodejs 依赖包的存放路径设置 使用命令npm root -g 查看依赖包的安装位置 默认依赖包的安装位置是在C盘。为了防止C盘存太多东西&#xff0c;我这里已经将安装位置改到了D盘&#xff0c;下面就记录下修改的步骤。 1. 创建新的依赖包安装目录 在 nodejs 的安装目录下创建两个新…

8年资深测试总结,性能测试+性能优化(详细)进军高级测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能优化常见概念…

LabVIEW FPGA利用响应式数字电子板快速开发空间应用程序

LabVIEW FPGA利用响应式数字电子板快速开发空间应用程序 与传统的基于文本的语言相比&#xff0c;LabVIEW的编程和设计已被证明可以缩短开发时间。各种研究表明&#xff0c;生产率的提高在3到10倍之间。LabVIEW通过图形语言、集成开发环境和多个编译器的组合来实现这一点。 图…