操作系统
内容:
1.操作系统简介
2.进程
3.线程
4.协程
5.IO多路复用
操作系统:http://www.cnblogs.com/Eva-J/articles/8253521.html
进程:https://www.cnblogs.com/Eva-J/articles/8253549.html
线程:https://www.cnblogs.com/Eva-J/articles/8306047.html
协程:https://www.cnblogs.com/Eva-J/articles/8324673.html
IO:https://www.cnblogs.com/Eva-J/articles/8324837.html
一、操作系统简介
1.什么是操作系统
操作系统位于计算机硬件与应用软件之间,本质也是一个软件。操作系统由操作系统的内核(运行于内核态,管理硬件资源)以及系统调用(运行于用户态,为应用程序员写的应用程序提供系统调用接口)两部分组成
所以,单纯的说操作系统是运行于内核态的,是不准确的。
2.操作系统作用
- 基本功能:处理机管理、存储器管理、设备管理和文件管理
- 隐藏丑陋复杂的硬件接口,提供良好的抽象接口,提供方便的用户接口
- 管理、调度进程,并且将多个进程对硬件的竞争变得有序
- 提高系统资源利用率,方便用户使用
3.操作系统发展
- 穿孔卡片 - 没有操作系统的概念,所有的程序设计都是直接操控硬件
- 批处理系统 - 依然是串行,批处理,磁带存储
- 多道程序设计 - 多道技术,空间复用和时间复用(宏观上并行,微观上串行)
- 多道批处理 - 提高系统资源利用率和系统吞吐量、多道、无交互能力
- 分时系统 - 多联机终端、多道技术、分时技术(多路性、交互性、及时性、独立性)
4.补充
多道技术:
- 产生背景:针对单核,实现并发(现在的主机一般是多核,那么每个核都会利用多道技术)
- 例如有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个cpu中的任意一个,具体由操作系统调度算法决定
- 空间上的复用:如内存中同时有多道程序
- 时间上的复用:复用一个cpu的时间片
- 强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样才能保证下次切换回来时,能基于上次切走的位置继续运行
二、进程
1.什么是进程
顾名思义,进程即正在执行的一个过程。进程是对正在运行程序的一个抽象
进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一。操作系统的其他所有内容都是围绕进程的概念展开的。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元
程序和进程的区别:
- 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
- 而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
- 程序可以作为一种软件资料长期存在,而进程是有一定生命期的。
- 程序是永久的,进程是暂时的。
2.进程调度
想多个进程交替运行,操作系统必须对这些进程进行调度,这个调度不是随机进行的,而需要遵循一定的法则,由此就有了进程的调度算法:
- 先来先服务调度算法
- 短作业优先调度算法
- 时间片轮转法
- 多级反馈队列
3.进程的并发与并行
并行 : 并行是指两者同时执行(多核同时刻运行多个进程)
并发 : 并发是指资源有限的情况下,两者交替轮流使用资源,目的是提高效率(单CPU多进程并发)
区别:
- 并行是从微观上,在一个精确的时间点上有不同的程序在执行,这就要求必须有多个处理器(多核CPU)
- 并发是从宏观上,在一个时间段不同的程序在同时执行的,比如一个服务器同时处理多个任务
4.同步、异步、阻塞、非阻塞
(1)进程3状态
如上图进程有三个状态:就绪,运行和阻塞
- 就绪状态:当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态
- 执行/运行状态:当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态
- 阻塞状态:正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理而处于阻塞状态。引起进程阻塞的事件可有多种,例如等待I/O完成、申请缓冲区不能满足、等待信件(信号)等
进程三状态实例:
(2)同步与异步
同步:一个进程在执行某个任务时,另一个进程必须等待其执行完毕,才能继续执行,同一时间只能做一个操作
异步:一个进程在执行某个任务时,另一个进程无需等待其执行完毕,就可以继续执行,当有消息返回时,系统会通知后者进行处理,这样可以提高执行效率,同一时间可以做两个操作
(3)阻塞与非阻塞
阻塞与非阻塞与线程等待消息通知(无所谓同步异步)时的状态有关,主要是程序(线程)等待消息通知时的状态角度来说的
注:很多时候同步操作会以阻塞的形式表现出来,而异步操作一般都不会在真正的IO操作处被阻塞
简单说程序到了IO处就停止运行就是阻塞(python),而程序到了IO处继续向后执行就是非阻塞(node.js)
5.进程的创建与结束
(1)进程的创建
- 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)
- 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)
- 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)
- 一个批处理作业的初始化(只在大型机的批处理系统中应用)
注:无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的
(2)进程的结束
- 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)
- 出错退出(自愿,python a.py中a.py不存在)
- 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)
- 被其他进程杀死(非自愿,如kill -9)
三、线程
1.线程的引入及背景
(1)进程
程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。
程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。
在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行。这是这样的设计,大大提高了CPU的利用率。
进程的出现让每个用户感觉到自己独享CPU,因此,进程就是为了在CPU上实现多道编程而提出的
(2)有进程为什么需要线程
进程虽然有优点,但是也有缺点:
-
进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了
-
进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行
而线程可以很好地解决这些缺陷
引入线程的原因:减少程序在并发执行时所付出的时空开销,使OS具有更好的并发性
(3)线程的出现
2.进程与线程的区别
- 地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见
- 通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性
- 调度和切换:线程上下文切换比进程上下文切换要快得多
- 在多线程操作系统中,进程不是一个可执行的实体
3.线程的特点
- 轻型实体(不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源)
- 独立调度和分派的基本单位、切换非常迅速且开销小(在同一进程中的)
- 在同一进程中的各个线程可以共享进程资源
- 可并发执行
4.内存中的线程
多个线程共享同一个进程的地址空间中的资源,是对一台计算机上多个进程的模拟,有时也称线程为轻量级的进程;而对一台计算机上多个进程,则共享物理内存、磁盘、打印机等其他物理资源。多线程的运行也多进程的运行类似,是cpu在多个线程之间的快速切换。
不同的进程之间是充满敌意的,彼此是抢占、竞争cpu的关系,如迅雷会和QQ抢资源。而同一个进程是由一个程序员的程序创建,所以同一进程内的线程是合作关系,一个线程可以访问另外一个线程的内存地址,大家都是共享的
类似于进程,每个线程也有自己的堆栈,不同于进程,线程库无法利用时钟中断强制线程让出CPU,可以调用thread_yield运行线程自动放弃cpu,让另外一个线程运行
线程通常是有益的,但是带来了不小程序设计难度,线程的问题是:
- 父进程有多个线程,那么开启的子线程是否需要同样多的线程
- 在同一个进程中,如果一个线程关闭了文件,而另外一个线程正准备往该文件内写内容呢?
因此,在多线程的代码中,需要更多的心思来设计程序的逻辑、保护程序的数据
四、协程
1.协程介绍
协程:是单线程下的并发,又称微线程,纤程
一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。、
注意:
1 python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行) 2 单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(!!!非io操作的切换与效率无关)
对比操作系统控制线程的切换,用户在单线程内控制协程的切换
优点:
- 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
- 单线程内就可以实现并发的效果,最大限度地利用cpu
缺点:
- 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
- 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
协程特点:
- 必须在只有一个单线程里实现并发
- 修改共享数据不需加锁
- 用户程序里自己保存多个控制流的上下文栈
- 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))
2.greenlet模块
(1)安装
pip3 install greenlet
(2)greenlet模块使用
1 # 使用greenlet模块 2 # 真正的协程就是使用greenlet模块完成切换 3 from greenlet import greenlet 4 5 6 def eat(name): 7 print('%s eat 1' % name) 8 g2.switch('egon') 9 print('%s eat 2' % name) 10 g2.switch() 11 12 13 def play(name): 14 print('%s play 1' % name) 15 g1.switch() 16 print('%s play 2' % name) 17 18 19 g1 = greenlet(eat) 20 g2 = greenlet(play) 21 22 g1.switch('egon') # 可以在第一次switch时传入参数,以后都不需要
3.gevent模块
(1)介绍
安装:pip3 install gevent
Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度
(2)用法
(3)同步与异步
4、协程应用
(1)爬虫
(2)通过gevent实现单线程下的socket并发
五、IO多路复用