操作系统发展史
1
.第一带计算机 真空管和穿孔卡片 没有进程 没有操作系统
2.第二代计算机 7094 1401
晶体管 批处理系统
输入输出 以及计算设备 不能互联 需要人参与 一批一批的处理 开发效率慢 并且串行执行
3
.第三代计算机 集成电路 与多道技术
多终端联机 spooling 同一台机器既能进行科学计算 又能做字符处理 通用计算机
多道技术 解决串行导致的效率低下问题
多用户终端 可以同时为多个用户提供服务 每个用户以为自己独享一台计算机
4
.第四代 个人电脑
大规模使用了集成电路,大多都提供了GUI界面
多道技术
产生背景 ,所有程序串行 导致资源浪费
目的是让多个程序可以并发执行 , 同时处理多个任务
空间复用
指的是 同一时间 内存中加载多个不同程序数据,
每个进程间内存区域相互隔离,物理层面的隔离
时间复用 切换 +
保存
切换条件:
1
.一个进程执行过程中遇到了IO操作 切换到其他进程
2
.运行时间过长,会被操作系统强行剥夺执行权力
单纯的切换不够,必须在切换前保存当前的状态,以便于恢复执行
进程
一个正在被运行的程序就称之为进程,是程序具体执行过程,一种抽象概念
进程来自于操作系统
进程和程序的区别
程序就是一堆计算机可以识别文件,程序在没有被运行就是躺在硬盘上的一堆二进制
运行程序时,要从硬盘读取数据到内存中,CPU从内存读取指令并执行 ,
一旦运行就产生了进程
一个程序可以多次执行 产生多个进程,但是进程之间相互独立
当我们右键运行了一个py文件时 ,其实启动的是python解释器,你的py文件其实是当作参数传给了解释器
同步 异步 阻塞 非阻塞 并发 并行
同步 异步 指的是任务的提交方式
1
.同步:任务提交之后 原地等待的任务的执行并拿到返回结果才走 期间不做任何事(程序层面的表现就是卡住了)
2.异步:任务提交之后 不再原地等待 而是继续执行下一行代码(结果是要的 但是是用过其他方式获取)
阻塞 非阻塞 指的是程序的运行状态
阻塞 : 程序遇到io操作是就进入了阻塞状态 ,程序无法继续执行其他代码
本地IO input print sleep read write
网络IO recv send
非阻塞: 程序正常运行中 没有任何IO操作 就处于非阻塞状态 ,或者通过某种方式使程序即时遇到了也不会停在原地,还可以执行其他操作,以提高CPU的占用率
并发 并行 说的是 任务的处理方式
并发: 多个任务看起来同时在处理 ,本质上是切换执行 速度非常快
并行: 多个任务真正的同时执行 必须具备多核CPU 才可能并行
进程的三种状态
就绪态,运行态,和阻塞态
多道技术会在进程执行时间过长或遇到IO时自动切换其他进程,意味着IO操作与进程被剥夺CPU执行权都会造成进程无法继续执行
创建进程
创建进程就是在内存中重新开辟一块内存空间,将允许产生的代码丢进去,一个进程对应在内存就是一块独立的内存空间
进程与进程之间数据是隔离的 无法直接交互,但是可以通过某些技术实现间接交互
实例化Process,将要执行任务用target传入
from multiprocessing
import Process
import time
def test(name):
print(
'%s is running'%
name)
time.sleep(2
)
print(
'%s is over'%
name)
# windows创建进程会将代码以模块的方式 从上往下执行一遍
# linux会直接将代码完完整整的拷贝一份
# windows创建进程一定要在if __name__ == '__main__':代码块内创建 否则报错
if __name__ ==
'__main__':
# 创建一个进程对象
p = Process(target=test,args=(
'lolo',))
# 告诉操作系统帮你创建进程
p.start()
print(
'主')
1
继承Process,并覆盖run方法, 将任务放入run方法中
from multiprocessing
import Process
import time
class MyProcess(Process):
def __init__(self,name):
super().__init__()
self.name =
name
def run(self):
print(
'%s is running'%
self.name)
time.sleep(2
)
print(
'%s is over'%
self.name)
if __name__ ==
'__main__':
p = MyProcess(
'coco')
p.start()
print(
'主')
2
1
.在windows下 开启子进程必须放到__main__下面,因为windows在开启子进程时会重新加载所有的代码造成递归创建进程
2
.第二种方式中,必须将要执行的代码放到run方法中,子进程只会执行run方法其他的一概不管
进程间内存相互隔离
join函数
Process的对象具备一个join函数
用于提高子进程优先级 ,使得父进程等待子进程结束
from multiprocessing
import Process
import time
def test(name,i):
print(
'%s is running'%
name)
time.sleep(i)
print(
'%s is over'%
name)
if __name__ ==
'__main__':
p_list =
[]
for i
in range(3
):
p = Process(target=test,args=(
'进程%s'%
i,i))
p.start()
p_list.append(p)
for p
in p_list:
p.join()
p1 = Process(target=test,args=(
'dodo',2
))
p2 = Process(target=test,args=(
'lolo',1
))
p1.start()
p2.start()
p1.join()
View Code
进程间相互隔离
from multiprocessing
import Process
money = 100
def test():
global money
money = 888
if __name__ ==
'__main__':
p = Process(target=
test)
p.start()
p.join()
print(money)
验证
进程对象及其它方法
from multiprocessing
import Process,current_process,active_children
import os
import time
def test(name):
print(
'%s is running'%
name,current_process().pid)
print(
'%s run'%
name,os.getpid(),os.getppid())
time.sleep(1
)
print(
'%s is over'%
name)
if __name__ ==
'__main__':
p = Process(target=test,args=(
'lolo',))
p.start()
p.terminate()
# 杀死当前进程 其实是告诉操作系统帮你杀死一个进程
print(p.is_alive())
# 判断进程是否存活
print(
'主',os.getpid(), os.getppid())
View Code
# p.join() # 等待子进程结束
# p.terminate() # 终止进程
# print(p.name) # 进程的名称
# print(p.is_alive()) #是否存活
# p.terminate() # 与start一样 都是给操作系统发送指令 所以会有延迟
# print(p.is_alive())
# print(p.pid)
# print(p.exitcode) # 获取退出码
守护进程
进程:一个正在运行的程序。
主进程创建守护进程:
1.守护进程会在主进程代码执行结束后就终止,
2.守护进程内无法再开启子进程,否则抛出异常。
注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止。
from multiprocessing
import Process
import time
def teat(name):
print(
'%s 在'%
name)
time.sleep(1
)
print(
'%s 不在'%
name)
if __name__ ==
'__main__':
p = Process(target=teat,args=(
'coco',))
p.daemon =
True
p.start()
# p.daemon = True
time.sleep(0.1
)
print(
'老板不在')
View Code
僵尸进程与孤儿进程
孤儿进程
孤儿进程指的是开启子进程后,父进程先于子进程终止了,那这个子进程就称之为孤儿进程
孤儿进程是无害的,有其存在的必要性,在父进程结束后,其子进程会被操作系统接管。
僵尸进程
僵尸进程指的是,当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被操作系统接管,子进程退出后操作系统会回收其占用的相关资源!
僵尸进程的危害:
由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。
在Linux中,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,
在python中,已经封装好了wait操作不需要我们自己清理。
但是系统所能使用的进程号是有限的,如果大量的产生[僵死进程],将因为没有可用的进程号而导致系统不能产生新的进程. 此为僵尸进程的危害,应当避免。
互斥锁
互相排斥的锁(如果这个资源已经被锁了,其他进程就无法使用了)
需要强调的是: 锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行。
使用场景:
并发将带来资源的竞争问题,
当多个进程同时要操作同一个资源时,将会导致数据错乱的问题。
解决方案1:
加join,
例子:
from multiprocessing
import Process
import time
def task1():
print(
'你好,阿森。。。')
time.sleep(3
)
print(
'吃饭')
time.sleep(3
)
print(
'下雨')
def task2():
print(
'你好,阿三。。。')
time.sleep(3
)
print(
'吃面')
time.sleep(3
)
print(
'下雪')
def task3():
print(
'你好,阿四。。。')
time.sleep(3
)
print(
'吃米')
time.sleep(3
)
print(
'下冰雹')
if __name__ ==
'__main__':
p1 = Process(target=
task1)
p2 = Process(target=
task2)
p3 = Process(target=
task3)
p1.start()
p1.join()
p2.start()
p2.join()
p3.start()
p3.join()
弊端: 1
.把原本并发的任务变成了穿行,避免了数据错乱问题,但是效率降低了,这样就没必要开子进程了。
2
.原本多个进程之间是公平竞争,join执行的顺序就定死了,这是不合理的。
解决方案2:
就是给公共资源加 锁----
互斥锁。
例子:
from multiprocessing
import Process,Lock
import time,random
def task1(lock):
# 上锁
lock.acquire()
#就等同于一个if判断
print(
'你好,阿森。。。')
time.sleep(random.randint(0,3
))
print(
'吃饭')
time.sleep(random.randint(0, 3
))
print(
'下雨')
#解锁
lock.release()
def task2(lock):
lock.acquire()
print(
'你好,阿三。。。')
time.sleep(random.randint(0, 3
))
print(
'吃面')
time.sleep(random.randint(0, 3
))
print(
'下雪')
lock.release()
def task3(lock):
lock.acquire()
print(
'你好,阿四。。。')
time.sleep(random.randint(0, 3
))
print(
'吃米')
time.sleep(random.randint(0, 3
))
print(
'下冰雹')
lock.release()
if __name__ ==
'__main__':
lock=
Lock()
p1=Process(target=task1,args=
(lock,))
p2=Process(target=task2,args=
(lock,))
p3=Process(target=task3,args=
(lock,))
p1.start()
p2.start()
p3.start()
View Code
# 注意1: 不要对同一把执行多出acquire 会锁死导致程序无法执行 一次acquire必须对应一次release
from multiprocessing
import Lock
l=
Lock()
l.acquire()
print(
'抢到了')
l.release()
l.acquire()
print(
'接着抢')
# 注意2:想要保住数据安全,必须保住所有进程使用同一把锁
锁和join的区别:
1. join是固定了执行顺序,会造成父进程等待子进程完成后完成
锁是公平竞争谁先抢到谁先执行,父进程可以做其他事情、
2. join是把进程的任务全部串行
锁可以锁任意代码 ,一行也可以 可以自己调整粒度
粒度:
粒度越大意味着锁住的代码越多 效率越低
粒度越小意味着锁住的代码越少 效率越高
MYSQL 中不同隔离级别 其实就是不同的粒度
小练习 -- 抢票
"""
过程:
1.查看余票,
2.有就买,无失败
os.getpid()获取当前进程id
#文件db的内容为:{"count":1}
#注意一定要用双引号,不然json无法识别
"""
from multiprocessing
import Process, Lock
import json, random, time, os
def check_ticket():
with open('ticket.json',
'rt', encoding=
'utf-8')as a:
data =
json.load(a)
time.sleep(random.randint(0, 3
))
print(
'%s正在查票,票还有%s' % (os.getpid(), data[
"count"]))
def buy_ticket():
with open('ticket.json',
'rt', encoding=
'utf-8')as a:
data =
json.load(a)
if data[
"count"] >
0:
data["count"] -= 1
# 模拟延迟
time.sleep(random.randint(0, 3
))
with open('ticket.json',
'wt', encoding=
'utf-8')as a:
json.dump(data, a)
print(
'%s恭喜你抢票成功' %
os.getpid())
else:
print(
'%s抢票失败,开个加速包试一试' %
os.getpid())
def task(lock):
check_ticket()
lock.acquire()
buy_ticket()
lock.release()
if __name__ ==
'__main__':
lock =
Lock()
# 三个人抢票
for i
in range(10
):
p = Process(target=task, args=
(lock,))
p.start()
抢票
转载于:https://www.cnblogs.com/komorebi/p/11348565.html
相关资源:JAVA上百实例源码以及开源项目