day30_8.9 操作系统与并发编程
一。操作系统相关
1.手工操作
1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式。此时还没有操作系统的概念。
这时候的计算机是由人为将穿孔的纸带装入输入机,控制台获取到数据和操作后进行计算,计算完后打印结果,最后用户取走纸带放入下一个用户的纸带。
手工操作方式两个特点:
2.批处理
手工搬运纸带输入操作,这一方式中人为干预的时间远远超过了计算机计算的时间,在搬运纸带的过程中,cpu处于高度空闲状态,为了解决这种人机矛盾,第一代类似于操作系统的批处理系统出现了。
将成批的指令输入输入机,输入机由卫星机获取数据转交给高速磁带,高速磁带再将数据交给主机,输出也是通过卫星机。
卫星机是一种不与主机直接相连的专门用于与输入输出设备打交道的。
其功能是:
不足:每次主机内存中仅存放一道作业,每当它运行期间发出输入/输出(I/O)请求后,高速的CPU便处于等待低速的I/O完成状态,致使CPU空闲。
3.多道程序设计。
因为初始批处理系统只能同时操作一个程序,当程序进入i/o操作时,cpu会出现大量空闲时间。cpu利用率大大降低。为了解决这个问题,躲到程序系统产生了。
多道程序系统就是在程序进入io操作时,切换另一个程序的cpu运算工作,然后循环切换程序进行cpu操作,这样的方式称为统筹,这样的cpu利用率才是最大的。
4.分时系统。
为了使得在电脑上可以同时运行两个程序,比如边用qq聊天边听音乐,操作系统将cpu对程序的计算分成很小的时间片,这些时间片轮流执行各个程序,看起来就像时同时计算一样,但是强行结束程序会大大减少运算效率,但是这样时为了实现看起来共同执行的效果。
总结
总之,为了充分利用cpu,操作系统会想办法让cpu不断地进行计算。、
二。进程
进程就是一个正在执行的程序,是操作系统提供的最古老的抽象概念之一。
1.多道技术。
(1)空间上的复用
多个程序共用一套计算机硬件。
(2)时间上的复用
实现时间复用就是用切换+保存状态实现。
当一个程序遇到IO操作 操作系统会剥夺该程序的cpu执行权限(提高了cpu的利用率 并且也不影响程序的执行效率)
当一个程序长时间占用cpu 操作系统也会剥夺该程序的cpu执行权限(降低了程序的执行效率)
主流的进程调度算法:
1:先来先服务调度算法。
当程序需要cpu计算的时候,cpu会按照先来后到的顺序计算他们。每当一个进程计算完后,在计算下一个进程。
这种算法,进程很不灵活,很容易出现后来的短作业一直没有运行,有利于长作业,不利于短作业。
2.短作业优先调度算法。
这种算法是判断后来的进程大小,将短作业优先执行,但是未来作业的长短是很难被计算出来,所以有根据作业剩余的长度来判断该分配先后顺序。
是活动的算法。
3.时间片轮转法
将每个进程分成相同的时间片,按照时间片来执行。
4多级反馈队列
对后来的进程分配低级的优先级,每当各个进程等待了一定时间就将其优先级加一,每当其进程执行了一定时间,就将其优先级减一。执行优先级最高的进程
创建进程的方式:
创建进程需要使用multiprocess模块中的Process模块
import time
from multiprocessing import Process def run():
print('进程开始')
time.sleep(3)
print('进程结束') if __name__ == '__main__':
p=Process(target=run)
p.start()
print('主进程结束')
在创建进程的时候使用process关键字,其中target参数传入的是你要运行的进程的函数,而当这个函数是有参函数时,需要用args对其参数进行赋值。
注意:在这个py文件下创建进程,需要在main函数中创建,
就进程创建的原理来看,当执行process时,会将该py文件当作模块导入,如果不写在main中,会出现循环导入情况。
process创建进程时会新开辟一个内存空间。
当然,创建进程的方式也可以将函数放入一个类中,这个类继承自process。
其中当创建子进程时,需要一小短时间,但即使这样主进程也不会等待这个是时间,会立即执行下面的代码,当创建空间完成才会执行,所以这是一个异步的情况。
class Myprocess(Process):
def __init__(self,name):
super().__init__()
self.name = name def run(self):
print('%s开始运行'%self.name)
time.sleep(3)
print('%s运行结束'%self.name) if __name__ == '__main__':
p = Myprocess('子进程')
p.start()
print('主进程结束')
以上是使用类创建一个子进程的方法,将一个继承自process的类中,改写其中的run方法,当创建一个对象后,调用其中的start方法就会自动调用这个方法。
join方法
join方法其作用就是等待子进程运行结束才会继续执行主进程。在start方法之后使用。
class Myprocess(Process):
def __init__(self,name):
super().__init__()
self.name = name def run(self):
print('%s开始运行'%self.name)
time.sleep(3)
print('%s运行结束'%self.name) if __name__ == '__main__':
p = Myprocess('子进程')
p.start()
p.join()
print('主进程结束')
#子进程开始运行
#子进程运行结束
#主进程结束
多个join重复调用时,最后长的那个子进程结束后才会继续执行主程序。
进程的数据隔离
在进程中,使用的是新开辟的内存空间,与主进程中的数据不会重叠。
from multiprocessing import Process money = 100 def test():
global money
money = 100000 if __name__ == '__main__':
p = Process(target=test)
p.start()
print(money)
#
即使在子进程中的函数,调用global改变全局变量,也只是改变子进程中的money,主进程没有影响。
terminate()与is_alive()
这两个方法都是有关进程的方法。
terminate是将一个进程杀手,而is_alive是判断这个进程是否还活着
import time
from multiprocessing import Process money = 100 def test():
global money
money = 100000 if __name__ == '__main__':
p = Process(target=test)
p.start()
p.terminate()
time.sleep(1)
a=p.is_alive()
print(a)
#False
daemon
daemon是当该值被赋予True时,将主进程设置为守护进程,
守护进程就是当主进程死亡后,无论子进程有没有运行结束,都会立即死亡。
from multiprocessing import Process
import time def test(name):
print('%s总管正常活着'%name)
time.sleep(3)
print('%s总管正常死亡'%name) if __name__ == '__main__':
p = Process(target=test,args=('egon',))
p.daemon = True # 将该进程设置为守护进程 这一句话必须放在start语句之前 否则报错
p.start()
time.sleep(0.1)
print('皇帝jason寿正终寝')
#皇帝jason寿正终寝
如果没有这个守护进程的设定,就会等主进程正常结束后,子进程再正常结束。
三。术语解释
1.同步异步
同步异步是表示的任务的提交方式。
同步:当任务提交之后,会原地等待任务的指向并拿到返回结果才走,期间不做任何事情,就好像程序卡住了一样。
异步:当任务提交了之后,就不再原地等待,而是继续执行下一行代码(结果会通过其他方式获取)
2.阻塞非阻塞
阻塞:阻塞态
非阻塞:就是就绪态,运行态
3.僵尸进程与孤儿进程
僵尸进程:一个进程结束后,会留下占用的端口号(所有进程都会步入僵尸进程)
孤儿进程:当一个父进程下有一个子进程,父进程意外结束后,并没有把子进程正常结束,子进程就会留下占用的端口号。
针对linux会有一个init,将意外结束的父进程下的子进程回收。
四。互斥锁
当多个进程操作同一份数据的时候 会造成数据的错乱,这个时候必须加锁处理,将并发变成串行,虽然降低了效率但是提高了数据的安全
注意:
1.锁不要轻易使用 容易造成死锁现象
2.只在处理数据的部分加锁 不要在全局加锁
锁必须在主进程中产生 交给子进程去使用。
已抢票为例
from multiprocessing import Process,Lock
import time
import json # 查票
def search(i):
with open('data','r',encoding='utf-8') as f:
data = f.read()
t_d = json.loads(data)
print('用户%s查询余票为:%s'%(i,t_d.get('ticket'))) # 买票
def buy(i):
with open('data','r',encoding='utf-8') as f:
data = f.read()
t_d = json.loads(data)
time.sleep(1)
if t_d.get('ticket') > 0:
# 票数减一
t_d['ticket'] -= 1
# 更新票数
with open('data','w',encoding='utf-8') as f:
json.dump(t_d,f)
print('用户%s抢票成功'%i)
else:
print('没票了') def run(i,mudex):
search(i)
mudex.acquire()
buy(i)
mudex.release() if __name__ == '__main__':
mudex = Lock()
for i in range(10):
p = Process(target=run,args=(i,mudex))
p.start()
#用户0查询余票为:5
#用户1查询余票为:5
#用户2查询余票为:5
#用户3查询余票为:5
#用户4查询余票为:5
#用户0抢票成功
#用户5查询余票为:4
#用户6查询余票为:4
#用户7查询余票为:4
#用户8查询余票为:4
#用户9查询余票为:4
#用户1抢票成功
#用户2抢票成功
#用户3抢票成功
#用户4抢票成功
#没票了
#没票了
#没票了
#没票了
#没票了
如果没有锁,当显示完票数后,大家的权限都是可以抢票的,而进程的运行会比较快,同时几个进程都去执行买票的方法,就会出现一张票被买了很多次。
这里有一个疑问,为什么后来的操作买票成功后,数据不会执行减法操作将数据减成负的
day30_8.9 操作系统与并发编程的更多相关文章
- socket之UDP协议,并发编程介绍,操作系统发展史
socket之UDP协议 1.UDP协议 UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection 参考 ...
- Python并发编程01 /操作系统发展史、多进程理论
Python并发编程01 /操作系统发展史.多进程理论 目录 Python并发编程01 /操作系统发展史.多进程理论 1. 操作系统 2. 进程理论 1. 操作系统 定义:管理控制协调计算机中硬件与软 ...
- 3、网络并发编程--udp代码、操作系统发展史、多道技术、进程理论
昨日内容回顾 socket基本使用 # 内置的模块 import socket s = socket.socket() # 默认是TCP协议 也可以切换为UDP协议 s.bind((ip,port)) ...
- 伪共享(false sharing),并发编程无声的性能杀手
在并发编程过程中,我们大部分的焦点都放在如何控制共享变量的访问控制上(代码层面),但是很少人会关注系统硬件及 JVM 底层相关的影响因素.前段时间学习了一个牛X的高性能异步处理框架 Disruptor ...
- Java并发编程:synchronized
Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...
- Java并发编程:进程和线程之由来
Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...
- Erlang 102 Erlang并发编程
笔记系列 Erlang环境和顺序编程Erlang并发编程Erlang分布式编程YawsErlang/OTP 日期 变更说明 2014-11-02 A outline 2014 ...
- Java编程思想学习(十六) 并发编程
线程是进程中一个任务控制流序列,由于进程的创建和销毁需要销毁大量的资源,而多个线程之间可以共享进程数据,因此多线程是并发编程的基础. 多核心CPU可以真正实现多个任务并行执行,单核心CPU程序其实不是 ...
- java并发编程:进程和线程
java并发编程涉及到很多内容,当然也包括多线程,再次补充点相关概念 原文地址:http://www.cnblogs.com/dolphin0520/p/3910667.html 一.操作系统中为什么 ...
随机推荐
- 《Dapper》
最近看了google的分布式追踪系统dapper的论文:http://static.googleusercontent.com/external_content/untrusted_dlcp/rese ...
- CF798D Mike and distribution
CF798D Mike and distribution 洛谷评测传送门 题目描述 Mike has always been thinking about the harshness of socia ...
- CF1005F Berland and the Shortest Paths 最短路树计数
问题描述 LG-CF1005F 题解 由题面显然可得,所求即最短路树. 所以跑出最短路树,计数,输出方案即可. \(\mathrm{Code}\) #include<bits/stdc++.h& ...
- eclipse创建git本地仓库,并将本地仓库更新到远端git服务器
目的:将本地代码更新到远端服务器 1.点击eclipsewindows->preference->team->git->Configuration配置git的基础环境 2.点击 ...
- Fink| 实时热门商品
HotNItems 拓展需求:实时统计双十一下单量,实时统计成交额,实时查看锅炉温度变化曲线,每个5分钟看一下过去一个小时温度变化曲线, 涉及到的技术点:sliding window.Watermar ...
- CF-weekly4 D. Haar Features
https://codeforces.com/gym/253910/problem/D D. Haar Features time limit per test 1 second memory lim ...
- Ubuntu 安装git及git命令
1.检查git是否已经安装,输入git version命令即可,如果没有显示版本号表示没有安装git 2.安装git sudo apt-get install git 3.配置git全局环境git c ...
- 【Java并发专题之一】Java内存模型
一.计算机内存模型 针对计算机机器而言,操作系统.JVM程序等其他所有程序都需要遵循内存模型规范.1.CPU技术发展1.1 CPU缓存的出现CPU的发展快于内存条,CPU的运算速度越来越快,内存条的读 ...
- HTML连载40-盒子宽度和高度的练习、box-sizing属性
一.判断方法 1.判断是否元素宽高为200的盒子 只需要看:边框+内边距+内容宽度/内容高度的值是否等于200 2.判断是否内容宽高为100的盒子 只需要看:width和heght的值是否等于100 ...
- TestNg之XMl形式实现多线程测试
为什么要使用多线程测试? 在实际测试中,为了节省测试时间,提高测试效率,在实际测试场景中经常会采用多线程的方式去执行,比如爬虫爬数据,多浏览器并行测试. 关于多线程并行测试 TestNG中实现多线程并 ...