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 一.操作系统中为什么 ...
随机推荐
- Appium自动化WebView中元素的操作
在App开发过程中,很容易用到第三方的WebView控件,这个属于移动端混合型App.在我们做自动化测试的过程中,就要对这种情况进行处理,最通用的办法就是先将appium切换到webview模式然后按 ...
- Python高级应用程序设计任务要求
Python高级应用程序设计任务要求 用Python实现一个面向主题的网络爬虫程序,并完成以下内容:(注:每人一题,主题内容自选,所有设计内容与源代码需提交到博客园平台) 一.主题式网络爬虫设计方案( ...
- 使用Vue封装暂无数据占位图组件
1. 前言 在日常开发中,页面上肯定有展示数据的需求,但是当某些时候该展示数据的地方此时数据为空时,就会留下一片空白,对用户体验不是很好,那么接下来我们就封装一个空数据时的占位展示图,告诉用户此时用户 ...
- 在Ubuntu18.04.2LTS上安装视频播放器smplayer/vlc
在Ubuntu18.04.2LTS上安装视频播放器smplayer/vlc 一.前言 在Ubuntu上的视频播放器质量很差,没有解码器,非常的不方便,于是我们需要手动去安装适合我们的播放器,比如smp ...
- 物联网架构成长之路(42)-直播流媒体入门(RTMP篇)
1. 安装RTMP流媒体服务器 以前其实我是利用Nginx-RTMP-module搭建过RTMP流媒体服务器,并实现了鉴权功能.参考https://www.cnblogs.com/wunaozai/p ...
- CSS3倒影效果
比较简单的倒影效果 <pre><div class="box-reflect"><img src="https://www.baidu.co ...
- 打开IDEA的更新选项,如何打开IDEA更新弹窗
如何让IDEA的更新弹窗重新出现,打开IDEA的更新选项 IDEA update的时候,会提示一个更新的弹框选择框如下图所示 在最下方有个Do not show this dialog in the ...
- 关于 C# 8.0 的 Switch Case When 的用法
直接贴代码了: static void Main(string[] args) { SwitchSample(); } private static void SwitchSample() { Swi ...
- Java代码开发之《异常日志》
异常日志 (一) 异常处理 1. [强制]Java 类库中定义的可以通过预检查方式规避的 RuntimeException 异常不应该通 过 catch 的方式来处理,比如:NullPointerEx ...
- Java开发在线考试系统 使用ssh框架编写源码
开发工具: Eclipse, Tomcat, MySql 1. 登录页面登录功能, 输入用户名与密码, 选择角色, 滑动箭头拉到最右边才可以点击登录 2. 学生角色登录 ...