(一)操作系统
1、为什么要有操作系统?
现代计算机系统是由一个或者多个处理器,主存,磁盘,打印机,键盘,鼠标显示器,网络接口以及各种其他输入输出设备组成的复杂系统,每位程序员不可能掌握所有系统实现的细节,并且管理优化这些部件是一件挑战性极强的工作。所以,我们需要为计算机安装一层软件,成为操作系统,任务就是用户程序提供一个简单清晰的计算机模型,并管理以上所有设备。
定义也就有了:操作系统是一个用来协调、管理和控制计算机硬件和软件资源的系统程序,它位于硬件和应用程序之间。(程序是运行在系统上的具有某种功能的软件,比如说浏览器,音乐播放器等。)
操作系统的内核的定义:操作系统的内核是一个管理和控制程序,负责管理计算机的所有物理资源,其中包括:文件系统、内存管理、设备管理和进程管理。
2、操作系统历史
2.1 真空管与穿孔卡片(无操作系统)
过程:
万能程序员们将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机 内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果并卸下纸带(或卡片)后,才让下一个用户上机。
注意点:
1 程序员需要在墙上的计时表上预约时间
2 同一时刻只有一个程序在内存中被CPU调用运行(串行的)优缺点:
优点:程序员在申请的时间段内独享整个资源,即时的调试自己的程序,如果有bug可以当场处理,
缺点:这对于计算机提供商来说是一种浪费(你买一台电脑4000块,那 一年中你用365比只用1天,肯定是省成本的,物尽其用)
2.2 晶体管和批处理系统
一代计算机的问题:
人机交互太多了(输入--->计算--->输出 输入--->计算--->输出 输入--->计算--->输出 )
解决办法:
把一堆人的输入攒成一大波输入,然后顺序计算(这是有问题的,但是第二代计算没有解决)再把计算结果攒成一大波输出,这就是批处理系统
操作系统前身:在收集了大约一个小时的批量作业之后,这些卡片被读入磁带,然后磁带被送到机房里并装到磁带上。然后磁带被送到机房里并装到磁带机上。随后,操作员装入一个特殊的程序(此乃现代操作系统的前身),它负责从磁带上读入第一个作业(job,一个或一组程序)并运行,其输出写到第二个磁带上,而且不打印。每个作业结束后,操作系统自动的从磁带上读入下一个作业并且运行。当一整批的作业全部结束后,操作员去下输入和输出磁带,讲输入磁带换成下一批作业,并且把输出磁带拿到一台1041机器上进行脱机(不与主计算机联机)打印
优点:批处理
缺点:
1 图的中间还有俩小人
2 仍然是顺序计算
2.3 集成电路芯片和多道程序设计
针对二代计算机的两个主要问题
开发出SPOOLING技术:
卡片被拿到机房后能够很快的将作业从卡片读入磁盘,于是任何时刻当一个作业结束时,操作系统就能将一个作业从磁带读出,装进空出啦的内存区域运行,这种技术叫做同时的外部设备联机操作:SPOOLING该技术同时用于输出。当采用了这种技术后,就不在需要IBM1401机了,也不必将磁带搬来搬去了(中间俩小人失业了),强化了操作系统的功能开发出多道程序设计,用于解决顺序执行的问题:
在7094机上(程序运行的机器),若当前作业因等待磁带或等待其他IO操作而暂停,CPU就处于休闲状态直至IO操作完成,对于CPU密集的科学计算,IO操作少,浪费时间不明显,对于商业数据处理,IO等待能到达80%~90%,所以必须解决CPU浪费的现象。
解决方案:将内存分为几个部分,每一部分存放不同的作业,如图1-5所示。当一个作业等待IO完成时,另一个作业可以使用CPU,内存中放足够的作业,则CPU的利用率能接近100%
此时的第三代计算机适合大型科学计算和繁忙的商务数据处理,但,本质上其仍是一个批处理系统。
虽然解决了诸如以上问题,但多个作业必须在全部运行结束后,才能得到结果,从一个作业的提交到运算结果取回往往长达数小时。
想象一个场景:A君 B君 C君 三个程序员同时在调试程序,一旦A君写错一个逗号,那么可能需要半天的时间才能看到结 果,因为B君C君的结果也同时运算出来了。时间必然要长。一言以蔽之:大家一起存作业,大家一起去数据(磁带)许多程序员怀念第一代独享的计算机,可以即时调试自己的程序。为了满足程序员们很快可以得到响应,出现了分时操作系统
分时操作系统:多个联机终端+多道技术20个客户端同时加载到内存,有17在思考,3个在运行,cpu就采用多道的方式处理内存中的这3个程序,由于客户提交的一般 都是简短的指令而且很少有耗时长的,索引计算机能够为许多用户提供快速的交互式服务,所有的用户都以为自己独享了计算机资源
2.4 个人计算机
随着大规模集成电路的发展,每平方厘米的硅片芯片上可以集成数千个晶体管,个人计算机的时代就此到来。
(二)进程
1、定义
进程就是一个程序在一个数据集上的一次动态执行过程,是最小的资源单位。
2、组成
进程一般由程序、数据集、进程控制块三部分组成。
2.1)我们编写的程序:用来描述进程要完成哪些功能以及如何完成;
2.2)数据集则是程序在执行过程中所需要使用的资源;
2.3)进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
3、切换
I/O操作、时间轮询
4、并行与并发
并行:同时间运行,没有任何切换
并发:通过切换达到看起来几乎同时运行的效果
一个cpu只能并发,不能并行,并行要多个cpu才能实现
5、通信
进程占独立的内存空间,其他应用进程不能直接访问,需要进程间的通信。
(三)线程
- 线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷, 使到进程内并发成为可能。
- 线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。
- 线程没有自己的系统资源,共享整个进程的资源,切换代价比进程小得多 。
1、定义
线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成
2、线程和进程的区别
2.1)一个程序至少有一个进程,一个进程至少有一个线程.(进程可以理解成线程的容器)
2.2)进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
2.3)线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
2.4)进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器(保存的是地址),一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源,一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
3、python的线程
3.1 导入线程模块
- import threading
- threading 模块建立在thread 模块之上。thread模块以低级、原始的方式来处理和控制线程,而threading 模块通过对thread进行二次封装,提供了更方便的api来处理线程。
3.2 创建线程对象
线程对象名 = threading.Tread(target=函数名,args=参数元组)
3.3 激活线程
线程对象名.start(),本质上是调用了run()方法,start并没有立刻启动线程,而是让线程处于就绪状态,可以被cpu切换执行。
import threading
import time
def sayhi(num): #定义每个线程要运行的函数
print("running on number:%s" %num)
time.sleep(3)
if __name__ == '__main__':
t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例
t1.start() #启动线程
t2.start() #启动另一个线程
print(t1.getName()) #获取线程名
print(t2.getName())
3.4 让主线程等待子线程结束后再继续运行
- 线程对象名.join()
- 在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
3.5 设置守护线程
在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程就分兵两路,分别运行,那么当主线程完成想退出时